mirror of
https://github.com/correl/mercenary.git
synced 2024-11-27 11:09:52 +00:00
Imported the QT4 IRC Client project, along with the mIRC script parser
that will eventually be integrated into it git-svn-id: file:///srv/svn/ircclient/trunk@1 a9804ffe-773b-11dd-bd7c-89c3ef1d2733
This commit is contained in:
commit
0381859219
24 changed files with 1315 additions and 0 deletions
51
guiapp/chatwindow.h
Normal file
51
guiapp/chatwindow.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef CHATWINDOW_H
|
||||||
|
#define CHATWINDOW_H
|
||||||
|
|
||||||
|
#include "ui_chatwindow.h"
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
class ChatWindow : public QWidget, public Ui::ChatWindow {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString filter;
|
||||||
|
QString defaultCmd;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ChatWindow( QWidget *parent = 0 ) : QWidget( parent ) {
|
||||||
|
};
|
||||||
|
|
||||||
|
void setupUi( QWidget *ChatWindow = 0 ) {
|
||||||
|
Ui::ChatWindow::setupUi( ChatWindow );
|
||||||
|
connect( input, SIGNAL( returnPressed() ), this, SLOT( processCmd() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setMessageFilter( QString filter ) { this->filter = filter; }
|
||||||
|
void setDefaultCmd( QString cmd ) { this->defaultCmd = cmd; }
|
||||||
|
void message( QString src, QString message ) {
|
||||||
|
display->append( "<" + src + "> " + message );
|
||||||
|
display->verticalScrollBar()->setValue( display->verticalScrollBar()->maximum() );
|
||||||
|
}
|
||||||
|
void echo( QString text ) {
|
||||||
|
display->append( text );
|
||||||
|
display->verticalScrollBar()->setValue( display->verticalScrollBar()->maximum() );
|
||||||
|
}
|
||||||
|
void processCmd() {
|
||||||
|
QString cmd = defaultCmd;
|
||||||
|
QStringList args = input->text().trimmed().split( " " );
|
||||||
|
if( args.count() < 1 ) { return; }
|
||||||
|
if( args[0].startsWith( '/' ) ) {
|
||||||
|
cmd = args.takeFirst();
|
||||||
|
cmd = cmd.right( cmd.length() - 1 );
|
||||||
|
}
|
||||||
|
emit doCmd( cmd + " " + args.join( " " ) );
|
||||||
|
input->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void doCmd( QString cmd );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
36
guiapp/chatwindow.ui
Normal file
36
guiapp/chatwindow.ui
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<ui version="4.0" >
|
||||||
|
<class>ChatWindow</class>
|
||||||
|
<widget class="QWidget" name="ChatWindow" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="display" >
|
||||||
|
<property name="styleSheet" >
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="html" >
|
||||||
|
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="input" />
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
16
guiapp/guiapp.pro
Normal file
16
guiapp/guiapp.pro
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
######################################################################
|
||||||
|
# Automatically generated by qmake (2.01a) Tue Aug 14 00:00:17 2007
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
TARGET = guiapp
|
||||||
|
DESTDIR = bin
|
||||||
|
DEPENDPATH += .
|
||||||
|
INCLUDEPATH += .
|
||||||
|
QT += network
|
||||||
|
|
||||||
|
# Input
|
||||||
|
HEADERS += chatwindow.h messagehandler.h ../src/ircclient.h ../src/dccserver.h
|
||||||
|
FORMS += chatwindow.ui
|
||||||
|
SOURCES += main.cpp messagehandler.cpp ../src/ircclient.cpp ../src/dccserver.cpp
|
||||||
|
TRANSLATIONS += guiapp_en.ts
|
34
guiapp/guiapp_en.ts
Normal file
34
guiapp/guiapp_en.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS><TS version="1.1" language="en">
|
||||||
|
<defaultcodec></defaultcodec>
|
||||||
|
<context>
|
||||||
|
<name>ChatWindow</name>
|
||||||
|
<message>
|
||||||
|
<location filename="chatwindow.ui" line="22"/>
|
||||||
|
<source><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></source>
|
||||||
|
<translation><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>IRCClient</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../src/ircclient.cpp" line="35"/>
|
||||||
|
<source>Quit</source>
|
||||||
|
<translation>Quit</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageHandler</name>
|
||||||
|
<message>
|
||||||
|
<location filename="messagehandler.cpp" line="61"/>
|
||||||
|
<source>Changing servers</source>
|
||||||
|
<translation>Changing Servers</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
18
guiapp/main.cpp
Normal file
18
guiapp/main.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <QDialog>
|
||||||
|
#include "../src/ircclient.h"
|
||||||
|
#include "chatwindow.h"
|
||||||
|
#include "messagehandler.h"
|
||||||
|
|
||||||
|
int main( int argc, char *argv[] ) {
|
||||||
|
QApplication app( argc, argv );
|
||||||
|
IRCClient *irc = new IRCClient();
|
||||||
|
MessageHandler *mh = new MessageHandler( irc );
|
||||||
|
|
||||||
|
QObject::connect( &app, SIGNAL( aboutToQuit() ), irc, SLOT( quit() ) );
|
||||||
|
mh->show();
|
||||||
|
|
||||||
|
irc->connectAndRegister( argc > 1 ? argv[1] : "dev1", 6667, argc > 2 ? argv[2] : "Test", "correlr", "Correl Roush" );
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
215
guiapp/messagehandler.cpp
Normal file
215
guiapp/messagehandler.cpp
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
#include "messagehandler.h"
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
MessageHandler::MessageHandler( IRCClient *irc, QWidget *parent ) : QTabWidget( parent ) {
|
||||||
|
this->irc = irc;
|
||||||
|
connect( irc, SIGNAL( messageRcvd( QString, QString, QString, QStringList, QString ) ), this, SLOT( messageRcvd( QString, QString, QString, QStringList, QString ) ) );
|
||||||
|
connect( irc, SIGNAL( registered() ), this, SLOT( autoRun() ) );
|
||||||
|
connect( irc, SIGNAL( sentRAW( QString ) ), this, SLOT( sentRAW( QString ) ) );
|
||||||
|
connect( irc, SIGNAL( rcvdRAW( QString ) ), this, SLOT( rcvdRAW( QString ) ) );
|
||||||
|
this->setTabPosition( QTabWidget::South );
|
||||||
|
_addWindow( "status", "", true );
|
||||||
|
|
||||||
|
DCCPortMin = 1024;
|
||||||
|
DCCPortMax = 5000;
|
||||||
|
|
||||||
|
DCCSendAhead = true;
|
||||||
|
|
||||||
|
// Set up variables
|
||||||
|
variables["address"] = "$ip";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::_addWindow( QString name, QString defaultCmd, bool focusOnOpen ) {
|
||||||
|
if( windows.keys().contains( name ) ) { return; }
|
||||||
|
int index = this->addTab( new ChatWindow(), name );
|
||||||
|
windows[name] = (ChatWindow*)this->widget( index );
|
||||||
|
windows[name]->setDefaultCmd( defaultCmd );
|
||||||
|
connect( windows[name], SIGNAL( doCmd( QString ) ), this, SLOT( processCmd( QString ) ) );
|
||||||
|
windows[name]->setupUi( windows[name] );
|
||||||
|
if( focusOnOpen ) {
|
||||||
|
this->setCurrentIndex( index );
|
||||||
|
windows[name]->input->setFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MessageHandler::parseVar( QString text ) {
|
||||||
|
if( !text.startsWith( '$' ) ) { return text; }
|
||||||
|
QString var = text.right( text.length() - 1 ).toLower();
|
||||||
|
QString value;
|
||||||
|
|
||||||
|
if( var == "ip" ) { value = irc->getIPAddress(); }
|
||||||
|
if( var == "nick" || var == "nickname" ) { value = irc->getNickName(); }
|
||||||
|
|
||||||
|
if( value.isNull() && variables.keys().contains( var ) ) { value = variables[var].toString(); }
|
||||||
|
return ( value.isNull() || value == text ) ? text : parseVar( value ); // Allows for recursive vars, while avoiding an infinite loop
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::messageRcvd( QString type, QString src, QString dest, QStringList values, QString text ) {
|
||||||
|
QString window = "status";
|
||||||
|
QString source = "server";
|
||||||
|
QString message = text;
|
||||||
|
|
||||||
|
if( src.startsWith( ':' ) ) { src = src.right( src.length() - 1 ); }
|
||||||
|
|
||||||
|
// Handle special messages first
|
||||||
|
if( type == "JOIN" ) {
|
||||||
|
_addWindow( text, "msg " + text, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !dest.isEmpty() && dest.startsWith( '#' ) ) {
|
||||||
|
window = dest;
|
||||||
|
}
|
||||||
|
if( !src.isEmpty() && src.contains( '!' ) && src.contains( '@' ) ) {
|
||||||
|
QStringList split = src.split( '!' );
|
||||||
|
source = split[0];
|
||||||
|
if( dest == irc->getNickName() && type == "PRIVMSG" ) {
|
||||||
|
window = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( type == "CTCP" ) {
|
||||||
|
values = text.split( " " );
|
||||||
|
QString ctcpCommand = values.takeFirst().toUpper();
|
||||||
|
if( ctcpCommand == "VERSION" ) {
|
||||||
|
irc->notice( source, tr( "Atma2 IRC Client %1" ).arg( 0.01 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//emit dispatchMessage( window, src, message );
|
||||||
|
_addWindow( window, "msg " + window );
|
||||||
|
windows[window]->message( source, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::messageSentDCC( QString nickName, QString text ) {
|
||||||
|
QString window = nickName.prepend( "=" );
|
||||||
|
_addWindow( window, "msg " + window );
|
||||||
|
windows[window]->message( irc->getNickName(), text );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::messageRcvdDCC( QString nickName, QString text ) {
|
||||||
|
QString window = "=" + nickName;
|
||||||
|
_addWindow( window, "msg " + window );
|
||||||
|
windows[window]->message( nickName, text );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::processCmd( QString cmdText ) {
|
||||||
|
qDebug() << cmdText;
|
||||||
|
QStringList args = cmdText.split( ' ' );
|
||||||
|
QStringList newargs;
|
||||||
|
|
||||||
|
QString cmd = args.takeFirst().toLower();
|
||||||
|
for( int i = 0; i < args.count(); i++ ) {
|
||||||
|
if( args[i].startsWith( '$' ) ) {
|
||||||
|
args[i] = parseVar( args[i] );
|
||||||
|
//QString var = args[i].right( args[i].length() - 1 );
|
||||||
|
//if( variables.contains( var ) ) { args[i] = variables[var].toString(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( cmd == "server" || cmd == "connect" ) {
|
||||||
|
if( args.count() < 1 ) { return; }
|
||||||
|
irc->quit( tr( "Changing servers" ) );
|
||||||
|
QString host = args.takeFirst();
|
||||||
|
int port = 0;
|
||||||
|
if( host.contains( ':' ) ) {
|
||||||
|
QStringList splitHost = host.split( ':' );
|
||||||
|
host = splitHost.takeFirst();
|
||||||
|
port = splitHost.join( "" ).toInt();
|
||||||
|
}
|
||||||
|
port = port > 0 ? port : 6667;
|
||||||
|
QString nickName = args.count() > 0 ? args.takeFirst() : irc->getNickName();
|
||||||
|
QString userName = args.count() > 0 ? args.takeFirst() : irc->getUserName();
|
||||||
|
QString realName = args.count() > 0 ? args.join( " " ) : irc->getRealName();
|
||||||
|
irc->connectAndRegister(
|
||||||
|
host, // Host
|
||||||
|
port > 0 ? port : 6667, // Port
|
||||||
|
nickName,
|
||||||
|
userName,
|
||||||
|
realName );
|
||||||
|
} else if( cmd == "nick" ) {
|
||||||
|
if( args.count() < 1 ) { return; }
|
||||||
|
irc->nick( args[0] );
|
||||||
|
} else if( cmd == "msg" || cmd == "privmsg" ) {
|
||||||
|
if( args.count() < 2 ) { return; }
|
||||||
|
newargs += args.takeFirst();
|
||||||
|
if( newargs[0].startsWith( "=") ) {
|
||||||
|
// DCC Chat
|
||||||
|
((DCCChatServer*)DCCServers[DCCNicks[newargs[0].right( newargs[0].length() - 1 )]])->sendText( args.join( " " ) );
|
||||||
|
} else {
|
||||||
|
irc->msg( newargs[0], args.join( " " ) );
|
||||||
|
}
|
||||||
|
// Update existing chat windows with the sent message
|
||||||
|
QString window;
|
||||||
|
QStringList windows = newargs[0].split( "," );
|
||||||
|
foreach( window, windows ) {
|
||||||
|
if( !window.startsWith( "=" ) && this->windows.keys().contains( window ) ) { this->windows[window]->message( irc->getNickName(), args.join( " " ) ); }
|
||||||
|
}
|
||||||
|
} else if( cmd == "notice" ) {
|
||||||
|
if( args.count() < 2 ) { return; }
|
||||||
|
QString dest = args.takeFirst();
|
||||||
|
irc->notice( dest, args.join( " " ) );
|
||||||
|
} else if( cmd == "ctcp" ) {
|
||||||
|
if( args.count() < 2 ) { return; }
|
||||||
|
newargs += args.takeFirst();
|
||||||
|
irc->ctcp( newargs[0], args.join( " " ) );
|
||||||
|
} else if( cmd == "join" ) {
|
||||||
|
irc->join( args.join( "," ) );
|
||||||
|
} else if( cmd == "set" ) {
|
||||||
|
QString var = args.takeFirst();
|
||||||
|
variables[var] = args.join( " " );
|
||||||
|
} else if( cmd == "dcc" ) {
|
||||||
|
if( args.count() < 2 ) { return; }
|
||||||
|
QString type = args.takeFirst();
|
||||||
|
QString nick = args.takeFirst();
|
||||||
|
if( type == "chat" ) {
|
||||||
|
startDCC( nick );
|
||||||
|
} else if( type == "send" ) {
|
||||||
|
if( args.count() == 0 ) { return; }
|
||||||
|
startDCC( nick, args.join( " " ) );
|
||||||
|
}
|
||||||
|
} else if( cmd == "quit" || cmd == "q" ) {
|
||||||
|
if( args.count() > 0 ) { irc->quit( args.join( " " ) ); }
|
||||||
|
else { irc->quit(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MessageHandler::autoRun() {
|
||||||
|
//irc->join( "#pinet" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::startDCC( QString nickName, QString fileName ) {
|
||||||
|
for( int i = DCCPortMin; i <= DCCPortMax; i++ ) {
|
||||||
|
if( !DCCServers.keys().contains( i ) ) {
|
||||||
|
QString message = "DCC %1";
|
||||||
|
if( fileName.isEmpty() ) {
|
||||||
|
// Chat session
|
||||||
|
DCCServers[i] = new DCCChatServer( nickName );
|
||||||
|
connect( ((DCCChatServer*)DCCServers[i]), SIGNAL( connectedChat( QString ) ), this, SLOT( connectedDCCChat( QString ) ) );
|
||||||
|
DCCNicks[nickName] = i;
|
||||||
|
message = message.arg( "CHAT chat %1 %2" );
|
||||||
|
} else {
|
||||||
|
// File Send
|
||||||
|
QFileInfo fileInfo = QFileInfo( fileName );
|
||||||
|
if( !fileInfo.exists() ) { return; }
|
||||||
|
DCCServers[i] = new DCCFileServer( fileName, DCCSendAhead );
|
||||||
|
message = message.arg( "SEND %1 %3 %2" ).arg( fileInfo.fileName() ).arg( fileInfo.size() ).arg( "%1 %2" );
|
||||||
|
}
|
||||||
|
bool success = DCCServers[i]->listen( QHostAddress::Any, i );
|
||||||
|
qDebug() << QString( "Listen on port %1: %2" ).arg( i ).arg( success );
|
||||||
|
message = message.arg( irc->localHost.toIPv4Address() ).arg( i );
|
||||||
|
qDebug() << message;
|
||||||
|
irc->ctcp( nickName, message );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::connectedDCCChat( QString nickName ) {
|
||||||
|
DCCChatServer *dcc = ((DCCChatServer*)DCCServers[DCCNicks[nickName]]);
|
||||||
|
connect( dcc, SIGNAL( rcvdText( QString, QString ) ), this, SLOT( messageRcvdDCC( QString, QString ) ) );
|
||||||
|
connect( dcc, SIGNAL( sentText( QString, QString ) ), this, SLOT( messageSentDCC( QString, QString ) ) );
|
||||||
|
QString window = nickName.prepend( "=" );
|
||||||
|
_addWindow( window, "msg " + window );
|
||||||
|
windows[window]->echo( "DCC Chat Connected" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageHandler::sentRAW( QString text ) { qDebug() << ">>> " << text.trimmed(); }
|
||||||
|
void MessageHandler::rcvdRAW( QString text ) { qDebug() << "<<< " << text.trimmed(); }
|
39
guiapp/messagehandler.h
Normal file
39
guiapp/messagehandler.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QPointer>
|
||||||
|
#include "../src/ircclient.h"
|
||||||
|
#include "../src/dccserver.h"
|
||||||
|
#include "chatwindow.h"
|
||||||
|
|
||||||
|
class MessageHandler : public QTabWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
IRCClient *irc;
|
||||||
|
QHash< QString, ChatWindow* > windows;
|
||||||
|
QHash< QString, QVariant > variables;
|
||||||
|
int DCCPortMin;
|
||||||
|
int DCCPortMax;
|
||||||
|
bool DCCSendAhead;
|
||||||
|
QHash< int, DCCServer* > DCCServers;
|
||||||
|
QHash< QString, int > DCCNicks;
|
||||||
|
|
||||||
|
void _addWindow( QString name, QString defaultCmd = "", bool focusOnOpen = false );
|
||||||
|
QString parseVar( QString text );
|
||||||
|
public:
|
||||||
|
MessageHandler( IRCClient *irc, QWidget *parent = 0 );
|
||||||
|
public slots:
|
||||||
|
void messageRcvd( QString type, QString src, QString dest, QStringList values, QString text );
|
||||||
|
void messageSentDCC( QString nickName, QString text );
|
||||||
|
void messageRcvdDCC( QString nickName, QString text );
|
||||||
|
void processCmd( QString cmdText );
|
||||||
|
void autoRun();
|
||||||
|
void startDCC( QString nickName, QString fileName = "" );
|
||||||
|
void connectedDCCChat( QString nickName );
|
||||||
|
|
||||||
|
void rcvdRAW( QString text );
|
||||||
|
void sentRAW( QString text );
|
||||||
|
signals:
|
||||||
|
void dispatchMessage( QString window, QString src, QString message );
|
||||||
|
};
|
||||||
|
|
13
ircclient.pro
Normal file
13
ircclient.pro
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
######################################################################
|
||||||
|
# Automatically generated by qmake (2.01a) Mon Aug 13 14:31:09 2007
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
TARGET = ircclient
|
||||||
|
DESTDIR = bin
|
||||||
|
DEPENDPATH += . src
|
||||||
|
INCLUDEPATH += . src
|
||||||
|
QT += network
|
||||||
|
# Input
|
||||||
|
HEADERS += src/ircclient.h
|
||||||
|
SOURCES += src/ircclient.cpp
|
18
mirc/includes/mirc.h
Normal file
18
mirc/includes/mirc.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef MIRC_H
|
||||||
|
#define MIRC_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
#include "script.h"
|
||||||
|
|
||||||
|
class MIRCScriptManager : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
//QMap<QString, QString> variables;
|
||||||
|
|
||||||
|
MIRCScriptManager(QObject *parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
269
mirc/includes/parser.h
Normal file
269
mirc/includes/parser.h
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
/*
|
||||||
|
Mercenary
|
||||||
|
|
||||||
|
mIRC Scripting Language Parser
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define BOOST_SPIRIT_DEBUG
|
||||||
|
#include <string>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/spirit/core.hpp>
|
||||||
|
#include <boost/spirit/utility/confix.hpp>
|
||||||
|
#include <boost/spirit/dynamic/if.hpp>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QStack>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace boost;
|
||||||
|
using namespace boost::spirit;
|
||||||
|
|
||||||
|
typedef QMap<QString, QString> mirc_variables;
|
||||||
|
|
||||||
|
struct mirc_alias {
|
||||||
|
mirc_alias(bool _global = true) {
|
||||||
|
global = _global;
|
||||||
|
}
|
||||||
|
bool global;
|
||||||
|
QString code;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QMap<QString, mirc_alias> mirc_aliases;
|
||||||
|
|
||||||
|
enum mirc_engine_stage {
|
||||||
|
PARSE,
|
||||||
|
EXECUTE
|
||||||
|
};
|
||||||
|
|
||||||
|
class mirc_script_engine : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
mirc_aliases::iterator current_alias;
|
||||||
|
mirc_variables::iterator current_variable;
|
||||||
|
QStack<QStringList> stack;
|
||||||
|
public:
|
||||||
|
mirc_engine_stage stage;
|
||||||
|
mirc_alias script;
|
||||||
|
mirc_aliases aliases;
|
||||||
|
mirc_variables vars;
|
||||||
|
|
||||||
|
mirc_script_engine() : script() {
|
||||||
|
stage = PARSE;
|
||||||
|
current_alias = aliases.end();
|
||||||
|
current_variable = vars.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_alias_definition(char const* str, char const* end) {
|
||||||
|
if (stage != PARSE) return;
|
||||||
|
|
||||||
|
string s(str, end);
|
||||||
|
aliases.insert(s.c_str(), mirc_alias(true));
|
||||||
|
current_alias = aliases.find(s.c_str());
|
||||||
|
}
|
||||||
|
void handle_alias_definition_local(char const* str, char const* end) {
|
||||||
|
if (stage != PARSE) return;
|
||||||
|
|
||||||
|
string s(str, end);
|
||||||
|
aliases.insert(s.c_str(), mirc_alias(false));
|
||||||
|
current_alias = aliases.find(s.c_str());
|
||||||
|
}
|
||||||
|
void close_alias(char const*, char const*) {
|
||||||
|
if (stage != PARSE) return;
|
||||||
|
|
||||||
|
if (!aliases.empty() && current_alias != aliases.end()) {
|
||||||
|
current_alias = aliases.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void store_code(char const* str, char const* end) {
|
||||||
|
if (stage != PARSE) return;
|
||||||
|
|
||||||
|
string s(str, end);
|
||||||
|
if (!aliases.empty() && current_alias != aliases.end()) {
|
||||||
|
current_alias->code.append(s.c_str()).append("\n");
|
||||||
|
} else {
|
||||||
|
script.code.append(s.c_str()).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void call_alias(char const*, char const*) {
|
||||||
|
if (stage != EXECUTE) return;
|
||||||
|
|
||||||
|
}
|
||||||
|
void return_alias(char const*, char const*) {
|
||||||
|
}
|
||||||
|
void declare_variable(char const* str, char const* end) {
|
||||||
|
if (stage != EXECUTE) return;
|
||||||
|
string s(str, end);
|
||||||
|
vars.insert(s.c_str(), "");
|
||||||
|
current_variable = vars.find(s.c_str());
|
||||||
|
stack.push(QStringList());
|
||||||
|
}
|
||||||
|
void assign_variable(char const* str, char const* end) {
|
||||||
|
if (stage != EXECUTE) return;
|
||||||
|
|
||||||
|
if (current_variable != vars.end()) {
|
||||||
|
string s(str, end);
|
||||||
|
*current_variable = (!stack.isEmpty() ? stack.pop().join(" ") : "");
|
||||||
|
current_variable = vars.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void fetch_variable(char const*, char const*) {
|
||||||
|
if (stage != EXECUTE) return;
|
||||||
|
|
||||||
|
}
|
||||||
|
void append_expression(char const* str, char const *end) {
|
||||||
|
if (stage != EXECUTE) return;
|
||||||
|
|
||||||
|
string s(str, end);
|
||||||
|
QStringList list;
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
list << s.c_str();
|
||||||
|
} else {
|
||||||
|
list = stack.pop();
|
||||||
|
list << s.c_str();
|
||||||
|
}
|
||||||
|
stack.push(list);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mirc_script : public grammar<mirc_script> {
|
||||||
|
mirc_script_engine *actions;
|
||||||
|
|
||||||
|
mirc_script( mirc_script_engine *_actions ) {
|
||||||
|
actions = _actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ScannerT>
|
||||||
|
struct definition {
|
||||||
|
rule<ScannerT> script,
|
||||||
|
space,
|
||||||
|
identifier,
|
||||||
|
string,
|
||||||
|
expression,
|
||||||
|
expression_group,
|
||||||
|
parameters,
|
||||||
|
variable,
|
||||||
|
assignment,
|
||||||
|
alias_action,
|
||||||
|
alias_function,
|
||||||
|
alias_definition,
|
||||||
|
code_line,
|
||||||
|
code_block,
|
||||||
|
comment;
|
||||||
|
|
||||||
|
definition(mirc_script const &self) {
|
||||||
|
|
||||||
|
typedef function< void(const char*, const char*) > s_action;
|
||||||
|
s_action a_def ( bind( &mirc_script_engine::handle_alias_definition, self.actions, _1, _2 ) );
|
||||||
|
s_action l_def ( bind( &mirc_script_engine::handle_alias_definition_local, self.actions, _1, _2 ) );
|
||||||
|
s_action a_close ( bind( &mirc_script_engine::close_alias, self.actions, _1, _2 ) );
|
||||||
|
s_action v_def ( bind( &mirc_script_engine::declare_variable, self.actions, _1, _2 ) );
|
||||||
|
s_action v_assign ( bind( &mirc_script_engine::assign_variable, self.actions, _1, _2 ) );
|
||||||
|
s_action e_append ( bind( &mirc_script_engine::append_expression, self.actions, _1, _2 ) );
|
||||||
|
s_action s_code ( bind( &mirc_script_engine::store_code, self.actions, _1, _2 ) );
|
||||||
|
|
||||||
|
script
|
||||||
|
= *(
|
||||||
|
alias_definition[a_close]
|
||||||
|
| code_block
|
||||||
|
) >> end_p
|
||||||
|
;
|
||||||
|
space
|
||||||
|
= ( blank_p
|
||||||
|
//| (ch_p('\\') >> eol_p)
|
||||||
|
| str_p("$&") >> *blank_p >> eol_p
|
||||||
|
)
|
||||||
|
;
|
||||||
|
identifier
|
||||||
|
= alpha_p >> *alnum_p
|
||||||
|
;
|
||||||
|
string
|
||||||
|
= ( variable
|
||||||
|
| alias_function
|
||||||
|
| +(graph_p - ch_p(',') - ch_p('(') - ch_p(')'))
|
||||||
|
)[e_append]
|
||||||
|
;
|
||||||
|
expression
|
||||||
|
= string >> *(*space >> string)
|
||||||
|
;
|
||||||
|
expression_group
|
||||||
|
= expression | expression_group
|
||||||
|
;
|
||||||
|
parameters
|
||||||
|
= expression >> *(*space >> ch_p(',') >> *space >> expression)
|
||||||
|
;
|
||||||
|
variable
|
||||||
|
= ch_p('%') >> identifier
|
||||||
|
;
|
||||||
|
assignment
|
||||||
|
= !(str_p("var") >> *space)
|
||||||
|
>> variable[v_def]
|
||||||
|
>> *space >> ch_p('=') >> *space
|
||||||
|
>> expression[v_assign]
|
||||||
|
;
|
||||||
|
alias_action
|
||||||
|
= !ch_p('/') >> !ch_p('/')
|
||||||
|
>> identifier >> *space >> parameters
|
||||||
|
;
|
||||||
|
alias_function
|
||||||
|
= ch_p('$') >> identifier
|
||||||
|
>> !(
|
||||||
|
ch_p('(') >> *space
|
||||||
|
>> parameters >> *space
|
||||||
|
/*
|
||||||
|
>> (expression - ch_p(','))
|
||||||
|
>> *( *space
|
||||||
|
>> ch_p(',') >> *space
|
||||||
|
>> (expression - ch_p(','))
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
>> ch_p(')')
|
||||||
|
)
|
||||||
|
;
|
||||||
|
alias_definition
|
||||||
|
= str_p("alias") >> *space
|
||||||
|
//>> !(str_p("-l") >> *space)
|
||||||
|
>> if_p(str_p("-l") >> *space)[identifier[l_def]].else_p[identifier[a_def]]
|
||||||
|
>> *space >> !eol_p
|
||||||
|
>> code_block
|
||||||
|
;
|
||||||
|
code_line
|
||||||
|
= *space
|
||||||
|
>> ( comment
|
||||||
|
| (
|
||||||
|
assignment /* Must come first to avoid "var" being caught as an action */
|
||||||
|
| alias_action
|
||||||
|
)[s_code]
|
||||||
|
)
|
||||||
|
>> !eol_p
|
||||||
|
;
|
||||||
|
code_block
|
||||||
|
= ( *space >> ch_p('{') >> *space >> !eol_p
|
||||||
|
>> (*code_line)
|
||||||
|
>> ch_p('}') >> *space >> !eol_p
|
||||||
|
)
|
||||||
|
| code_line
|
||||||
|
;
|
||||||
|
comment = comment_p(";");
|
||||||
|
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(script);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(space);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(identifier);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(string);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(expression);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(variable);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(assignment);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(alias_action);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(alias_function);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(alias_definition);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(code_line);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(code_block);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(comment);
|
||||||
|
BOOST_SPIRIT_DEBUG_NODE(*this);
|
||||||
|
}
|
||||||
|
rule<ScannerT> const& start() const { return script; }
|
||||||
|
};
|
||||||
|
};
|
29
mirc/includes/script.h
Normal file
29
mirc/includes/script.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef MIRC_SCRIPT_H
|
||||||
|
#define MIRC_SCRIPT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QMap>
|
||||||
|
#include "mirc.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
class MIRCScript : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QString script;
|
||||||
|
QMap<QString, mirc_alias> _aliases;
|
||||||
|
QMap<QString, QString> _variables;
|
||||||
|
bool loaded;
|
||||||
|
public:
|
||||||
|
MIRCScript();
|
||||||
|
bool load(QString filename);
|
||||||
|
bool parse(QString script);
|
||||||
|
bool run();
|
||||||
|
bool run(QString alias);
|
||||||
|
QString code();
|
||||||
|
QString code(QString alias);
|
||||||
|
QMap<QString, mirc_alias> aliases();
|
||||||
|
QMap<QString, QString> variables();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
16
mirc/mirc.pro
Normal file
16
mirc/mirc.pro
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
######################################################################
|
||||||
|
# Automatically generated by qmake (2.01a) Sat Aug 30 23:01:47 2008
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
# CONFIG += plugin
|
||||||
|
TARGET = mirc
|
||||||
|
DESTDIR = bin
|
||||||
|
DEPENDPATH += . includes src
|
||||||
|
INCLUDEPATH += . includes
|
||||||
|
|
||||||
|
# Input
|
||||||
|
HEADERS += includes/mirc.h includes/parser.h includes/script.h
|
||||||
|
SOURCES += src/mirc.cpp \
|
||||||
|
src/parser.cpp \
|
||||||
|
src/script.cpp
|
4
mirc/src/mirc.cpp
Normal file
4
mirc/src/mirc.cpp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#include "mirc.h"
|
||||||
|
|
||||||
|
MIRCScriptManager::MIRCScriptManager(QObject *parent = 0) {
|
||||||
|
}
|
77
mirc/src/parser.cpp
Normal file
77
mirc/src/parser.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <QTextStream>
|
||||||
|
#include "script.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
QTextStream output(stdout);
|
||||||
|
|
||||||
|
QString foo;
|
||||||
|
foo.append("; Hey, here's some test code\n");
|
||||||
|
foo.append("set name Correl\n");
|
||||||
|
foo.append("%name = Correl $&\n\tRoush\n");
|
||||||
|
foo.append("echo Hello, %name!\n");
|
||||||
|
foo.append("alias dostuff {\n");
|
||||||
|
foo.append(" ; Not very useful, but good for testing the parser!\n");
|
||||||
|
foo.append(" var %b = 42\n");
|
||||||
|
foo.append(" %b = $calc(%b * 3)\n");
|
||||||
|
foo.append(" return %b;\n");
|
||||||
|
foo.append("}\n");
|
||||||
|
foo.append("alias -l dosomethingelse {\n");
|
||||||
|
foo.append(" ; Useless local alias!\n");
|
||||||
|
foo.append(" echo -s Busy doing nothing\n");
|
||||||
|
foo.append("}\n");
|
||||||
|
foo.append("alias -l dosomethingelse {\n");
|
||||||
|
foo.append(" ; Useless local alias!\n");
|
||||||
|
foo.append(" echo -s Busy doing nothing\n");
|
||||||
|
foo.append("}\n");
|
||||||
|
|
||||||
|
output << "Code:\n"
|
||||||
|
<< "================================================================================\n"
|
||||||
|
<< foo
|
||||||
|
<< "================================================================================\n"
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
mirc_script_engine *interpreter = new mirc_script_engine();
|
||||||
|
mirc_script parser(interpreter);
|
||||||
|
|
||||||
|
parse_info<> info = parse((const char*)foo.toLatin1(), parser);
|
||||||
|
|
||||||
|
if (info.full)
|
||||||
|
{
|
||||||
|
output << "-------------------------\n";
|
||||||
|
output << "Parsing succeeded\n";
|
||||||
|
output << "-------------------------\n";
|
||||||
|
|
||||||
|
MIRCScript *ms = new MIRCScript();
|
||||||
|
output << "Creating new MIRCScript object\n";
|
||||||
|
//if (ms->parse(foo)) {
|
||||||
|
if (ms->load("test.mrc")) {
|
||||||
|
output << "MRC LOADED\n";
|
||||||
|
output << "Code:\n" << ms->code();
|
||||||
|
output << "Aliases:\n";
|
||||||
|
QMapIterator<QString, mirc_alias> alias(ms->aliases());
|
||||||
|
while(alias.hasNext()) {
|
||||||
|
alias.next();
|
||||||
|
output << (alias.value().global ? "global" : "local");
|
||||||
|
output << " " << alias.key() << "\n";
|
||||||
|
}
|
||||||
|
if (ms->run()) {
|
||||||
|
output << "MRC RAN SUCCESSFULLY\n";
|
||||||
|
QMapIterator<QString, QString> i(ms->variables());
|
||||||
|
output << "Variables:\n";
|
||||||
|
while(i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
output << i.key() << " = " << i.value() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output << "-------------------------\n";
|
||||||
|
output << "Parsing failed\n";
|
||||||
|
output << "stopped at: \": " << info.stop << "\"\n";
|
||||||
|
output << "-------------------------\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
61
mirc/src/script.cpp
Normal file
61
mirc/src/script.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include "script.h"
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
MIRCScript::MIRCScript() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MIRCScript::load(QString filename) {
|
||||||
|
QFile file(filename);
|
||||||
|
if (file.exists() && file.open(QIODevice::ReadOnly)) {
|
||||||
|
QString code(file.readAll());
|
||||||
|
file.close();
|
||||||
|
return parse(code);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MIRCScript::parse(QString code) {
|
||||||
|
mirc_script_engine *interpreter = new mirc_script_engine();
|
||||||
|
mirc_script parser(interpreter);
|
||||||
|
parse_info<> info = boost::spirit::parse((const char*)code.toLatin1(), parser);
|
||||||
|
loaded = info.full;
|
||||||
|
if (loaded) {
|
||||||
|
script = interpreter->script.code;
|
||||||
|
_aliases = interpreter->aliases;
|
||||||
|
}
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MIRCScript::run() {
|
||||||
|
if (!loaded) return false;
|
||||||
|
mirc_script_engine *interpreter = new mirc_script_engine();
|
||||||
|
interpreter->stage = EXECUTE;
|
||||||
|
mirc_script parser(interpreter);
|
||||||
|
parse_info<> info = boost::spirit::parse((const char*)script.toLatin1(), parser);
|
||||||
|
if (info.full) {
|
||||||
|
_variables = interpreter->vars;
|
||||||
|
}
|
||||||
|
return info.full;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MIRCScript::run(QString alias) {
|
||||||
|
if (!loaded) return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MIRCScript::code() {
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MIRCScript::code(QString alias) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, mirc_alias> MIRCScript::aliases() {
|
||||||
|
return _aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> MIRCScript::variables() {
|
||||||
|
return _variables;
|
||||||
|
}
|
15
mirc/test.mrc
Normal file
15
mirc/test.mrc
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
; Hey, here's some test code
|
||||||
|
set name Correl
|
||||||
|
%name = Correl $&
|
||||||
|
Roush
|
||||||
|
echo Hello, %name!
|
||||||
|
alias dostuff {
|
||||||
|
; Not very useful, but good for testing the parser!
|
||||||
|
var %b = 42
|
||||||
|
%b = $calc(%b * 3)
|
||||||
|
return %b;
|
||||||
|
}
|
||||||
|
alias -l dosomethingelse {
|
||||||
|
; Useless local alias!
|
||||||
|
echo -s Busy doing nothing
|
||||||
|
}
|
77
src/dccserver.cpp
Normal file
77
src/dccserver.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include "dccserver.h"
|
||||||
|
|
||||||
|
DCCServer::DCCServer( QObject *parent ) : QTcpServer( parent ) {
|
||||||
|
connect( this, SIGNAL( newConnection() ), this, SLOT( connectClient() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCServer::connectClient() {
|
||||||
|
conn = nextPendingConnection();
|
||||||
|
connect( conn, SIGNAL( readyRead() ), this, SLOT( readSocket() ) );
|
||||||
|
close(); // No more than one client
|
||||||
|
}
|
||||||
|
|
||||||
|
DCCChatServer::DCCChatServer( QString nickName, QObject *parent ) : DCCServer( parent ) {
|
||||||
|
this->nickName = nickName.trimmed();
|
||||||
|
connect( this, SIGNAL( newConnection() ), this, SLOT( connectChatClient() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCChatServer::sendText( QString text ) {
|
||||||
|
emit sentText( nickName, text );
|
||||||
|
text.append( "\r\n" );
|
||||||
|
conn->write( text.toLatin1() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCChatServer::connectChatClient() {
|
||||||
|
emit connectedChat( nickName );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCChatServer::readSocket() {
|
||||||
|
if( !conn->canReadLine() ) return;
|
||||||
|
char buf[512];
|
||||||
|
while( conn->readLine( buf, sizeof( buf ) ) > 0 )
|
||||||
|
emit rcvdText( nickName, QString( buf ).trimmed() );
|
||||||
|
}
|
||||||
|
|
||||||
|
DCCFileServer::DCCFileServer( QString fileName, bool sendAhead, QObject *parent ) : DCCServer( parent ) {
|
||||||
|
chunkSize = 1024;
|
||||||
|
sent = 0;
|
||||||
|
verified = 0;
|
||||||
|
this->sendAhead = sendAhead;
|
||||||
|
file.setFileName( fileName );
|
||||||
|
file.open( QIODevice::ReadOnly );
|
||||||
|
connect( this, SIGNAL( newConnection() ), this, SLOT( connectFileClient() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCFileServer::connectFileClient() {
|
||||||
|
emit connectedFile( conn->localPort() );
|
||||||
|
// Send the initial chunk of data
|
||||||
|
sendNextChunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCFileServer::readSocket() {
|
||||||
|
char buf[4];
|
||||||
|
while( conn->bytesAvailable() >= 4 ) {
|
||||||
|
conn->read( buf, 4 );
|
||||||
|
quint32 v = *reinterpret_cast<quint32*>( &buf[0] );
|
||||||
|
v = qFromBigEndian( v );
|
||||||
|
verified = v;
|
||||||
|
if( sendAhead || verified == sent ) { sendNextChunk(); }
|
||||||
|
if( !file.isOpen() ) { conn->close(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCCFileServer::sendNextChunk() {
|
||||||
|
char buf[chunkSize];
|
||||||
|
if( !file.isOpen() || !file.isReadable() || !conn->isOpen() ) { return; }
|
||||||
|
qint64 bytesRead = 0;
|
||||||
|
while( ( sendAhead || sent == verified ) && ( bytesRead = file.read( buf, chunkSize ) ) ) {
|
||||||
|
if( bytesRead > 0 ) {
|
||||||
|
conn->write( buf, bytesRead );
|
||||||
|
}
|
||||||
|
sent += bytesRead;
|
||||||
|
if( conn->bytesAvailable() >= 4 ) { readSocket(); }
|
||||||
|
}
|
||||||
|
if( bytesRead < chunkSize && sent == verified ) {
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
60
src/dccserver.h
Normal file
60
src/dccserver.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef DCCSERVER_H
|
||||||
|
#define DCCSERVER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QtEndian>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
class DCCServer: public QTcpServer {
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
QTcpSocket *conn;
|
||||||
|
public:
|
||||||
|
DCCServer( QObject *parent = 0 );
|
||||||
|
protected slots:
|
||||||
|
void connectClient();
|
||||||
|
};
|
||||||
|
|
||||||
|
class DCCChatServer : public DCCServer {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QString nickName;
|
||||||
|
public:
|
||||||
|
DCCChatServer( QString nickName, QObject *parent = 0 );
|
||||||
|
private slots:
|
||||||
|
void connectChatClient();
|
||||||
|
void readSocket();
|
||||||
|
public slots:
|
||||||
|
void sendText( QString text );
|
||||||
|
signals:
|
||||||
|
void connectedChat( QString nickName );
|
||||||
|
void sentText( QString nickName, QString text );
|
||||||
|
void rcvdText( QString nickName, QString text );
|
||||||
|
};
|
||||||
|
|
||||||
|
class DCCFileServer : public DCCServer {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
int port;
|
||||||
|
QFile file;
|
||||||
|
int chunkSize;
|
||||||
|
quint64 sent;
|
||||||
|
quint64 verified;
|
||||||
|
bool sendAhead;
|
||||||
|
public:
|
||||||
|
DCCFileServer( QString fileName, bool sendAhead = false, QObject *parent = 0 );
|
||||||
|
private slots:
|
||||||
|
void connectFileClient();
|
||||||
|
void readSocket();
|
||||||
|
void sendNextChunk();
|
||||||
|
signals:
|
||||||
|
void connectedFile( int port );
|
||||||
|
void progress( int port, double percentage );
|
||||||
|
void complete( int port, bool success );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
121
src/ircclient.cpp
Normal file
121
src/ircclient.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#include "ircclient.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
IRCClient::IRCClient( QObject *parent ) : QObject( parent ) {
|
||||||
|
conn = new QTcpSocket();
|
||||||
|
QObject::connect( conn, SIGNAL( readyRead() ), this, SLOT( readSocket() ) );
|
||||||
|
QObject::connect( conn, SIGNAL( connected() ), this, SLOT( _connected() ) );
|
||||||
|
QObject::connect( conn, SIGNAL( disconnected() ), this, SLOT( _disconnected() ) );
|
||||||
|
QObject::connect( this, SIGNAL( rcvdRAW( QString ) ), this, SLOT( parseMessage( QString ) ) );
|
||||||
|
nickName = userName = realName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCClient::connectAndRegister( QString host, uint port, QString nickName, QString userName, QString realName ) {
|
||||||
|
conn->abort();
|
||||||
|
conn->connectToHost( host, port );
|
||||||
|
this->nickName = nickName;
|
||||||
|
this->userName = userName;
|
||||||
|
this->realName = realName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCClient::raw( QString text ) {
|
||||||
|
// Send raw text to the IRC Server
|
||||||
|
text.append( "\r\n" );
|
||||||
|
conn->write( text.toLatin1() );
|
||||||
|
emit sentRAW( text );
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCClient::msg( QString dest, QString text ) { raw( "PRIVMSG " + dest + " :" + text ); }
|
||||||
|
void IRCClient::ctcp( QString dest, QString text ) { raw( "PRIVMSG " + dest + " :\001" + text + "\001" ); }
|
||||||
|
void IRCClient::notice( QString dest, QString text ) { raw( "NOTICE " + dest + " :" + text ); }
|
||||||
|
void IRCClient::join( QString channel ) { raw( "JOIN " + channel ); }
|
||||||
|
void IRCClient::quit( QString reason ) { raw( "QUIT :" + reason ); conn->flush(); }
|
||||||
|
void IRCClient::quit() { quit( tr( "Quit" ) ); }
|
||||||
|
void IRCClient::nick( QString nick ) { raw( "NICK " + nick ); }
|
||||||
|
|
||||||
|
void IRCClient::_connected() {
|
||||||
|
localHost = conn->localAddress();
|
||||||
|
emit connected();
|
||||||
|
// Register
|
||||||
|
raw( "USER " + userName + " +iw localhost :" + realName );
|
||||||
|
nick( nickName );
|
||||||
|
}
|
||||||
|
void IRCClient::_disconnected() { emit disconnected(); }
|
||||||
|
|
||||||
|
void IRCClient::closeSocket() {
|
||||||
|
emit disconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCClient::updateHostInfo( QHostInfo host ) {
|
||||||
|
if (host.error() != QHostInfo::NoError) {
|
||||||
|
qDebug() << "Lookup failed: " + host.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (QHostAddress address, host.addresses())
|
||||||
|
localHost = address;
|
||||||
|
qDebug() << "Host updated: " + localHost.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCClient::readSocket() {
|
||||||
|
if( !conn->canReadLine() ) return;
|
||||||
|
char buf[512];
|
||||||
|
while( conn->readLine( buf, sizeof( buf ) ) > 0 )
|
||||||
|
emit rcvdRAW( buf );
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRCClient::parseMessage( QString text ) {
|
||||||
|
text = text.trimmed();
|
||||||
|
int split = text.indexOf( " :" );
|
||||||
|
QString message = split >= 0 ? text.left( split ) : text;
|
||||||
|
QString messageText = split >= 0 ? text.right( text.length() - split - 2 ) : "";
|
||||||
|
|
||||||
|
QString from = "";
|
||||||
|
QString type = "";
|
||||||
|
QString dest = "";
|
||||||
|
QStringList values;
|
||||||
|
QStringList parsedMessage = message.split( ' ' );
|
||||||
|
if( parsedMessage.count() > 0 ) {
|
||||||
|
if( message.startsWith( ':' ) ) from = parsedMessage.takeFirst();
|
||||||
|
if( parsedMessage.count() > 0 ) type = parsedMessage.takeFirst();
|
||||||
|
if( parsedMessage.count() > 0 ) dest = parsedMessage.takeFirst();
|
||||||
|
values = parsedMessage;
|
||||||
|
} else {
|
||||||
|
type = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following are special cases that can be taken care of immediately
|
||||||
|
// Anything else should probably be dealt with by an actual client
|
||||||
|
if( type == "001" ) {
|
||||||
|
emit registered();
|
||||||
|
// Fetch the hostname from the welcome text if it's there and perform a nonblocking dns lookup
|
||||||
|
QString hostMask = messageText.right( messageText.length() - messageText.lastIndexOf( ' ' ) - 1 );
|
||||||
|
if( hostMask.contains( '@' ) ) {
|
||||||
|
QString hostName = hostMask.right( hostMask.length() - hostMask.indexOf( '@' ) - 1 );
|
||||||
|
qDebug() << "Looking up " + hostName;
|
||||||
|
QHostInfo::lookupHost( hostName, this, SLOT( updateHostInfo( QHostInfo ) ) );
|
||||||
|
} else {
|
||||||
|
raw( "WHOIS " + nickName );
|
||||||
|
}
|
||||||
|
} else if( type == "311" ) {
|
||||||
|
// RPL_WHOIS
|
||||||
|
if( values.count() < 3 ) return;
|
||||||
|
if( values[0] == nickName ) {
|
||||||
|
qDebug() << "Looking up " + values[2];
|
||||||
|
QHostInfo::lookupHost( values[2], this, SLOT( updateHostInfo( QHostInfo ) ) );
|
||||||
|
}
|
||||||
|
} else if( type == "NICK" && from.startsWith( ":" + nickName + "!" ) ) {
|
||||||
|
nickName = messageText;
|
||||||
|
} else if( type == "PING" ) {
|
||||||
|
raw( "PONG :" + messageText );
|
||||||
|
emit pingPong();
|
||||||
|
} else if( type == "PRIVMSG" ) {
|
||||||
|
if( messageText.startsWith( "\001" ) && messageText.endsWith( "\001" ) ) {
|
||||||
|
// CTCP Message
|
||||||
|
type = "CTCP";
|
||||||
|
messageText = messageText.mid( 1, messageText.length() - 2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//qDebug() << "t" << type << "s" << from << "d" << dest << "v" << values.join( "," ) << "m" << messageText;
|
||||||
|
emit messageRcvd( type, from, dest, values, messageText );
|
||||||
|
}
|
65
src/ircclient.h
Normal file
65
src/ircclient.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef IRCCLIENT_H
|
||||||
|
#define IRCCLIENT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QHostInfo>
|
||||||
|
|
||||||
|
|
||||||
|
class IRCClient : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QString nickName, userName, realName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QTcpSocket *conn;
|
||||||
|
QHostAddress localHost;
|
||||||
|
|
||||||
|
IRCClient( QObject *parent = 0 );
|
||||||
|
//void connect( QString host, uint port, QString nickName );
|
||||||
|
void connectAndRegister( QString host, uint port, QString nickName, QString userName, QString realName );
|
||||||
|
void raw( QString text );
|
||||||
|
void msg( QString dest, QString message );
|
||||||
|
void ctcp( QString dest, QString message );
|
||||||
|
void notice( QString dest, QString message );
|
||||||
|
void join( QString channel );
|
||||||
|
void nick( QString nick );
|
||||||
|
|
||||||
|
QString getNickName() { return nickName; }
|
||||||
|
QString getUserName() { return userName; }
|
||||||
|
QString getRealName() { return realName; }
|
||||||
|
QString getIPAddress() { return localHost.toString(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// Basic
|
||||||
|
void connected();
|
||||||
|
void disconnected();
|
||||||
|
void registered();
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
void rcvdRAW( QString text );
|
||||||
|
void sentRAW( QString text );
|
||||||
|
void debug( QString text );
|
||||||
|
|
||||||
|
// Events
|
||||||
|
void pingPong();
|
||||||
|
void messageRcvd( QString type, QString src, QString dest, QStringList values, QString text );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void quit( QString reason );
|
||||||
|
void quit(); // No reason...
|
||||||
|
void updateHostInfo( QHostInfo host );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void _connected();
|
||||||
|
void _disconnected();
|
||||||
|
void closeSocket();
|
||||||
|
void readSocket();
|
||||||
|
void parseMessage( QString text );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
8
testapp/main.cpp
Normal file
8
testapp/main.cpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include "testapp.h"
|
||||||
|
|
||||||
|
int main( int argc, char *argv[] ) {
|
||||||
|
TestApp app( argc, argv );
|
||||||
|
return app.exec();
|
||||||
|
}
|
38
testapp/testapp.cpp
Normal file
38
testapp/testapp.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "testapp.h"
|
||||||
|
|
||||||
|
TestApp::TestApp( int argc, char *argv[] ) : QCoreApplication( argc, argv ) {
|
||||||
|
irc = new IRCClient();
|
||||||
|
connect( irc->conn, SIGNAL( connected() ), this, SLOT( connected() ) );
|
||||||
|
connect( irc->conn, SIGNAL( disconnected() ), this, SLOT( disconnected() ) );
|
||||||
|
connect( irc, SIGNAL( registered() ), this, SLOT( registered() ) );
|
||||||
|
connect( irc, SIGNAL( sentRAW( QString ) ), this, SLOT( sent( QString ) ) );
|
||||||
|
connect( irc, SIGNAL( rcvdRAW( QString ) ), this, SLOT( rcvd( QString ) ) );
|
||||||
|
connect( irc, SIGNAL( debug( QString ) ), this, SLOT( debug( QString ) ) );
|
||||||
|
|
||||||
|
irc->connectAndRegister( argc > 1 ? argv[1] : "dev1", 6667, argc > 2 ? argv[2] : "Test", "correlr", "Correl Roush" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestApp::connected() {
|
||||||
|
printf( "Connected!\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestApp::registered() {
|
||||||
|
irc->join( "#pinet" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestApp::disconnected() {
|
||||||
|
printf( "Disconnected.\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestApp::sent( QString text ) {
|
||||||
|
printf( ">>> %s", (const char*)text.toLatin1() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestApp::rcvd( QString text ) {
|
||||||
|
printf( "<<< %s", (const char*)text.toLatin1() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestApp::debug( QString text ) {
|
||||||
|
printf( "DEBUG: %s\n", (const char*)text.toLatin1() );
|
||||||
|
}
|
||||||
|
|
21
testapp/testapp.h
Normal file
21
testapp/testapp.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include "../src/ircclient.h"
|
||||||
|
|
||||||
|
class TestApp : public QCoreApplication {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestApp( int argc, char *argv[] );
|
||||||
|
|
||||||
|
private:
|
||||||
|
IRCClient *irc;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void connected();
|
||||||
|
void disconnected();
|
||||||
|
void registered();
|
||||||
|
void sent( QString text );
|
||||||
|
void rcvd( QString text );
|
||||||
|
void debug( QString text );
|
||||||
|
};
|
14
testapp/testapp.pro
Normal file
14
testapp/testapp.pro
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
######################################################################
|
||||||
|
# Automatically generated by qmake (2.01a) Mon Aug 13 15:01:40 2007
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
TARGET = testapp
|
||||||
|
DESTDIR = bin
|
||||||
|
DEPENDPATH += .
|
||||||
|
INCLUDEPATH += .
|
||||||
|
QT += network
|
||||||
|
|
||||||
|
# Input
|
||||||
|
HEADERS += testapp.h ../src/ircclient.h
|
||||||
|
SOURCES += main.cpp testapp.cpp ../src/ircclient.cpp
|
Loading…
Reference in a new issue