commit a57ababfece7c1e1b1fb12014d25c82c5a17ba66 Author: unknown Date: Thu May 21 15:26:18 2015 +0200 initial commit diff --git a/SparrowBot.pro b/SparrowBot.pro new file mode 100644 index 0000000..fa18909 --- /dev/null +++ b/SparrowBot.pro @@ -0,0 +1,28 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2015-05-13T11:07:00 +# +#------------------------------------------------- + +QT += core gui network widgets + +TARGET = SparrowBot +TEMPLATE = app +CONFIG += c++11 + +SOURCES += main.cpp\ + mainwindow.cpp \ + sparrowbot.cpp \ + socketirc.cpp \ + message.cpp \ + user.cpp \ + prompt.cpp + +HEADERS += mainwindow.h \ + sparrowbot.h \ + socketirc.h \ + message.h \ + user.h \ + prompt.h + +FORMS += mainwindow.ui diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..90f42fc --- /dev/null +++ b/main.cpp @@ -0,0 +1,45 @@ +#include "mainwindow.h" +#include "socketirc.h" +#include "sparrowbot.h" +#include + +int main(int argc, char *argv[]) +{ + // set up the socket + SocketIRC sock; + sock.setServer("irc.freenode.net"); + sock.setPort(6667); + + // set up the bot + SparrowBot* bot = new SparrowBot("SparrowBot", "#epicsparrow"); + QObject::connect(&sock, SIGNAL(receivedMsg(QString)), bot, SLOT(receiveMsg(QString))); + QObject::connect(bot, SIGNAL(sendMsg(QString)), &sock, SLOT(sendMsg(QString))); + QObject::connect(bot, SIGNAL(changeSocketStatus(int)), &sock, SLOT(setConnected(int))); + + // set up Qt + QApplication a(argc, argv); + bool nogui = a.arguments().contains("-nogui"); + MainWindow w; + + // set up UI + if(!nogui) + { + // bind signals to slots + QObject::connect(&sock, SIGNAL(receivedMsg(QString)), w.getConsole(), SLOT(append(QString))); + QObject::connect(&sock, SIGNAL(stateChanged(int)), w.getLed(), SLOT(setValue(int))); + QObject::connect(&sock, SIGNAL(stateChanged(int)), w.getSwitch(), SLOT(setValue(int))); + + QObject::connect(w.getPrompt(), SIGNAL(sendMsg(QString)), &sock, SLOT(sendMsg(QString))); + QObject::connect(w.getPrompt(), SIGNAL(returnPressed()), w.getPrompt(), SLOT(confirmationPerformed())); + + QObject::connect(w.getSwitch(), SIGNAL(valueChanged(int)), bot, SLOT(forceStatus(int))); + + // show window + w.show(); + } + + // run event loop on the main thread + if(nogui) + bot->forceStatus(1); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..399f54e --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,34 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +QTextBrowser* MainWindow::getConsole() +{ + return this->ui->monitoringConsole; +} + +QSlider* MainWindow::getSwitch() +{ + return this->ui->connectSwitch; +} + +QProgressBar* MainWindow::getLed() +{ + return this->ui->statusLed; +} + +Prompt* MainWindow::getPrompt() +{ + return this->ui->prompt; +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..b518d61 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,30 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "prompt.h" +#include +#include +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + QTextBrowser* getConsole(); + QSlider* getSwitch(); + QProgressBar* getLed(); + Prompt* getPrompt(); +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..2cd4ba3 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,66 @@ + + + MainWindow + + + + 0 + 0 + 374 + 404 + + + + MainWindow + + + + + + + 1 + + + 1 + + + Qt::Horizontal + + + + + + + 1 + + + 0 + + + false + + + false + + + + + + + + + + + + + + + + Prompt + QLineEdit +
prompt.h
+
+
+ + +
diff --git a/message.cpp b/message.cpp new file mode 100644 index 0000000..773c08a --- /dev/null +++ b/message.cpp @@ -0,0 +1,40 @@ +#include "message.h" + +#include +#include + +using namespace std; + +Message::Message(QString str) +{ + if(str.startsWith("PING")) + { + command = "PING"; + target = "PING"; + src = str.right(str.size()-(str.indexOf(':')+1)); + args = str; + } + else + { + // remove the first char, which is ':' + str = str.remove(0, 1); + // locate the mid ':' separator + int mid = str.indexOf(':'); + // the arguments are after the separator + args = str.right(str.size()-(mid+1)); + // the interesting infos before the separator are separated by spaces + QStringList list = str.split(' '); + // source of the message + src = list.takeFirst(); + // command issued by the source + command = list.takeFirst(); + // target of the command + target = list.takeFirst(); + } +} + +Message::~Message() +{ + +} + diff --git a/message.h b/message.h new file mode 100644 index 0000000..032e5ca --- /dev/null +++ b/message.h @@ -0,0 +1,18 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +#include +#include + +class Message +{ +public: + QString src; + QString command; + QString target; + QString args; + Message(QString str); + ~Message(); +}; + +#endif // MESSAGE_H diff --git a/prompt.cpp b/prompt.cpp new file mode 100644 index 0000000..b3f8757 --- /dev/null +++ b/prompt.cpp @@ -0,0 +1,8 @@ +#include "prompt.h" + +void Prompt::confirmationPerformed() +{ + QString str = text(); + clear(); + emit sendMsg(str.append("\r\n")); +} diff --git a/prompt.h b/prompt.h new file mode 100644 index 0000000..c2671bd --- /dev/null +++ b/prompt.h @@ -0,0 +1,19 @@ +#ifndef PROMPT_H +#define PROMPT_H + +#include + +class Prompt : public QLineEdit +{ + Q_OBJECT +public: + Prompt(QWidget*& w) : QLineEdit(w) {} + +public slots: + void confirmationPerformed(); + +signals: + void sendMsg(QString); +}; + +#endif // PROMPT_H diff --git a/socketirc.cpp b/socketirc.cpp new file mode 100644 index 0000000..12d740c --- /dev/null +++ b/socketirc.cpp @@ -0,0 +1,61 @@ +#include "socketirc.h" +#include + +SocketIRC::SocketIRC() : server("irc.freenode.net"), port(6667), isConnected(false) +{ + connect(&sock, SIGNAL(readyRead()), this, SLOT(readMsg())); +} + +void SocketIRC::setServer(std::string server_) +{ + server = server_; +} + +void SocketIRC::setPort(int port_) +{ + port = port_; +} + +void SocketIRC::sendMsg(QString msg) +{ + if(isConnected) + { + sock.write(msg.toStdString().c_str()); + sock.flush(); + std::cout << msg.toStdString(); + } +} + +void SocketIRC::setConnected(int c) +{ + if(c != isConnected) + { + if(isConnected) + { + sock.close(); + isConnected = false; + emit stateChanged(isConnected); + } + else + { + sock.connectToHost(QString(server.c_str()), quint16(port)); + if(sock.waitForConnected(5000)) + isConnected = true; + else + std::cerr << "failed to connect : " << sock.errorString().toStdString() << std::endl; + emit stateChanged(isConnected); + } + } +} + +void SocketIRC::readMsg() +{ + char buffer[512]; + while(sock.canReadLine()) + { + int numbytes = sock.readLine(buffer, 512); + buffer[numbytes - 2] = '\0'; + std::cout << buffer << std::endl; + emit receivedMsg(QString(buffer)); + } +} diff --git a/socketirc.h b/socketirc.h new file mode 100644 index 0000000..31803ea --- /dev/null +++ b/socketirc.h @@ -0,0 +1,37 @@ +#ifndef SOCKETIRC_H +#define SOCKETIRC_H + +#include +#include +#include + +class SocketIRC : public QObject +{ + Q_OBJECT + +public: + + SocketIRC(); + void setServer(std::string server_); + void setPort(int port_); + +private: + + std::string server; + int port; + QTcpSocket sock; + bool isConnected; + +private slots: + void readMsg(); + +public slots: + void sendMsg(QString msg); + void setConnected(int c); + +signals: + void receivedMsg(QString msg); + void stateChanged(int newState); +}; + +#endif // SOCKETIRC_H diff --git a/sparrowbot.cpp b/sparrowbot.cpp new file mode 100644 index 0000000..85064b4 --- /dev/null +++ b/sparrowbot.cpp @@ -0,0 +1,95 @@ +#include "sparrowbot.h" +#include +#include +#include + +using namespace std; + +void SparrowBot::receiveMsg(QString msg) +{ + string str; + if(msg.contains("PING")) + { + str = "PONG\r\n"; + emit sendMsg(QString(str.c_str())); + } + switch(status) + { + case OFFLINE : + status = ONLINE; + sendRawMessage("NICK " + nick + "\r\nUSER " + nick + " 0 * " + nick + "\r\n"); + break; + case ONLINE : + status = ON_CHAN; + sendRawMessage("JOIN #" + chan + "\r\n"); + break; + case ON_CHAN : + handleMessage(Message(msg)); + break; + } +} + +void SparrowBot::forceStatus(int newStatus) +{ + emit changeSocketStatus(newStatus); + if(newStatus) + { + //status = ONLINE; + //sendRawMessage("NICK " + nick + "\r\nUSER " + nick + " 0 * " + nick + "\r\n"); + } + else + { + status = OFFLINE; + } +} + +void SparrowBot::handleMessage(Message msg) +{ + //char* str = msg.args.toStdString().c_str(); + if(msg.command.compare(QString("PRIVMSG"), Qt::CaseInsensitive) == 0) + { + // message + + + if(msg.args.compare("!destroy") == 0) + { + sendRawMessage("QUIT :i'll be back\r\n"); + status = OFFLINE; + emit changeSocketStatus(false); + } + if(msg.args.compare("!list") == 0) + { + string str = "Online users : "; + for(User u : users) + str += u.getNick().toStdString() + " "; + say(str); + } + } + + if(msg.command.compare(QString("353"), Qt::CaseInsensitive) == 0) + { + // names + QStringList names = msg.args.split(' '); + for(QString s : names) + { + User u = User(s); + users.push_back(u); + sendRawMessage("WHOIS "+u.getNick().toStdString()+"\r\n"); + } + } +} + +void SparrowBot::say(string str) +{ + sendRawMessage("PRIVMSG #" + chan + " :" + str + "\r\n"); +} + +void SparrowBot::action(string str) +{ + sendRawMessage("PRIVMSG #" + chan + " :ACTION " + str + "\r\n"); +} + +void SparrowBot::sendRawMessage(string str) +{ + emit sendMsg(QString(str.c_str())); +} diff --git a/sparrowbot.h b/sparrowbot.h new file mode 100644 index 0000000..dfe37f7 --- /dev/null +++ b/sparrowbot.h @@ -0,0 +1,39 @@ +#ifndef SPARROWBOT_H +#define SPARROWBOT_H + +#include "user.h" +#include "message.h" +#include +#include + +class SparrowBot : public QObject +{ + Q_OBJECT + + enum{OFFLINE, ONLINE, ON_CHAN}; + + std::string nick; + std::string chan; + int status; + + std::vector users; +public: + SparrowBot() : nick("SparrowBot"), chan("epicsparrow"), status(OFFLINE) {} + SparrowBot(std::string nick_, std::string chan_) : nick(nick_), chan(chan_), status(OFFLINE) {} + +private: + void handleMessage(Message msg); + void say(std::string str); + void action(std::string str); + void sendRawMessage(std::string str); + +public slots: + void receiveMsg(QString msg); + void forceStatus(int newStatus); + +signals: + void sendMsg(QString msg); + void changeSocketStatus(int newStatus); +}; + +#endif // SPARROWBOT_H diff --git a/user.cpp b/user.cpp new file mode 100644 index 0000000..a2b51f2 --- /dev/null +++ b/user.cpp @@ -0,0 +1,15 @@ +#include "user.h" + +User::User(QString str) +{ + isOp = (str.at(0) == '@'); + if(isOp) + str = str.remove(0, 1); + nick = str; +} + +QString User::getNick() +{ + return nick; +} + diff --git a/user.h b/user.h new file mode 100644 index 0000000..ef6f981 --- /dev/null +++ b/user.h @@ -0,0 +1,16 @@ +#ifndef USER_H +#define USER_H + +#include + +class User +{ + QString nick; + bool isOp; + +public: + User(QString str); + QString getNick(); +}; + +#endif // USER_H