mirror of
https://github.com/correl/mercenary.git
synced 2024-11-23 11:09:50 +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