From 1c7d9f13b744cd517c0769f453fd8dc3106cd94c Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Tue, 24 Oct 2006 10:15:10 +0000 Subject: [PATCH] More neato stuff. A preliminary TabWidget now allows us to display multiple buffers, and we already sorta use this feature. Implemented /say, /quote and /join. Made output prettier. However, this is all still pretty much work in progress and I guess there are still some Q_ASSERTs triggering where they shouldn't. --- core/core.cpp | 17 ++--- core/core.h | 6 +- core/coreproxy.cpp | 2 +- core/coreproxy.h | 7 +- gui/CMakeLists.txt | 3 +- gui/channelwidget.cpp | 122 ++++++++++++++++++++++++++-------- gui/channelwidget.h | 46 +++++++++++-- gui/channelwidget.ui | 26 +++++++- gui/guiproxy.cpp | 5 +- gui/guiproxy.h | 9 ++- gui/ircwidget.ui | 44 +++++++++++++ gui/mainwin.cpp | 19 ++---- main/global.cpp | 5 +- main/proxy_common.h | 1 + network/CMakeLists.txt | 4 +- network/buffer.cpp | 10 +++ network/buffer.h | 15 +++++ network/message.cpp | 101 +++-------------------------- network/message.h | 84 ++++-------------------- network/server.cpp | 144 ++++++++++++++++++++++++++++++++++++----- network/server.h | 37 ++++++++--- 21 files changed, 448 insertions(+), 259 deletions(-) create mode 100644 gui/ircwidget.ui diff --git a/core/core.cpp b/core/core.cpp index f7fedd11..6270527f 100644 --- a/core/core.cpp +++ b/core/core.cpp @@ -29,8 +29,8 @@ Core::Core() { if(core) qFatal("Trying to instantiate more than one Core object!"); connect(coreProxy, SIGNAL(gsRequestConnect(QStringList)), this, SLOT(connectToIrc(QStringList))); - connect(coreProxy, SIGNAL(gsUserInput(QString)), this, SLOT(inputLine(QString))); - connect(this, SIGNAL(sendMessage(QString, QString, QString)), coreProxy, SLOT(csSendMessage(QString, QString, QString))); + connect(coreProxy, SIGNAL(gsUserInput(QString, QString, QString)), this, SIGNAL(msgFromGUI(QString, QString, QString))); + connect(this, SIGNAL(sendMessage(QString, QString, Message)), coreProxy, SLOT(csSendMessage(QString, QString, Message))); connect(this, SIGNAL(sendStatusMsg(QString, QString)), coreProxy, SLOT(csSendStatusMsg(QString, QString))); // Read global settings from config file @@ -54,12 +54,6 @@ void Core::globalDataUpdated(QString key) { s.setValue(QString("Global/")+key, data); } -// temp -void Core::inputLine(QString s) { - emit msgFromGUI("", "", s); - -} - void Core::connectToIrc(QStringList networks) { foreach(QString net, networks) { if(servers.contains(net)) { @@ -69,8 +63,10 @@ void Core::connectToIrc(QStringList networks) { connect(this, SIGNAL(connectToIrc(QString)), server, SLOT(connectToIrc(QString))); connect(this, SIGNAL(disconnectFromIrc(QString)), server, SLOT(disconnectFromIrc(QString))); connect(this, SIGNAL(msgFromGUI(QString, QString, QString)), server, SLOT(userInput(QString, QString, QString))); - connect(server, SIGNAL(sendMessage(QString, QString)), this, SLOT(recvMessageFromServer(QString, QString))); + connect(server, SIGNAL(sendMessage(QString, Message)), this, SLOT(recvMessageFromServer(QString, Message))); connect(server, SIGNAL(sendStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString))); + connect(server, SIGNAL(setTopic(QString, QString, QString)), coreProxy, SLOT(csSetTopic(QString, QString, QString))); + connect(server, SIGNAL(setNicks(QString, QString, QStringList)), coreProxy, SLOT(csSetNicks(QString, QString, QStringList))); // add error handling server->start(); @@ -80,7 +76,7 @@ void Core::connectToIrc(QStringList networks) { } } -void Core::recvMessageFromServer(QString buf, QString msg) { +void Core::recvMessageFromServer(QString buf, Message msg) { Q_ASSERT(sender()); QString net = qobject_cast(sender())->getNetwork(); emit sendMessage(net, buf, msg); @@ -89,7 +85,6 @@ void Core::recvMessageFromServer(QString buf, QString msg) { void Core::recvStatusMsgFromServer(QString msg) { Q_ASSERT(sender()); QString net = qobject_cast(sender())->getNetwork(); - qDebug() << "sent status:"< servers; diff --git a/core/coreproxy.cpp b/core/coreproxy.cpp index 3db3f152..91380470 100644 --- a/core/coreproxy.cpp +++ b/core/coreproxy.cpp @@ -122,7 +122,7 @@ void CoreProxy::recv(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) //qDebug() << "[CORE] Received signal" << sig << ":" << arg1< #include @@ -39,12 +40,14 @@ class CoreProxy : public QObject { public slots: inline void csUpdateGlobalData(QString key, QVariant data) { send(CS_UPDATE_GLOBAL_DATA, key, data); } - inline void csSendMessage(QString net, QString chan, QString msg) { send(CS_SEND_MESSAGE, net, chan, msg); } + inline void csSendMessage(QString net, QString buf, Message msg) { send(CS_SEND_MESSAGE, net, buf, QVariant::fromValue(msg)); } inline void csSendStatusMsg(QString net, QString msg) { send(CS_SEND_STATUS_MSG, net, msg); } + inline void csSetTopic(QString net, QString buf, QString topic) { send(CS_SET_TOPIC, net, buf, topic); } + inline void csSetNicks(QString net, QString buf, QStringList nicks) { send(CS_SET_NICKS, net, buf, nicks); } signals: void gsPutGlobalData(QString, QVariant); - void gsUserInput(QString); + void gsUserInput(QString, QString, QString); void gsRequestConnect(QStringList networks); private: diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 3467e3ff..d83476c5 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,7 +1,8 @@ SET(gui_SRCS channelwidget.cpp mainwin.cpp serverlist.cpp identities.cpp coreconnectdlg.cpp guiproxy.cpp) SET(gui_HDRS ) SET(gui_MOCS channelwidget.h mainwin.h serverlist.h identities.h coreconnectdlg.h guiproxy.h) -SET(gui_UICS channelwidget.ui identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui nickeditdlg.ui serverlistdlg.ui servereditdlg.ui coreconnectdlg.ui) +SET(gui_UICS channelwidget.ui identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui + nickeditdlg.ui serverlistdlg.ui servereditdlg.ui coreconnectdlg.ui ircwidget.ui) QT4_WRAP_UI(_UIC ${gui_UICS}) QT4_WRAP_CPP(_MOC ${gui_MOCS}) diff --git a/gui/channelwidget.cpp b/gui/channelwidget.cpp index 70066dc8..f5024b23 100644 --- a/gui/channelwidget.cpp +++ b/gui/channelwidget.cpp @@ -24,43 +24,111 @@ #include #include -ChannelWidget::ChannelWidget(QWidget *parent) : QWidget(parent) { +ChannelWidget::ChannelWidget(QString netname, QString bufname, QWidget *parent) : QWidget(parent) { ui.setupUi(this); - //ui.inputEdit->grabKeyboard(); - -/* //ui.splitter-> - ui.textBrowser->setHtml("[17:21] --> Dante has joined #quassel (~hurz@p1af2242.dip.t-dialin.net)
" - "[17:21] --> Sput has joined #quassel (~Sput42@vincent.mindpool.net)
" - "[17:23] <Dante> Das sieht ja soweit schonmal Klasse aus!
" - "[17:23] <Sput> Find ich auch... schade dass es noch nix tut :p
" - "[17:24] <Dante> Das wird sich ja gottseidank bald ändern.
" - "[17:24] <Sput> Wollen wir's hoffen :D" - ); - ui.listWidget->addItem("@Dante"); - ui.listWidget->addItem("@Sput"); - */ - //connect(&core, SIGNAL(outputLine( const QString& )), ui.textBrowser, SLOT(insertPlainText(const QString &))); - //connect(ui.lineEdit, SIGNAL( - //connect(&core, SIGNAL(outputLine( const QString& )), this, SLOT(lineReceived(const QString &))); + _networkName = netname; + _bufferName = bufname; connect(ui.inputEdit, SIGNAL(returnPressed()), this, SLOT(enterPressed())); - //connect(this, SIGNAL(inputLine( const QString& )), &core, SLOT(inputLine( const QString& ))); + //ui.inputEdit->setFocus(); - connect(this, SIGNAL(inputLine(QString)), guiProxy, SLOT(gsUserInput(QString))); - connect(guiProxy, SIGNAL(csSendMessage(QString, QString, QString)), this, SLOT(msgReceived(QString, QString, QString))); - connect(guiProxy, SIGNAL(csSendStatusMsg(QString, QString)), this, SLOT(statusMsgReceived(QString, QString))); - ui.inputEdit->setFocus(); + // Define standard colors + stdCol = QColor("black"); + noticeCol = QColor("darkblue"); + serverCol = QColor("darkblue"); + errorCol = QColor("red"); + joinCol = QColor("green"); + quitCol = QColor("firebrick"); + partCol = QColor("firebrick"); + } void ChannelWidget::enterPressed() { - emit inputLine(ui.inputEdit->text()); + emit sendMessage(networkName(), bufferName(), ui.inputEdit->text()); ui.inputEdit->clear(); } -void ChannelWidget::msgReceived(QString net, QString chan, QString msg) { - ui.chatWidget->insertPlainText(QString("[%1:%2] %3\n").arg(net).arg(chan).arg(msg)); +void ChannelWidget::recvMessage(Message msg) { + QString s; + QColor c = stdCol; + switch(msg.type) { + case Message::Server: + c = serverCol; s = msg.msg; + break; + case Message::Error: + c = errorCol; s = msg.msg; + break; + default: + c = stdCol; s = QString("[%1] %2").arg(msg.sender).arg(msg.msg); + break; + } + ui.chatWidget->setTextColor(c); + ui.chatWidget->insertPlainText(QString("%1\n").arg(s)); ui.chatWidget->ensureCursorVisible(); } -void ChannelWidget::statusMsgReceived(QString net, QString msg) { - msgReceived(net, "STATUS", msg); +void ChannelWidget::recvStatusMsg(QString msg) { + ui.chatWidget->insertPlainText(QString("[STATUS] %1").arg(msg)); + ui.chatWidget->ensureCursorVisible(); +} + +void ChannelWidget::setTopic(QString topic) { + ui.topicEdit->setText(topic); +} + +void ChannelWidget::setNicks(QStringList nicks) { + + +} + +/**********************************************************************************************/ + + +IrcWidget::IrcWidget(QWidget *parent) : QWidget(parent) { + ui.setupUi(this); + ui.tabWidget->removeTab(0); + + connect(guiProxy, SIGNAL(csSendMessage(QString, QString, Message)), this, SLOT(recvMessage(QString, QString, Message))); + connect(guiProxy, SIGNAL(csSendStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString))); + connect(guiProxy, SIGNAL(csSetTopic(QString, QString, QString)), this, SLOT(setTopic(QString, QString, QString))); + connect(guiProxy, SIGNAL(csSetNicks(QString, QString, QStringList)), this, SLOT(setNicks(QString, QString, QStringList))); + connect(this, SIGNAL(sendMessage( QString, QString, QString )), guiProxy, SLOT(gsUserInput(QString, QString, QString))); +} + +ChannelWidget * IrcWidget::getBuffer(QString net, QString buf) { + QString key = net + buf; + if(!buffers.contains(key)) { + ChannelWidget *cw = new ChannelWidget(net, buf); + connect(cw, SIGNAL(sendMessage(QString, QString, QString)), this, SLOT(userInput(QString, QString, QString))); + ui.tabWidget->addTab(cw, net+buf); + ui.tabWidget->setCurrentWidget(cw); + //cw->setFocus(); + buffers[key] = cw; + } + return buffers[key]; +} + + +void IrcWidget::recvMessage(QString net, QString buf, Message msg) { + ChannelWidget *cw = getBuffer(net, buf); + cw->recvMessage(msg); +} + +void IrcWidget::recvStatusMsg(QString net, QString msg) { + recvMessage(net, "", QString("[STATUS] %1").arg(msg)); + } + +void IrcWidget::userInput(QString net, QString buf, QString msg) { + emit sendMessage(net, buf, msg); +} + +void IrcWidget::setTopic(QString net, QString buf, QString topic) { + ChannelWidget *cw = getBuffer(net, buf); + cw->setTopic(topic); +} + +void IrcWidget::setNicks(QString net, QString buf, QStringList nicks) { + ChannelWidget *cw = getBuffer(net, buf); + cw->setNicks(nicks); +} + diff --git a/gui/channelwidget.h b/gui/channelwidget.h index 853d8a93..7338ecdc 100644 --- a/gui/channelwidget.h +++ b/gui/channelwidget.h @@ -22,26 +22,62 @@ #define _CHANNELWIDGET_H_ #include "ui_channelwidget.h" +#include "ui_ircwidget.h" + +#include "message.h" class ChannelWidget : public QWidget { Q_OBJECT public: - ChannelWidget(QWidget *parent = 0); + ChannelWidget(QString netname, QString bufname, QWidget *parent = 0); + QString bufferName() { return _bufferName; } + QString networkName() { return _networkName; } signals: - void requestConnect(QString, quint16); - void inputLine(QString); + void sendMessage(QString, QString, QString); + + public slots: + void recvMessage(Message); + void recvStatusMsg(QString msg); + void setTopic(QString); + void setNicks(QStringList); private slots: void enterPressed(); - void msgReceived(QString, QString, QString); - void statusMsgReceived(QString net, QString msg); private: Ui::ChannelWidget ui; + QColor stdCol, errorCol, noticeCol, joinCol, quitCol, partCol, serverCol; + QString _networkName; + QString _bufferName; }; +/** Temporary widget for displaying a set of ChannelWidgets. */ +class IrcWidget : public QWidget { + Q_OBJECT + + public: + IrcWidget(QWidget *parent = 0); + + public slots: + void recvMessage(QString network, QString buffer, Message message); + void recvStatusMsg(QString network, QString message); + void setTopic(QString, QString, QString); + void setNicks(QString, QString, QStringList); + + signals: + void sendMessage(QString network, QString buffer, QString message); + + private slots: + void userInput(QString, QString, QString); + + private: + Ui::IrcWidget ui; + QHash buffers; + + ChannelWidget * getBuffer(QString net, QString buf); +}; #endif diff --git a/gui/channelwidget.ui b/gui/channelwidget.ui index 82fad189..ffea438a 100644 --- a/gui/channelwidget.ui +++ b/gui/channelwidget.ui @@ -1,6 +1,14 @@ ChannelWidget + + + 0 + 0 + 713 + 519 + + 3 @@ -37,7 +45,14 @@ 6 - + + + Qt::ClickFocus + + + true + + @@ -87,6 +102,11 @@ 0 + + + Monospace + + @@ -218,8 +238,12 @@ + inputEdit + ownNick + nickTree topicEdit chanSettingsButton + chatWidget diff --git a/gui/guiproxy.cpp b/gui/guiproxy.cpp index a6bd7070..e9da5b01 100644 --- a/gui/guiproxy.cpp +++ b/gui/guiproxy.cpp @@ -22,6 +22,7 @@ #include "guiproxy.h" #include "util.h" +#include "message.h" void GUIProxy::recv(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { //qDebug() << "[GUI] Received signal:" << sig <()); break; case CS_SEND_STATUS_MSG: emit csSendStatusMsg(arg1.toString(), arg2.toString()); break; + case CS_SET_TOPIC: emit csSetTopic(arg1.toString(), arg2.toString(), arg3.toString()); break; + case CS_SET_NICKS: emit csSetNicks(arg1.toString(), arg2.toString(), arg3.toStringList()); break; default: qWarning() << "Unknown signal in GUIProxy::recv: " << sig; } diff --git a/gui/guiproxy.h b/gui/guiproxy.h index 0c013791..df788d72 100644 --- a/gui/guiproxy.h +++ b/gui/guiproxy.h @@ -22,6 +22,7 @@ #define _GUIPROXY_H_ #include "proxy_common.h" +#include "message.h" #include #include @@ -39,18 +40,20 @@ class GUIProxy : public QObject { GUIProxy(); public slots: - inline void gsUserInput(QString s) { send(GS_USER_INPUT, s); } - inline void gsRequestConnect(QStringList networks) { send(GS_REQUEST_CONNECT, networks); } + inline void gsUserInput(QString net, QString buf, QString msg) { send(GS_USER_INPUT, net, buf, msg); } + inline void gsRequestConnect(QStringList networks) { send(GS_REQUEST_CONNECT, networks); } void connectToCore(QString host, quint16 port); void disconnectFromCore(); signals: void csCoreState(QVariant); - void csSendMessage(QString, QString, QString); + void csSendMessage(QString, QString, Message); void csSendStatusMsg(QString, QString); void csUpdateGlobalData(QString key, QVariant data); void csGlobalDataChanged(QString key); + void csSetTopic(QString, QString, QString); + void csSetNicks(QString, QString, QStringList); void coreConnected(); void coreDisconnected(); diff --git a/gui/ircwidget.ui b/gui/ircwidget.ui new file mode 100644 index 00000000..5ddc795a --- /dev/null +++ b/gui/ircwidget.ui @@ -0,0 +1,44 @@ + + IrcWidget + + + + 0 + 0 + 733 + 531 + + + + Form + + + + 9 + + + 6 + + + + + QTabWidget::South + + + QTabWidget::Rounded + + + 0 + + + + No connection + + + + + + + + + diff --git a/gui/mainwin.cpp b/gui/mainwin.cpp index 3faaf109..3fefe4d7 100644 --- a/gui/mainwin.cpp +++ b/gui/mainwin.cpp @@ -40,11 +40,8 @@ MainWin::MainWin() : QMainWindow() { move(s.value("MainWinPos", QPoint(50, 50)).toPoint()); s.endGroup(); - workspace = new QWorkspace(this); - setCentralWidget(workspace); - //ChannelWidget *cw = new ChannelWidget(this); - //workspace->addWindow(cw); - //setCentralWidget(cw); + //workspace = new QWorkspace(this); + //setCentralWidget(workspace); statusBar()->showMessage(tr("Waiting for core...")); setEnabled(false); show(); @@ -55,14 +52,12 @@ MainWin::MainWin() : QMainWindow() { setupMenus(); //identitiesAct = settingsMenu->addAction(QIcon(":/default/identity.png"), tr("&Identities..."), serverListDlg, SLOT(editIdentities())); //showServerList(); - ChannelWidget *cw = new ChannelWidget(this); - //setCentralWidget(cw); - workspace->addWindow(cw); - cw->showMaximized(); - //setEnabled(true); + IrcWidget *cw = new IrcWidget(this); + setCentralWidget(cw); + //workspace->addWindow(cw); + //cw->showMaximized(); statusBar()->showMessage(tr("Ready.")); - //QSystemTrayIcon *systray = new QSystemTrayIcon(QIcon(":/qirc-icon.png")); - //systray->showMessage("Quassel", "Started!"); + cw->setFocus(); } void MainWin::syncToCore() { diff --git a/main/global.cpp b/main/global.cpp index 7a47771b..25eba7ec 100644 --- a/main/global.cpp +++ b/main/global.cpp @@ -21,9 +21,9 @@ #include "global.h" #include "logger.h" #include "core.h" +#include "message.h" -#include -#include +#include #include extern void messageHandler(QtMsgType type, const char *msg); @@ -31,6 +31,7 @@ extern void messageHandler(QtMsgType type, const char *msg); Global::Global() { if(global) qFatal("Trying to instantiate more than one Global object!"); qInstallMsgHandler(messageHandler); + qRegisterMetaType("Message"); //initIconMap(); } diff --git a/main/proxy_common.h b/main/proxy_common.h index 53f24a9f..f7b55945 100644 --- a/main/proxy_common.h +++ b/main/proxy_common.h @@ -26,6 +26,7 @@ enum GUISignal { GS_CLIENT_INIT, GS_USER_INPUT, GS_REQUEST_CONNECT, GS_UPDATE_GL }; enum CoreSignal { CS_CORE_STATE, CS_SEND_MESSAGE, CS_SEND_STATUS_MSG, CS_UPDATE_GLOBAL_DATA, + CS_SET_TOPIC, CS_SET_NICKS, }; diff --git a/network/CMakeLists.txt b/network/CMakeLists.txt index 2a79cc86..20b0c908 100644 --- a/network/CMakeLists.txt +++ b/network/CMakeLists.txt @@ -1,5 +1,5 @@ -SET(network_SRCS server.cpp buffer.cpp) -SET(network_HDRS ) +SET(network_SRCS server.cpp buffer.cpp message.cpp) +SET(network_HDRS message.h) SET(network_MOCS server.h buffer.h) QT4_WRAP_CPP(_MOC ${network_MOCS}) diff --git a/network/buffer.cpp b/network/buffer.cpp index e204ef82..61cd6b3d 100644 --- a/network/buffer.cpp +++ b/network/buffer.cpp @@ -17,3 +17,13 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ + +#include "buffer.h" + +Buffer::Buffer(QString n) { + _name = n; + + + +} + diff --git a/network/buffer.h b/network/buffer.h index e937f729..cb77fff0 100644 --- a/network/buffer.h +++ b/network/buffer.h @@ -26,8 +26,23 @@ class Buffer : public QObject { Q_OBJECT + public: + Buffer(QString name); + QString name() { return _name; } + QString topic() { return _topic; } + public slots: + //void setNicks(QStringList nicks); + //void addNick(QString nick); + //void removeNick(QString nick); + + signals: + + private: + QString _name; + QString _topic; + QStringList nicks; }; diff --git a/network/message.cpp b/network/message.cpp index b2e6f880..37398225 100644 --- a/network/message.cpp +++ b/network/message.cpp @@ -18,99 +18,18 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -/* OBSOLETE CODE! */ - #include "message.h" -#include - -extern BuiltinCmd builtins[]; - -recvHandlerType Message::defaultRecvHandler; -sendHandlerType Message::defaultSendHandler; -QHash Message::cmdTypes; - -Message::Message(Server *srv, Buffer *buf, QString _cmd, QString _prefix, QStringList _params) - : server(srv), buffer(buf), cmd(_cmd), prefix(_prefix), params(_params) { - - // Check if it's a registered cmd (or a numeric reply with a custom entry) - if(cmdTypes.contains(cmd)) { - CmdType c = cmdTypes[cmd]; - recvHandler = ( c.recvHandler ? c.recvHandler : defaultRecvHandler); - sendHandler = ( c.sendHandler ? c.sendHandler : defaultSendHandler); - cmdCode = - c.cmdCode; // named commands have a _negative_ code! - } else { - int t = cmd.toInt(); - if(t) { - cmdCode = t; - recvHandler = defaultRecvHandler; - sendHandler = defaultSendHandler; - } else { - // Unknown cmd! - qWarning() << "Unknown command: " << cmd; - cmdCode = 0; - } - } -} - -void Message::init(recvHandlerType _r, sendHandlerType _s) { - defaultRecvHandler = _r; - defaultSendHandler = _s; - - // Register builtin commands - for(int i = 0; ; i++) { - if(builtins[i].cmd.isEmpty()) break; - CmdType c; - c.cmdCode = builtins[i].cmdCode; - c.cmd = builtins[i].cmd.toUpper(); - c.cmdDescr = builtins[i].cmdDescr; - c.args = builtins[i].args; - c.argsDescr = builtins[i].argsDescr; - c.recvHandler = ( builtins[i].recvHandler ? builtins[i].recvHandler : defaultRecvHandler); - c.sendHandler = ( builtins[i].sendHandler ? builtins[i].sendHandler : defaultSendHandler); - cmdTypes.insert(c.cmd, c); - } - -} - -recvHandlerType Message::getRecvHandler() { - CmdType c = cmdTypes[cmd]; - if(c.recvHandler) return c.recvHandler; - qDebug() << "No recvHandler defined for " << cmd << "!"; - return 0; -} +#include -sendHandlerType Message::getSendHandler() { - CmdType c = cmdTypes[cmd]; - if(c.sendHandler) return c.sendHandler; - qDebug() << "No sendHandler defined for " << cmd << "!"; - return 0; +QDataStream &operator<<(QDataStream &out, const Message &msg) { + out << (quint8)msg.type << (quint8)msg.flags << msg.sender << msg.msg; + return out; } -/** This parses a raw string as sent by the server and constructs a message object which is then returned. - */ -Message * Message::createFromServerString(Server *srv, QString msg) { - if(msg.isEmpty()) { - qWarning() << "Received empty message from server!"; - return 0; - } - QString prefix; - QString cmd; - QStringList params; - if(msg[0] == ':') { - msg.remove(0,1); - prefix = msg.section(' ', 0, 0); - msg = msg.section(' ', 1); - } - cmd = msg.section(' ', 0, 0).toUpper(); - msg = msg.section(' ', 1); - QString left = msg.section(':', 0, 0); - QString trailing = msg.section(':', 1); - if(!left.isEmpty()) { - params << left.split(' ', QString::SkipEmptyParts); - } - if(!trailing.isEmpty()) { - params << trailing; - } - return new Message(srv, 0, cmd, prefix, params); - //qDebug() << "prefix: " << prefix << " cmd: " << cmd << " params: " << params; +QDataStream &operator>>(QDataStream &in, Message &msg) { + quint8 t, f; + in >> t >> f >> msg.sender >> msg.msg; + msg.type = (Message::Type)t; + msg.flags = (Message::Flags)f; + return in; } diff --git a/network/message.h b/network/message.h index 83c24b3b..c9f55a4e 100644 --- a/network/message.h +++ b/network/message.h @@ -21,84 +21,24 @@ #ifndef _MESSAGE_H_ #define _MESSAGE_H_ -#include -#include -#include +#include -class Server; -class Buffer; -class Message; +struct Message { -typedef void (*sendHandlerType)(Message *); // handler for commands sent by the user -typedef void (*recvHandlerType)(Message *); // handler for incoming messages + /** The different types a message can have for display */ + enum Type { Msg, Notice, Action, Nick, Mode, Join, Part, Quit, Kick, Kill, Server, Info, Error }; + enum Flags { None = 0, Self = 1, Highlight = 2 }; -/** - * This contains information that depends (solely) on the message type, such as the handler function and help texts. - * Most of these are defined at compile time, but more may be added at runtime. - */ -struct CmdType { - int cmdCode; - QString cmd; - QString cmdDescr; - QString args; - QString argsDescr; - recvHandlerType recvHandler; - sendHandlerType sendHandler; + Type type; + Flags flags; + QString sender; + QString msg; -}; - -/** - * -*/ -class Message { - public: - Message(Server *server, Buffer *buffer, QString cmd, QString prefix, QStringList args = QStringList()); - - virtual ~Message() {}; - - static void init(recvHandlerType defaultRevcHandler, sendHandlerType defaultSendHandler); - static Message * createFromServerString(Server *server, QString srvMsg); - //static Message * createFromUserString(Server *server, Buffer *buffer, QString usrMsg); - //static registerCmd(); - //static unregisterCmd(); + Message(QString _msg = "", QString _sender = "", Type _type = Msg, Flags _flags = None) + : msg(_msg), sender(_sender), type(_type), flags(_flags) {}; - inline Server * getServer() { return server; } - inline Buffer * getBuffer() { return buffer; } - inline int getCmdCode() { return cmdCode; } - inline QString getPrefix() { return prefix; } - inline QString getCmd() { return cmd; } - inline QStringList getParams() { return params; } - inline recvHandlerType getRecvHandler(); - inline sendHandlerType getSendHandler(); - - protected: - Server *server; - Buffer *buffer; - int cmdCode; - QString prefix; - QString cmd; - QStringList params; - recvHandlerType recvHandler; - sendHandlerType sendHandler; - static recvHandlerType defaultRecvHandler; - static sendHandlerType defaultSendHandler; - - static QHash cmdTypes; }; - -/** This is only used to have a nice way for defining builtin commands. - * We create an array of these in builtin_cmds.cpp and read this to fill our - * command hash. - */ -struct BuiltinCmd { - int cmdCode; - QString cmd; - QString cmdDescr; - QString args; - QString argsDescr; - recvHandlerType recvHandler; - sendHandlerType sendHandler; -}; +Q_DECLARE_METATYPE(Message) #endif diff --git a/network/server.cpp b/network/server.cpp index 4d00c2c1..d9e0a5b9 100644 --- a/network/server.cpp +++ b/network/server.cpp @@ -21,6 +21,7 @@ #include "global.h" #include "server.h" #include "cmdcodes.h" +#include "message.h" #include @@ -60,7 +61,7 @@ void Server::disconnectFromIrc(QString net) { void Server::socketHasData() { while(socket.canReadLine()) { QString s = socket.readLine().trimmed(); - //qDebug() << "Read: " << s; + qDebug() << "Read: " << s; emit recvRawServerMsg(s); //Message *msg = Message::createFromServerString(this, s); handleServerMsg(s); @@ -68,7 +69,7 @@ void Server::socketHasData() { } void Server::socketError( QAbstractSocket::SocketError err ) { - qDebug() << "Socket Error!"; + //qDebug() << "Socket Error!"; //emit error(err); } @@ -79,16 +80,22 @@ void Server::socketConnected( ) { } void Server::socketDisconnected( ) { - qDebug() << "Socket disconnected!"; - //emit disconnected(); + //qDebug() << "Socket disconnected!"; + emit disconnected(); } void Server::socketStateChanged(QAbstractSocket::SocketState state) { - qDebug() << "Socket state changed: " << state; + //qDebug() << "Socket state changed: " << state; } void Server::userInput(QString net, QString buf, QString msg) { - putRawLine(msg); + if(net != network) return; // not me! + msg = msg.trimmed(); // remove whitespace from start and end + if(msg.isEmpty()) return; + if(!msg.startsWith('/')) { + msg = QString("/SAY ") + msg; + } + handleUserMsg(buf, msg); } void Server::putRawLine(QString s) { @@ -139,39 +146,144 @@ void Server::handleServerMsg(QString msg) { // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-) QString hname = cmd.toLower(); hname[0] = hname[0].toUpper(); - hname = "handle" + hname + "FromServer"; + hname = "handleServer" + hname; if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, prefix), Q_ARG(QStringList, params))) { // Ok. Default handler it is. - defaultHandlerForServer(cmd, prefix, params); + defaultServerHandler(cmd, prefix, params); } } catch(Exception e) { - emit sendStatusMsg(e.msg()); + emit sendMessage("", Message(e.msg(), "", Message::Error)); } } -void Server::defaultHandlerForServer(QString cmd, QString prefix, QStringList params) { +void Server::defaultServerHandler(QString cmd, QString prefix, QStringList params) { uint num = cmd.toUInt(); if(num) { - emit sendMessage("", cmd + " " + params.join(" ")); + if(params.count() > 0) { + if(params[0] == currentNick) params.removeFirst(); // remove nick if it is first arg + else qWarning((QString("First param NOT nick: %1:%2 %3").arg(prefix).arg(cmd).arg(params.join(" "))).toAscii()); + } + // A lot of server messages don't really need their own handler because they don't do much. + // Catch and handle these here. + switch(num) { + // Welcome, status, info messages. Just display these. + case 2: case 3: case 4: case 5: case 251: case 252: case 253: case 254: case 255: case 372: case 375: + emit sendMessage("", Message(params.join(" "), prefix, Message::Server)); + break; + // Ignore these commands. + case 376: + break; + + // Everything else will be marked in red, so we can add them somewhere. + default: + emit sendMessage("", Message(cmd + " " + params.join(" "), prefix, Message::Error)); + } + //qDebug() << prefix <<":"<name() << msg; + putCmd("PRIVMSG", params); } -void Server::handleNoticeFromServer(QString prefix, QStringList params) { - sendMessage("", params.join(" ")); +/**********************************************************************************/ +void Server::handleServerJoin(QString prefix, QStringList params) { + Q_ASSERT(params.count() == 1); + QString bufname = params[0]; + if(!buffers.contains(bufname)) { + Buffer *buf = new Buffer(bufname); + buffers[bufname] = buf; + } + // handle user joins! +} +void Server::handleServerNotice(QString prefix, QStringList params) { + Message msg(params[1], prefix, Message::Notice); + if(prefix == currentServer) emit sendMessage("", Message(params[1], prefix, Message::Server)); + else emit sendMessage("", Message(params[1], prefix, Message::Notice)); } -void Server::handlePingFromServer(QString prefix, QStringList params) { +void Server::handleServerPing(QString prefix, QStringList params) { putCmd("PONG", params); } +void Server::handleServerPrivmsg(QString prefix, QStringList params) { + emit sendMessage(params[0], Message(params[1], prefix, Message::Msg)); + +} + +/* RPL_WELCOME */ +void Server::handleServer001(QString prefix, QStringList params) { + currentServer = prefix; + currentNick = params[0]; + emit sendMessage("", Message(params[1], prefix, Message::Server)); +} + +/* RPL_NOTOPIC */ +void Server::handleServer331(QString prefix, QStringList params) { + if(params[0] == currentNick) params.removeFirst(); + emit setTopic(network, params[0], ""); +} + +/* RPL_TOPIC */ +void Server::handleServer332(QString prefix, QStringList params) { + if(params[0] == currentNick) params.removeFirst(); + emit setTopic(network, params[0], params[1]); +} + +/***********************************************************************************/ + /* Exception classes for message handling */ Server::ParseError::ParseError(QString cmd, QString prefix, QStringList params) { _msg = QString("Command Parse Error: ") + cmd + params.join(" "); diff --git a/network/server.h b/network/server.h index dff974bb..6fde53f8 100644 --- a/network/server.h +++ b/network/server.h @@ -27,12 +27,12 @@ #include "global.h" #include "buffer.h" +#include "message.h" #define DEFAULT_PORT 6667 -/*! \file */ -/*! \class Server +/*! * This is a server object, managing a single connection to an IRC server, handling the associated channels and so on. * We have this running in its own thread mainly to not block other server objects or the core if something goes wrong, * e.g. if some scripts starts running wild... @@ -63,9 +63,13 @@ class Server : public QThread { signals: void recvRawServerMsg(QString); void sendStatusMsg(QString); - void sendMessage(QString buffer, QString msg); + void sendMessage(QString buffer, Message msg); void disconnected(); + void setTopic(QString network, QString buffer, QString topic); + void setNicks(QString network, QString buffer, QStringList nicks); + + private slots: void run(); void socketHasData(); @@ -75,19 +79,36 @@ class Server : public QThread { void socketStateChanged(QAbstractSocket::SocketState); /* Message Handlers */ - /* handleXxxxFromServer(QString prefix, QStringList params); */ - void handleNoticeFromServer(QString, QStringList); - void handlePingFromServer(QString, QStringList); - void defaultHandlerForServer(QString cmd, QString prefix, QStringList params); + /* handleUser(QString, Buffer *) */ + void handleUserJoin(QString, Buffer *); + void handleUserQuote(QString, Buffer *); + void handleUserSay(QString, Buffer *); + + + /* handleServer(QString, QStringList); */ + void handleServerJoin(QString, QStringList); + void handleServerNotice(QString, QStringList); + void handleServerPing(QString, QStringList); + void handleServerPrivmsg(QString, QStringList); + + void handleServer001(QString, QStringList); // RPL_WELCOME + void handleServer331(QString, QStringList); // RPL_NOTOPIC + void handleServer332(QString, QStringList); // RPL_TOPIC + + void defaultServerHandler(QString cmd, QString prefix, QStringList params); + void defaultUserHandler(QString cmd, QString msg, Buffer *buf); private: QString network; QTcpSocket socket; QHash buffers; + QString currentNick; + QString currentServer; + void handleServerMsg(QString rawMsg); - void handleUserMsg(QString usrMsg); + void handleUserMsg(QString buffer, QString usrMsg); class ParseError : public Exception { public: -- 2.20.1