Initial revision

git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
prozacx
2004-08-24 00:08:51 +00:00
parent 71a0088bea
commit 538d3ece4e
41 changed files with 10362 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
#!/bin/sh
CXXFLAGS="-Wall -D_GNU_SOURCE -DHAVE_LIBSSL -I.."
LIBS="-lssl"
if test -z "$1"; then
echo "Usage: $0 <module> [...]"
exit 1
fi
for arg in "$@"
do
if test -d $arg; then
(cd $arg && make || exit 1)
elif test -f "$arg"; then
FILE="$arg"
MOD="${FILE%.cpp}"
MOD="${MOD%.cc}"
elif test -f "$arg.cpp"; then
FILE="$arg.cpp"
MOD="$arg"
elif test -f "$arg.cc"; then
FILE="$arg.cc"
MOD="$arg"
fi
rm -f "$MOD.so"
if test -n "$FILE"; then
COMMAND="g++ $CXXFLAGS -c $FILE"
echo $COMMAND
$COMMAND || exit 1
COMMAND="g++ $CXXFLAGS -shared -o $MOD.so $MOD.o $LIBS"
echo $COMMAND
$COMMAND || exit 1
fi
if ! test -f "$MOD.so"; then
echo "Failed to build $MOD.so!"
exit 1
else
echo "Built $MOD.so"
fi
done
exit 0
+269
View File
@@ -0,0 +1,269 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include "md5.h"
#include <pwd.h>
#include <sstream>
/*
* Email Monitor / Retrieval
* Author: imaginos <imaginos@imaginos.net>
*
* $Log$
* Revision 1.1 2004/08/24 00:08:52 prozacx
* Initial revision
*
*
*/
struct EmailST
{
string sFrom;
string sSubject;
string sUidl;
u_int iSize;
};
class CEmailJob : public CTimer
{
public:
CEmailJob( CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription )
: CTimer( pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CEmailJob() {}
protected:
virtual void RunJob();
};
class CEmail : public CModule
{
public:
MODCONSTRUCTOR(CEmail)
{
m_iLastCheck = 0;
m_bInitialized = false;
}
virtual ~CEmail()
{
vector<Csock*> vSocks = m_pManager->FindSocksByName( "EMAIL::" + m_pUser->GetUserName() );
for( u_int a = 0; a < vSocks.size(); a++ )
m_pManager->DelSockByAddr( vSocks[a] );
}
virtual bool OnLoad(const string & sArgs) {
m_sMailPath = sArgs;
StartParser();
if ( m_pUser->IsUserAttached() )
StartTimer();
return true;
}
virtual void OnUserAttached()
{
stringstream s;
s << "You have " << m_ssUidls.size() << " emails.";
PutModule( s.str() );
StartTimer();
}
virtual void OnUserDetached()
{
RemTimer( "EMAIL::" + m_pUser->GetUserName() );
}
void StartTimer()
{
if ( !FindTimer( "EMAIL::" + m_pUser->GetUserName() ) )
{
CEmailJob *p = new CEmailJob( this, 60, 0, "EmailMonitor", "Monitors email activity" );
AddTimer( p );
}
}
virtual string GetDescription()
{
return ( "Monitors Email activity on local disk /var/mail/user" );
}
virtual void OnModCommand( const string& sCommand );
void StartParser();
void ParseEmails( const vector<EmailST> & vEmails )
{
if ( !m_bInitialized )
{
m_bInitialized = true;
for( u_int a = 0; a < vEmails.size(); a++ )
m_ssUidls.insert( vEmails[a].sUidl );
stringstream s;
s << "You have " << vEmails.size() << " emails.";
PutModule( s.str() );
} else
{
set<string> ssUidls;
CTable Table;
Table.AddColumn("From");
Table.AddColumn("Size");
Table.AddColumn("Subject");
for( u_int a = 0; a < vEmails.size(); a++ )
{
if ( m_ssUidls.find( vEmails[a].sUidl ) == m_ssUidls.end() )
{
//PutModule( "------------------- New Email -------------------" );
Table.AddRow();
Table.SetCell( "From", CUtils::Ellipsize( vEmails[a].sFrom, 32 ) );
Table.SetCell( "Size", CUtils::ToString( vEmails[a].iSize ) );
Table.SetCell( "Subject", CUtils::Ellipsize( vEmails[a].sSubject, 64 ) );
}
ssUidls.insert( vEmails[a].sUidl );
}
m_ssUidls = ssUidls; // keep the list in synch
if (Table.size()) {
unsigned int uTableIdx = 0;
string sLine;
while ( Table.GetLine( uTableIdx++, sLine ) ) {
PutModule( sLine );
}
stringstream s;
s << "You have " << vEmails.size() << " emails.";
PutModule( s.str() );
}
}
}
private:
string m_sMailPath;
u_int m_iLastCheck;
set<string> m_ssUidls;
bool m_bInitialized;
};
class CEmailFolder : public Csock
{
public:
CEmailFolder( CEmail *pModule, const string & sMailbox ) : Csock()
{
m_pModule = pModule;
m_sMailbox = sMailbox;
EnableReadLine();
}
virtual ~CEmailFolder()
{
if ( !m_sMailBuffer.empty() )
ProcessMail(); // get the last one
if ( !m_vEmails.empty() )
m_pModule->ParseEmails( m_vEmails );
}
virtual void ReadLine( const CS_STRING & sLine )
{
if ( sLine.substr( 0, 5 ) == "From " )
{
if ( !m_sMailBuffer.empty() )
{
ProcessMail();
m_sMailBuffer.clear();
}
}
m_sMailBuffer += sLine;
}
void ProcessMail()
{
EmailST tmp;
tmp.sUidl = (char *)CMD5( m_sMailBuffer.substr( 0, 255 ) );
string sLine;
u_int iPos = 0;
while( ::ReadLine( m_sMailBuffer, sLine, iPos ) )
{
CUtils::Trim( sLine );
if ( sLine.empty() )
break; // out of the headers
if ( strncasecmp( sLine.c_str(), "From: ", 6 ) == 0 )
tmp.sFrom = sLine.substr( 6, string::npos );
else if ( strncasecmp( sLine.c_str(), "Subject: ", 9 ) == 0 )
tmp.sSubject = sLine.substr( 9, string::npos );
if ( ( !tmp.sFrom.empty() ) && ( !tmp.sSubject.empty() ) )
break;
}
tmp.iSize = m_sMailBuffer.length();
m_vEmails.push_back( tmp );
}
private:
CEmail *m_pModule;
string m_sMailbox;
string m_sMailBuffer;
vector<EmailST> m_vEmails;
};
void CEmail::OnModCommand( const string& sCommand )
{
u_int iPos = sCommand.find( " " );
string sCom, sArgs;
if ( iPos == string::npos )
sCom = sCommand;
else
{
sCom = sCommand.substr( 0, iPos );
sArgs = sCommand.substr( iPos + 1, string::npos );
}
if ( sCom == "timers" )
{
ListTimers();
} else
PutModule( "Error, no such command [" + sCom + "]" );
}
void CEmail::StartParser()
{
string sParserName = "EMAIL::" + m_pUser->GetUserName();
if ( m_pManager->FindSockByName( sParserName ) )
return; // one at a time sucker
CFile cFile( m_sMailPath );
if ( ( !cFile.Exists() ) || ( cFile.GetSize() == 0 ) )
{
m_bInitialized = true;
return; // der
}
if ( cFile.GetMTime() <= m_iLastCheck )
return; // only check if modified
int iFD = open( m_sMailPath.c_str(), O_RDONLY );
if ( iFD >= 0 )
{
m_iLastCheck = time( NULL );
CEmailFolder *p = new CEmailFolder( this, m_sMailPath );
p->SetRSock( iFD );
p->SetWSock( iFD );
m_pManager->AddSock( (Csock *)p, "EMAIL::" + m_pUser->GetUserName() );
}
}
void CEmailJob::RunJob()
{
CEmail *p = (CEmail *)m_pModule;
p->StartParser();
}
MODULEDEFS(CEmail)
+28
View File
@@ -0,0 +1,28 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
class CRawMod : public CModule {
public:
MODCONSTRUCTOR(CRawMod) {}
virtual ~CRawMod() {}
virtual string GetDescription() {
return "View all of the raw traffic.";
}
virtual bool OnRaw(string& sLine) {
PutModule("IRC -> [" + sLine + "]");
return false;
}
virtual bool OnUserRaw(string& sLine) {
PutModule("YOU -> [" + sLine + "]");
return false;
}
};
MODULEDEFS(CRawMod)
+198
View File
@@ -0,0 +1,198 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
class CSampleTimer : public CTimer {
public:
CSampleTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CSampleTimer() {}
private:
protected:
virtual void RunJob() {
m_pModule->PutModule("TEST!!!!");
}
};
class CSampleMod : public CModule {
public:
MODCONSTRUCTOR(CSampleMod) {}
virtual bool OnLoad(const string& sArgs) {
PutModule("I'm being loaded with the arguments: [" + sArgs + "]");
//AddTimer(new CSampleTimer(this, 300, 0, "Sample", "Sample timer for sample things."));
//AddTimer(new CSampleTimer(this, 5, 20, "Another", "Another sample timer."));
//AddTimer(new CSampleTimer(this, 25000, 5, "Third", "A third sample timer."));
return true;
}
virtual ~CSampleMod() {
PutModule("I'm being unloaded!");
}
virtual bool OnBoot() {
// This is called when the app starts up (only modules that are loaded in the config will get this event)
return true;
}
virtual string GetDescription() {
return "To be used as a sample for writing modules.";
}
virtual void OnIRCConnected() {
PutModule("You got connected BoyOh.");
}
virtual void OnIRCDisconnected() {
PutModule("You got disconnected BoyOh.");
}
virtual void OnOp(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] opped [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnDeop(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] deopped [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnVoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] voiced [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnDevoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] devoiced [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnRawMode(const CNick& OpNick, const CChan& Channel, const string& sModes, const string& sArgs) {
PutModule("* " + OpNick.GetNick() + " sets mode: " + sModes + " " + sArgs + " (" + Channel.GetName() + ")");
}
virtual bool OnRaw(string& sLine) {
// PutModule("OnRaw() [" + sLine + "]");
return false;
}
virtual bool OnUserRaw(string& sLine) {
// PutModule("UserRaw() [" + sLine + "]");
return false;
}
virtual void OnKick(const CNick& OpNick, const string& sKickedNick, const CChan& Channel, const string& sMessage) {
PutModule("[" + OpNick.GetNick() + "] kicked [" + sKickedNick + "] from [" + Channel.GetName() + "] with the msg [" + sMessage + "]");
}
virtual void OnQuit(const CNick& Nick, const string& sMessage) {
PutModule("* Quits: " + Nick.GetNick() + " (" + Nick.GetIdent() + "!" + Nick.GetHost() + ") (" + sMessage + ")");
}
virtual void OnJoin(const CNick& Nick, const CChan& Channel) {
PutModule("* Joins: " + Nick.GetNick() + " (" + Nick.GetIdent() + "!" + Nick.GetHost() + ")");
}
virtual void OnPart(const CNick& Nick, const CChan& Channel) {
PutModule("* Parts: " + Nick.GetNick() + " (" + Nick.GetIdent() + "!" + Nick.GetHost() + ")");
}
virtual void OnNick(const CNick& OldNick, const string& sNewNick) {
PutModule("* " + OldNick.GetNick() + " is now known as " + sNewNick);
}
virtual bool OnUserCTCPReply(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] userctcpreply [" + sMessage + "]");
sMessage = "\037" + sMessage + "\037";
return false;
}
virtual bool OnCTCPReply(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] ctcpreply [" + sMessage + "]");
return false;
}
virtual bool OnUserCTCP(const string& sTarget, string& sMessage) {
PutModule("[" + sTarget + "] userctcp [" + sMessage + "]");
return false;
}
virtual bool OnPrivCTCP(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] privctcp [" + sMessage + "]");
sMessage = "\002" + sMessage + "\002";
return false;
}
virtual bool OnChanCTCP(const CNick& Nick, const CChan& Channel, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] chanctcp [" + sMessage + "] to [" + Channel.GetName() + "]");
sMessage = "\00311,5 " + sMessage + " \003";
return false;
}
virtual bool OnUserNotice(const string& sTarget, string& sMessage) {
PutModule("[" + sTarget + "] usernotice [" + sMessage + "]");
sMessage = "\037" + sMessage + "\037";
return false;
}
virtual bool OnPrivNotice(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] privnotice [" + sMessage + "]");
sMessage = "\002" + sMessage + "\002";
return false;
}
virtual bool OnChanNotice(const CNick& Nick, const CChan& Channel, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] channotice [" + sMessage + "] to [" + Channel.GetName() + "]");
sMessage = "\00311,5 " + sMessage + " \003";
return false;
}
virtual bool OnUserMsg(const string& sTarget, string& sMessage) {
PutModule("[" + sTarget + "] usermsg [" + sMessage + "]");
sMessage = "\0034" + sMessage + "\003";
return false;
}
virtual bool OnPrivMsg(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] privmsg [" + sMessage + "]");
sMessage = "\002" + sMessage + "\002";
return false;
}
virtual bool OnChanMsg(const CNick& Nick, const CChan& Channel, string& sMessage) {
if (sMessage == "!ping") {
PutIRC("PRIVMSG " + Channel.GetName() + " :PONG?");
}
sMessage = "x " + sMessage + " x";
return false;
}
virtual void OnModCommand(const string& sCommand) {
if (strcasecmp(sCommand.c_str(), "TIMERS") == 0) {
ListTimers();
}
}
virtual bool OnStatusCommand(const string& sCommand) {
if (strcasecmp(sCommand.c_str(), "SAMPLE") == 0) {
PutModule("Hi, I'm your friendly sample module.");
return true;
}
return false;
}
};
MODULEDEFS(CSampleMod)
+211
View File
@@ -0,0 +1,211 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include <pwd.h>
#ifndef HAVE_LIBSSL
#error This plugin only works with OpenSSL
#endif /* HAVE_LIBSSL */
#define CRYPT_VERIFICATION_TOKEN "::__:SAVEBUFF:__::"
/*
* Buffer Saving thing, incase your shit goes out while your out
* Author: imaginos <imaginos@imaginos.net>
*
* Its only as secure as your shell, the encryption only offers a slightly
* better solution then plain text.
*
* $Log$
* Revision 1.1 2004/08/24 00:08:52 prozacx
* Initial revision
*
*
*/
class CSaveBuff;
class CSaveBuffJob : public CTimer
{
public:
CSaveBuffJob( CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription )
: CTimer( pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CSaveBuffJob() {}
protected:
virtual void RunJob();
};
class CSaveBuff : public CModule
{
public:
MODCONSTRUCTOR(CSaveBuff)
{
// m_sPassword = CBlowfish::MD5( "" );
AddTimer( new CSaveBuffJob( this, 60, 0, "SaveBuff", "Saves the current buffer to disk every 1 minute" ) );
}
virtual ~CSaveBuff()
{
SaveBufferToDisk();
}
virtual bool OnBoot()
{
if ( m_sPassword.empty() )
{
char *pTmp = getpass( "Enter Encryption Key for savebuff.so: " );
if ( pTmp )
m_sPassword = CBlowfish::MD5( pTmp );
*pTmp = 0;
}
const vector<CChan *>& vChans = m_pUser->GetChans();
for( u_int a = 0; a < vChans.size(); a++ )
{
string sFile;
string sPath = GetPath( vChans[a]->GetName() );
if ( ( sPath.empty() ) || ( !ReadFile( sPath, sFile ) ) )
continue;
if ( !sFile.empty() )
{
CBlowfish c( m_sPassword, BF_DECRYPT );
sFile = c.Crypt( sFile );
if ( sFile.substr( 0, strlen( CRYPT_VERIFICATION_TOKEN ) ) != CRYPT_VERIFICATION_TOKEN )
{
// failed to decode :(
cerr << "Unable to decode Encrypted file [" << sPath << "]" << endl;
continue;
}
sFile.erase( 0, strlen( CRYPT_VERIFICATION_TOKEN ) );
string sLine;
u_int iPos = 0;
while( ReadLine( sFile, sLine, iPos ) )
{
CUtils::Trim( sLine );
vChans[a]->AddBuffer( sLine );
}
}
}
return true;
}
void SaveBufferToDisk()
{
if ( !m_sPassword.empty() )
{
const vector<CChan *>& vChans = m_pUser->GetChans();
for( u_int a = 0; a < vChans.size(); a++ )
{
const vector<string> & vBuffer = vChans[a]->GetBuffer();
if ( vBuffer.empty() )
continue;
string sFile = CRYPT_VERIFICATION_TOKEN;
for( u_int b = 0; b < vBuffer.size(); b++ )
sFile += vBuffer[b] + "\n";
CBlowfish c( m_sPassword, BF_ENCRYPT );
sFile = c.Crypt( sFile );
string sPath = GetPath( vChans[a]->GetName() );
if ( !sPath.empty() )
{
WriteFile( sPath, sFile );
chmod( sPath.c_str(), 0600 );
}
}
}
}
virtual string GetDescription()
{
return ( "Stores channel buffers to disk, encrypted." );
}
virtual void OnModCommand( const string& sCommand )
{
u_int iPos = sCommand.find( " " );
string sCom, sArgs;
if ( iPos == string::npos )
sCom = sCommand;
else
{
sCom = sCommand.substr( 0, iPos );
sArgs = sCommand.substr( iPos + 1, string::npos );
}
if ( strcasecmp( sCom.c_str(), "setpass" ) == 0 )
{
PutModule( "Password set to [" + sArgs + "]" );
m_sPassword = CBlowfish::MD5( sArgs );
} else if ( strcasecmp( sCom.c_str(), "dumpbuff" ) == 0 )
{
string sChannel = GetPath( sArgs );
string sFile;
if ( ( sChannel.empty() ) || ( !ReadFile( sChannel, sFile ) ) )
{
PutModule( "Unable to find buffer for that channel" );
return;
}
if ( !sFile.empty() )
{
CBlowfish c( m_sPassword, BF_DECRYPT );
sFile = c.Crypt( sFile );
if ( sFile.substr( 0, strlen( CRYPT_VERIFICATION_TOKEN ) ) != CRYPT_VERIFICATION_TOKEN )
{
// failed to decode :(
PutModule( "Unable to decode Encrypted file [" + sChannel + "]" );
return;
}
sFile.erase( 0, strlen( CRYPT_VERIFICATION_TOKEN ) );
string sLine;
u_int iPos = 0;
while( ReadLine( sFile, sLine, iPos ) )
{
CUtils::Trim( sLine );
PutModule( "[" + sLine + "]" );
}
}
} else if ( strcasecmp( sCom.c_str(), "save" ) == 0 )
{
SaveBufferToDisk();
PutModule( "Done." );
} else
PutModule( "Unknown command [" + sCommand + "]" );
}
string GetPath( const string & sChannel )
{
string sBuffer = m_pUser->GetUserName() + Lower( sChannel );
string sRet = m_pUser->GetHomePath();
sRet += "/.znc-savebuff-" + CBlowfish::MD5( sBuffer, true );
return( sRet );
}
private:
string m_sPassword;
};
void CSaveBuffJob::RunJob()
{
CSaveBuff *p = (CSaveBuff *)m_pModule;
p->SaveBufferToDisk();
}
MODULEDEFS(CSaveBuff)
+462
View File
@@ -0,0 +1,462 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include "Csocket.h"
#include "md5.h"
#include <pwd.h>
#include <sstream>
/*
* Secure chat system
* Author: imaginos <imaginos@imaginos.net>
*
* $Log$
* Revision 1.1 2004/08/24 00:08:52 prozacx
* Initial revision
*
*
*/
class CSChat;
class CRemMarkerJob : public CTimer
{
public:
CRemMarkerJob( CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription )
: CTimer( pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CRemMarkerJob() {}
void SetNick( const string & sNick )
{
m_sNick = sNick;
}
protected:
virtual void RunJob();
string m_sNick;
};
class CSChatSock : public Csock
{
public:
CSChatSock( CSChat *pMod ) : Csock()
{
m_pModule = pMod;
}
CSChatSock( int itimeout = 60 ) : Csock( itimeout )
{
m_pModule = NULL;
EnableReadLine();
}
CSChatSock( const CS_STRING & sHost, int iPort, int iTimeout = 60 )
: Csock( sHost, iPort, iTimeout )
{
m_pModule = NULL;
EnableReadLine();
}
virtual Csock *GetSockObj( const CS_STRING & sHostname, int iPort )
{
CSChatSock *p = new CSChatSock( sHostname, iPort );
return( p );
}
virtual bool ConnectionFrom( const CS_STRING & sHost, int iPort )
{
Close(); // close the listener after the first connection
return( true );
}
virtual void Connected();
virtual bool CreatedChild( Csock *pSock )
{
CSChatSock *p = (CSChatSock *)pSock;
p->SetModule( m_pModule );
p->SetChatNick( m_sChatNick );
p->SetSockName( GetSockName() + "::" + m_sChatNick );
return( true );
}
virtual void Timeout();
void SetModule( CSChat *p )
{
m_pModule = p;
}
void SetChatNick( const string & sNick )
{
m_sChatNick = sNick;
}
const string & GetChatNick() const { return( m_sChatNick ); }
virtual void ReadLine( const CS_STRING & sLine );
virtual void Disconnected();
virtual void AddLine( const string & sLine )
{
m_vBuffer.insert( m_vBuffer.begin(), sLine );
if ( m_vBuffer.size() > 200 )
m_vBuffer.pop_back();
}
virtual void DumpBuffer()
{
for( vector<CS_STRING>::reverse_iterator it = m_vBuffer.rbegin(); it != m_vBuffer.rend(); it++ )
ReadLine( *it );
m_vBuffer.clear();
}
private:
CSChat *m_pModule;
string m_sChatNick;
vector<CS_STRING> m_vBuffer;
};
class CSChat : public CModule
{
public:
MODCONSTRUCTOR(CSChat) {}
virtual ~CSChat() { CleanSocks(); }
virtual bool OnLoad( const string & sArgs )
{
m_sPemFile = sArgs;
if ( m_sPemFile.empty() )
{
m_sPemFile = m_pUser->GetBinPath() + "/znc.pem";
}
if (!CFile::Exists(m_sPemFile)) {
PutModule("Unable to load pem file [" + m_sPemFile + "]");
return false;
}
return true;
}
virtual void OnUserAttached()
{
string sName = "SCHAT::" + m_pUser->GetUserName();
for( u_int a = 0; a < m_pManager->size(); a++ )
{
if ( ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) != 0 ) || ( (*m_pManager)[a]->GetType() == CSChatSock::LISTENER ) )
continue;
CSChatSock *p = (CSChatSock *)(*m_pManager)[a];
p->DumpBuffer();
}
}
virtual void OnUserDetached() {}
void CleanSocks()
{
string sName = "SCHAT::" + m_pUser->GetUserName();
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) == 0 )
m_pManager->DelSock( a-- );
}
}
virtual string GetDescription()
{
return ( "Secure cross platform (:P) chat system" );
}
virtual bool OnUserRaw( string & sLine )
{
if ( strncasecmp( sLine.c_str(), "schat ", 6 ) == 0 )
{
OnModCommand( "chat " + sLine.substr( 6, string::npos ) );
return( true );
} else if ( strcasecmp( sLine.c_str(), "schat" ) == 0 )
{
PutModule( "SChat User Area ..." );
OnModCommand( "help" );
return( true );
}
return( false );
}
virtual void OnModCommand( const string& sCommand )
{
u_int iPos = sCommand.find( " " );
string sCom, sArgs;
if ( iPos == string::npos )
sCom = sCommand;
else
{
sCom = sCommand.substr( 0, iPos );
sArgs = sCommand.substr( iPos + 1, string::npos );
}
if ( ( strcasecmp( sCom.c_str(), "chat" ) == 0 ) && ( !sArgs.empty() ) )
{
string sSockName = "SCHAT::" + m_pUser->GetUserName();
string sNick = "(s)" + sArgs;
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sSockName.c_str(), sSockName.length() ) != 0 )
continue;
CSChatSock *pSock = (CSChatSock *)(*m_pManager)[a];
if ( strcasecmp( pSock->GetChatNick().c_str(), sNick.c_str() ) == 0 )
{
PutModule( "Already Connected to [" + sArgs + "]" );
return;
}
}
CSChatSock *pSock = new CSChatSock;
pSock->SetCipher( "HIGH" );
pSock->SetPemLocation( m_sPemFile );
pSock->SetModule( this );
pSock->SetChatNick( sNick );
u_short iPort = m_pManager->ListenRand( sSockName, m_pUser->GetLocalIP(), true, SOMAXCONN, pSock, 60 );
if ( iPort == 0 )
{
PutModule( "Failed to start chat!" );
return;
}
stringstream s;
s << "PRIVMSG " << sArgs << " :\001";
s << "DCC SCHAT chat ";
s << CUtils::GetLongIP( m_pUser->GetLocalIP() );
s << " " << iPort << "\001";
PutIRC( s.str() );
} else if ( strcasecmp( sCom.c_str(), "list" ) == 0 )
{
string sName = "SCHAT::" + m_pUser->GetUserName();
CTable Table;
Table.AddColumn( "Nick" );
Table.AddColumn( "Created" );
Table.AddColumn( "Host" );
Table.AddColumn( "Port" );
Table.AddColumn( "Status" );
Table.AddColumn( "Cipher" );
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) != 0 )
continue;
Table.AddRow();
CSChatSock *pSock = (CSChatSock *)(*m_pManager)[a];
Table.SetCell( "Nick", pSock->GetChatNick() );
unsigned long long iStartTime = pSock->GetStartTime();
time_t iTime = iStartTime / 1000;
char *pTime = ctime( &iTime );
if ( pTime )
{
string sTime = pTime;
CUtils::Trim( sTime );
Table.SetCell( "Created", sTime );
}
if ( pSock->GetType() != CSChatSock::LISTENER )
{
Table.SetCell( "Status", "Established" );
Table.SetCell( "Host", pSock->GetRemoteIP() );
Table.SetCell( "Port", CUtils::ToString( pSock->GetRemotePort() ) );
SSL_SESSION *pSession = pSock->GetSSLSession();
if ( ( pSession ) && ( pSession->cipher ) && ( pSession->cipher->name ) )
Table.SetCell( "Cipher", pSession->cipher->name );
} else
{
Table.SetCell( "Status", "Waiting" );
Table.SetCell( "Port", CUtils::ToString( pSock->GetLocalPort() ) );
}
}
if ( Table.size() )
{
unsigned int uTableIdx = 0;
string sLine;
while ( Table.GetLine( uTableIdx++, sLine ) )
PutModule( sLine );
} else
PutModule( "No SDCCs currently in session" );
} else if ( strcasecmp( sCom.c_str(), "close" ) == 0 )
{
string sName = "SCHAT::" + m_pUser->GetUserName();
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) != 0 )
continue;
CSChatSock *pSock = (CSChatSock *)(*m_pManager)[a];
if ( strncasecmp( sArgs.c_str(), "(s)", 3 ) != 0 )
sArgs = "(s)" + sArgs;
if ( strcasecmp( sArgs.c_str(), pSock->GetChatNick().c_str() ) == 0 )
{
pSock->Close();
return;
}
PutModule( "No Such Chat [" + sArgs + "]" );
}
} else if ( strcasecmp( sCom.c_str(), "help" ) == 0 )
{
PutModule( "Commands are: " );
PutModule( " help - This text." );
PutModule( " chat <nick> - Chat a nick." );
PutModule( " list - List current chats." );
PutModule( " close <nick> - Close a chat to a nick." );
PutModule( " timers - Shows related timers." );
} else if ( strcasecmp( sCom.c_str(), "timers" ) == 0 )
ListTimers();
else
PutModule( "Unknown command [" + sCom + "] [" + sArgs + "]" );
}
virtual bool OnPrivCTCP( const CNick& Nick, string& sMessage )
{
if ( strncasecmp( sMessage.c_str(), "DCC SCHAT ", 10 ) == 0 )
{
// chat ip port
unsigned long iIP = strtoul( CUtils::Token( sMessage, 3 ).c_str(), NULL, 10 );
unsigned short iPort = strtoul( CUtils::Token( sMessage, 4 ).c_str(), NULL, 10 );
if ( ( iIP > 0 ) && ( iPort > 0 ) )
{
pair<u_long, u_short> pTmp;
pTmp.first = iIP;
pTmp.second = iPort;
m_siiWaitingChats["(s)" + Nick.GetNick()] = pTmp;
SendToUser( "(s)" + Nick.GetNick() + "!" + "(s)" + Nick.GetNick() + "@" + CUtils::GetIP( iIP ), "*** Incoming DCC SCHAT, Accept ? (yes/no)" );
CRemMarkerJob *p = new CRemMarkerJob( this, 60, 1, "Remove (s)" + Nick.GetNick(), "Removes this nicks entry for waiting DCC." );
p->SetNick( "(s)" + Nick.GetNick() );
AddTimer( p );
return( true );
}
}
return( false );
}
void AcceptSDCC( const string & sNick, u_long iIP, u_short iPort )
{
CSChatSock *p = new CSChatSock( CUtils::GetIP( iIP ), iPort, 60 );
p->SetModule( this );
p->SetChatNick( sNick );
string sSockName = "SCHAT::" + m_pUser->GetUserName() + "::" + sNick;
m_pManager->Connect( CUtils::GetIP( iIP ), iPort, sSockName, 60, true, m_pUser->GetLocalIP(), p );
RemTimer( "Remove " + sNick ); // delete any associated timer to this nick
}
virtual bool OnUserMsg( const string& sTarget, string& sMessage )
{
if ( strncmp( sTarget.c_str(), "(s)", 3 ) == 0 )
{
string sSockName = "SCHAT::" + m_pUser->GetUserName() + "::" + sTarget;
CSChatSock *p = (CSChatSock *)m_pManager->FindSockByName( sSockName );
if ( !p )
{
map< string,pair< u_long,u_short > >::iterator it = m_siiWaitingChats.find( sTarget );
if ( it != m_siiWaitingChats.end() )
{
if ( strcasecmp( sMessage.c_str(), "yes" ) != 0 )
SendToUser( sTarget + "!" + sTarget + "@" + CUtils::GetIP( it->second.first ), "Refusing to accept DCC SCHAT!" );
else
AcceptSDCC( sTarget, it->second.first, it->second.second );
m_siiWaitingChats.erase( it );
return( true );
}
PutModule( "No such SCHAT to [" + sTarget + "]" );
} else
p->Write( sMessage + "\n" );
return( true );
}
return( false );
}
virtual void RemoveMarker( const string & sNick )
{
map< string,pair< u_long,u_short > >::iterator it = m_siiWaitingChats.find( sNick );
if ( it != m_siiWaitingChats.end() )
m_siiWaitingChats.erase( it );
}
void SendToUser( const string & sFrom, const string & sText )
{
//:*schat!znc@znc.com PRIVMSG Jim :
string sSend = ":" + sFrom + " PRIVMSG " + m_pUser->GetCurNick() + " :" + sText;
PutUser( sSend );
}
bool IsAttached()
{
return( m_pUser->IsUserAttached() );
}
private:
map< string,pair< u_long,u_short > > m_siiWaitingChats;
string m_sPemFile;
};
//////////////////// methods ////////////////
void CSChatSock::ReadLine( const CS_STRING & sLine )
{
if ( m_pModule )
{
string sText = sLine;
CUtils::Trim( sText );
if ( m_pModule->IsAttached() )
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), sText );
else
AddLine( sText );
}
}
void CSChatSock::Disconnected()
{
if ( m_pModule )
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), "*** Disconnected." );
}
void CSChatSock::Connected()
{
SetTimeout( 0 );
if ( m_pModule )
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), "*** Connected." );
}
void CSChatSock::Timeout()
{
if ( m_pModule )
{
if ( GetType() == LISTENER )
m_pModule->PutModule( "Timeout while waiting for [" + m_sChatNick + "]" );
else
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), "*** Connection Timed out." );
}
}
void CRemMarkerJob::RunJob()
{
CSChat *p = (CSChat *)m_pModule;
p->RemoveMarker( m_sNick );
// store buffer
}
MODULEDEFS(CSChat)
+220
View File
@@ -0,0 +1,220 @@
#ifndef _NO_CSOCKET_NS
#define _NO_CSOCKET_NS
#endif
#include "Csocket.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include <sys/wait.h>
// Forward Declaration
class CShellMod;
class CExecSock : public Csock {
public:
CExecSock(CShellMod* pShellMod, const string& sExec) : Csock() {
EnableReadLine();
m_pParent = pShellMod;
int iReadFD, iWriteFD;
m_iPid = popen2(iReadFD, iWriteFD, sExec);
ConnectFD(iReadFD, iWriteFD, "0.0.0.0:0");
}
virtual ~CExecSock() {
close2(m_iPid, GetRSock(), GetWSock());
SetRSock( -1 );
SetWSock( -1 );
}
// These next two function's bodies are at the bottom of the file since they reference CShellMod
virtual void ReadLine(const string& sData);
virtual void Disconnected();
CShellMod* m_pParent;
int m_iPid;
int popen2(int & iReadFD, int & iWriteFD, const string & sCommand) {
int rpipes[2] = { -1, -1 };
int wpipes[2] = { -1, -1 };
iReadFD = -1;
iWriteFD = -1;
pipe(rpipes);
pipe(wpipes);
int iPid = fork();
if (iPid == -1) {
return -1;
}
if (iPid == 0) {
close(wpipes[1]);
close(rpipes[0]);
dup2(wpipes[0], 0);
dup2(rpipes[1], 1);
dup2(rpipes[1], 2);
close(wpipes[0]);
close(rpipes[1]);
system( sCommand.c_str() );
exit(0);
}
close(wpipes[0]);
close(rpipes[1]);
iWriteFD = wpipes[1];
iReadFD = rpipes[0];
return iPid;
}
void close2(int iPid, int iReadFD, int iWriteFD) {
close( iReadFD );
close( iWriteFD );
u_int iNow = time( NULL );
while( waitpid( iPid, NULL, WNOHANG ) == 0 )
{
if ( ( time( NULL ) - iNow ) > 5 )
break; // giveup
usleep( 100 );
}
return;
}
};
class CShellMod : public CModule {
public:
MODCONSTRUCTOR(CShellMod) {
m_sPath = pUser->GetHomePath();
}
virtual ~CShellMod() {
vector<Csock*> vSocks = m_pManager->FindSocksByName("SHELL");
for (unsigned int a = 0; a < vSocks.size(); a++) {
m_pManager->DelSockByAddr(vSocks[a]);
}
}
virtual string GetDescription() {
return "Gives shell access.";
}
virtual void OnModCommand(const string& sCommand) {
if ((strcasecmp(sCommand.c_str(), "cd") == 0) || (strncasecmp(sCommand.c_str(), "cd ", 3) == 0)) {
string sPath = CUtils::ChangeDir(m_sPath, ((sCommand.length() == 2) ? m_pUser->GetHomePath() : sCommand.substr(3)), m_pUser->GetHomePath());
CFile Dir(sPath);
if (Dir.IsDir()) {
m_sPath = sPath;
} else if (Dir.Exists()) {
PutShell("cd: not a directory [" + sPath + "]");
} else {
PutShell("cd: no such directory [" + sPath + "]");
}
PutShell("znc$");
} else if (strcasecmp(CUtils::Token(sCommand, 0).c_str(), "SEND") == 0) {
string sToNick = CUtils::Token(sCommand, 1);
string sFile = CUtils::Token(sCommand, 2);
if ((sToNick.empty()) || (sFile.empty())) {
PutShell("usage: Send <nick> <file>");
} else {
sFile = CUtils::ChangeDir(m_sPath, sFile, m_pUser->GetHomePath());
if (!CFile::Exists(sFile)) {
PutShell("get: no such file [" + sFile + "]");
} else if (!CFile::IsReg(sFile)) {
PutShell("get: not a file [" + sFile + "]");
} else {
m_pUser->SendFile(sToNick, sFile, GetModName());
}
}
} else if (strcasecmp(CUtils::Token(sCommand, 0).c_str(), "GET") == 0) {
string sFile = CUtils::Token(sCommand, 1);
if (sFile.empty()) {
PutShell("usage: Get <file>");
} else {
sFile = CUtils::ChangeDir(m_sPath, sFile, m_pUser->GetHomePath());
if (!CFile::Exists(sFile)) {
PutShell("get: no such file [" + sFile + "]");
} else if (!CFile::IsReg(sFile)) {
PutShell("get: not a file [" + sFile + "]");
} else {
m_pUser->SendFile(m_pUser->GetCurNick(), sFile, GetModName());
}
}
} else {
RunCommand(sCommand);
}
}
virtual bool OnStatusCommand(const string& sCommand) {
if (strcasecmp(sCommand.c_str(), "SHELL") == 0) {
PutShell("-- ZNC Shell Service --");
return true;
}
return false;
}
virtual bool OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const string& sFile, unsigned long uFileSize) {
if (strcasecmp(RemoteNick.GetNick().c_str(), string(GetModNick()).c_str()) == 0) {
string sLocalFile = CUtils::ChangeDir(m_sPath, sFile, m_pUser->GetHomePath());
m_pUser->GetFile(m_pUser->GetCurNick(), CUtils::GetIP(uLongIP), uPort, sLocalFile, uFileSize, GetModName());
return true;
}
return false;
}
void PutShell(const string& sLine) {
string sPath = m_sPath;
unsigned int a = sPath.find(' ');
while (a != string::npos) {
sPath.replace(a, 1, "_");
a = sPath.find(' ');
}
PutModule(sLine, m_pUser->GetCurNick(), sPath);
}
void RunCommand(const string& sCommand) {
m_pManager->AddSock((Csock*) new CExecSock(this, "cd " + m_sPath + " && " + sCommand), "SHELL");
}
private:
string m_sPath;
};
void CExecSock::ReadLine(const string& sData) {
string sLine = sData;
while ((sLine.length()) && (sLine[sLine.length() -1] == '\r') || (sLine[sLine.length() -1] == '\n')) {
sLine = sLine.substr(0, sLine.length() -1);
}
unsigned int a = sLine.find('\t');
while (a != string::npos) {
sLine.replace(a, 1, " ");
a = sLine.find('\t');
}
m_pParent->PutShell(sLine);
}
void CExecSock::Disconnected() {
m_pParent->PutShell("znc$");
}
MODULEDEFS(CShellMod)