From 902c95728306e5ba115de84800fc8d5d239c9d62 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Thu, 18 Oct 2007 13:58:04 +0000 Subject: [PATCH] Ok this is the major rework of quassel we've all been waiting for. For the actual user it's a step back though (at least for the moment). With this update the topicline, and the nicklist will not be working anymore. Major changes: - core/server.cpp has been disected into seperate handlers which all derive from core/basichandler - the switch from networknames to networkids has been done where possible (connection to irc is still missing since this is undergoing a separate redesign) - there are now objects providing information about networks, ircusers and channels. they are avaialbe in the core and in the client - BufferId has been renamed to BufferInfo since it's no longer an Identifier. (the actual identifier is BufferInfo.uid()) --- src/client/CMakeLists.txt | 2 +- src/client/buffer.cpp | 138 +++--- src/client/buffer.h | 150 +++--- src/client/buffertreemodel.cpp | 20 +- src/client/buffertreemodel.h | 5 +- src/client/client.cpp | 477 +++++++++--------- src/client/client.h | 235 ++++----- src/client/quasselui.h | 2 +- src/common/CMakeLists.txt | 4 +- src/common/bufferinfo.cpp | 68 +++ src/common/bufferinfo.h | 62 +++ src/common/common.pri | 4 +- src/common/global.cpp | 41 -- src/common/global.h | 34 -- src/common/ircchannel.cpp | 202 ++++++++ src/common/ircchannel.h | 102 ++++ src/common/ircuser.cpp | 175 ++++--- src/common/ircuser.h | 113 +++-- src/common/main.cpp | 4 +- src/common/message.cpp | 10 +- src/common/message.h | 9 +- src/common/networkinfo.cpp | 376 ++++++++++++++ src/common/networkinfo.h | 151 ++++++ src/common/signalproxy.h | 1 + src/common/synchronizer.cpp | 343 +++++++++++++ src/common/synchronizer.h | 79 +++ src/core/CMakeLists.txt | 4 +- src/core/basichandler.cpp | 77 +++ src/core/basichandler.h | 61 +++ src/core/core.cpp | 11 +- src/core/core.pri | 4 +- src/core/coresession.cpp | 141 +++--- src/core/coresession.h | 116 ++--- src/core/ctcphandler.cpp | 155 ++++++ src/core/ctcphandler.h | 62 +++ src/core/ircserverhandler.cpp | 428 ++++++++++++++++ src/core/ircserverhandler.h | 60 +++ src/core/server.cpp | 861 ++------------------------------- src/core/server.h | 225 ++++----- src/core/serverinfo.cpp | 112 ----- src/core/serverinfo.h | 84 ---- src/core/sqlitestorage.cpp | 44 +- src/core/sqlitestorage.h | 15 +- src/core/storage.cpp | 8 +- src/core/storage.h | 22 +- src/core/userinputhandler.cpp | 183 +++++++ src/core/userinputhandler.h | 62 +++ src/qtgui/bufferviewfilter.cpp | 10 +- src/qtgui/chatline.cpp | 2 +- src/qtgui/chatline.h | 2 +- src/qtgui/mainwin.cpp | 36 +- src/qtgui/mainwin.h | 4 +- src/qtgui/qtgui.pri | 6 +- src/qtgui/topicwidget.cpp | 33 ++ src/qtgui/topicwidget.h | 41 ++ src/qtgui/ui/topicwidget.ui | 60 +++ src/qtopia/chatline.cpp | 4 +- src/qtopia/chatline.h | 4 +- src/qtopia/qtopiamainwin.cpp | 12 +- src/qtopia/qtopiamainwin.h | 2 +- 60 files changed, 3731 insertions(+), 2027 deletions(-) create mode 100644 src/common/bufferinfo.cpp create mode 100644 src/common/bufferinfo.h create mode 100644 src/common/ircchannel.cpp create mode 100644 src/common/ircchannel.h create mode 100644 src/common/networkinfo.cpp create mode 100644 src/common/networkinfo.h create mode 100644 src/common/synchronizer.cpp create mode 100644 src/common/synchronizer.h create mode 100644 src/core/basichandler.cpp create mode 100644 src/core/basichandler.h create mode 100644 src/core/ctcphandler.cpp create mode 100644 src/core/ctcphandler.h create mode 100644 src/core/ircserverhandler.cpp create mode 100644 src/core/ircserverhandler.h delete mode 100644 src/core/serverinfo.cpp delete mode 100644 src/core/serverinfo.h create mode 100644 src/core/userinputhandler.cpp create mode 100644 src/core/userinputhandler.h create mode 100644 src/qtgui/topicwidget.cpp create mode 100644 src/qtgui/topicwidget.h create mode 100644 src/qtgui/ui/topicwidget.ui diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 3ad8f7dd..7746c0f5 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -5,4 +5,4 @@ SET(client_MOCS buffer.h buffertreemodel.h client.h clientsettings.h quasselui.h QT4_WRAP_CPP(_MOC ${client_MOCS}) ADD_LIBRARY(client ${client_SRCS} ${_MOC}) -TARGET_LINK_LIBRARIES(client common) \ No newline at end of file +TARGET_LINK_LIBRARIES(client common) diff --git a/src/client/buffer.cpp b/src/client/buffer.cpp index 917d71a2..1fb07971 100644 --- a/src/client/buffer.cpp +++ b/src/client/buffer.cpp @@ -23,16 +23,18 @@ #include "util.h" -Buffer::Buffer(BufferId bufid) { - id = bufid; - _networkName = bufid.network(); - _bufferName = bufid.buffer(); - - if(_bufferName.isEmpty()) type = ServerBuffer; - else if(isChannelName(_bufferName)) type = ChannelBuffer; - else type = QueryBuffer; +Buffer::Buffer(BufferInfo bufferid, QObject *parent) + : QObject(parent), + _bufferInfo(bufferid), + _active(false) +{ + if(bufferid.buffer().isEmpty()) + _type = ServerBuffer; + else if(isChannelName(bufferid.buffer())) + _type = ChannelBuffer; + else + _type = QueryBuffer; - active = false; /* QSettings s; s.beginGroup(QString("GUI/BufferStates/%1/%2").arg(netname).arg(bufname)); @@ -55,19 +57,32 @@ Buffer::~Buffer() { } Buffer::Type Buffer::bufferType() const { - return type; + return _type; } bool Buffer::isActive() const { - return active; + // FIXME determine status by checking for a networkInfo objekt + return true; +} + +BufferInfo Buffer::bufferInfo() const { + return _bufferInfo; +} + +void Buffer::updateBufferInfo(BufferInfo bufferid) { + _bufferInfo = bufferid; +} + +uint Buffer::networkId() const { + return bufferInfo().networkId(); } QString Buffer::networkName() const { - return _networkName; + return bufferInfo().network(); } QString Buffer::bufferName() const { - return _bufferName; + return bufferInfo().buffer(); } QString Buffer::displayName() const { @@ -77,24 +92,23 @@ QString Buffer::displayName() const { return bufferName(); } -BufferId Buffer::bufferId() const { - return id; -} - QList Buffer::contents() const { - return layoutedMsgs; + return layoutedMsgs; } QVariantMap Buffer::nickList() const { - return nicks; + // FIXME should return a Map or List of IrcUsers in the future + return QVariantMap(); } QString Buffer::topic() const { - return _topic; + // FIXME check if we got a networkInfo() object + return QString(); } QString Buffer::ownNick() const { - return _ownNick; + // FIXME check if we got a networkInfo() object + return QString(); } bool Buffer::isStatusBuffer() const { @@ -102,10 +116,10 @@ bool Buffer::isStatusBuffer() const { } void Buffer::setActive(bool a) { - if(a != active) { - active = a; - emit bufferUpdated(this); - } +// if(a != active) { +// active = a; +// emit bufferUpdated(this); +// } } void Buffer::appendMsg(const Message &msg) { @@ -129,39 +143,41 @@ bool Buffer::layoutMsg() { void Buffer::processUserInput(QString msg) { // TODO User Input processing (plugins) -> well, this goes through MainWin into Core for processing... so... - emit userInput(id, msg); -} - -void Buffer::setTopic(QString t) { - _topic = t; - emit topicSet(t); - emit bufferUpdated(this); -} - -void Buffer::addNick(QString nick, QVariantMap props) { - if(nick == ownNick()) setActive(true); - nicks[nick] = props; - emit nickListChanged(nicks); -} - -void Buffer::updateNick(QString nick, QVariantMap props) { - nicks[nick] = props; - emit nickListChanged(nicks); -} - -void Buffer::renameNick(QString oldnick, QString newnick) { - QVariant v = nicks.take(oldnick); - nicks[newnick] = v; - emit nickListChanged(nicks); -} - -void Buffer::removeNick(QString nick) { - if(nick == ownNick()) setActive(false); - nicks.remove(nick); - emit nickListChanged(nicks); -} - -void Buffer::setOwnNick(QString nick) { - _ownNick = nick; - emit ownNickSet(nick); -} + emit userInput(_bufferInfo, msg); +} + +// no longer needed +// back reference: +// void Buffer::setTopic(QString t) { +// _topic = t; +// emit topicSet(t); +// emit bufferUpdated(this); +// } + +// void Buffer::addNick(QString nick, QVariantMap props) { +// if(nick == ownNick()) setActive(true); +// nicks[nick] = props; +// emit nickListChanged(nicks); +// } + +// void Buffer::updateNick(QString nick, QVariantMap props) { +// nicks[nick] = props; +// emit nickListChanged(nicks); +// } + +// void Buffer::renameNick(QString oldnick, QString newnick) { +// QVariant v = nicks.take(oldnick); +// nicks[newnick] = v; +// emit nickListChanged(nicks); +// } + +// void Buffer::removeNick(QString nick) { +// if(nick == ownNick()) setActive(false); +// nicks.remove(nick); +// emit nickListChanged(nicks); +// } + +// void Buffer::setOwnNick(QString nick) { +// _ownNick = nick; +// emit ownNickSet(nick); +// } diff --git a/src/client/buffer.h b/src/client/buffer.h index 68de96a8..3465e5f2 100644 --- a/src/client/buffer.h +++ b/src/client/buffer.h @@ -21,85 +21,95 @@ #ifndef _BUFFER_H_ #define _BUFFER_H_ -#include "global.h" - class AbstractUiMsg; -class Message; + struct BufferState; +#include "message.h" +#include "bufferinfo.h" + +#include + //!\brief Encapsulates the contents of a single channel, query or server status context. /** A Buffer maintains a list of existing nicks and their status. */ class Buffer : public QObject { Q_OBJECT - public: - Buffer(BufferId); - ~Buffer(); - - enum Type { ServerBuffer, ChannelBuffer, QueryBuffer }; - - enum Activity { - NoActivity = 0x00, - OtherActivity = 0x01, - NewMessage = 0x02, - Highlight = 0x40 - }; - Q_DECLARE_FLAGS(ActivityLevel, Activity); - - Type bufferType() const; - bool isActive() const; - - QString networkName() const; - QString bufferName() const; - QString displayName() const; - BufferId bufferId() const; - QList contents() const; - QVariantMap nickList() const; - QString topic() const; - QString ownNick() const; - bool isStatusBuffer() const; - - signals: - void userInput(const BufferId &, QString); - void nickListChanged(QVariantMap nicks); - void topicSet(QString topic); - void ownNickSet(QString ownNick); - void bufferUpdated(Buffer *); - void bufferDestroyed(Buffer *); - - void msgAppended(AbstractUiMsg *); - void msgPrepended(AbstractUiMsg *); - void layoutQueueEmpty(); - - public slots: - void setActive(bool active = true); - void appendMsg(const Message &); - void prependMsg(const Message &); - bool layoutMsg(); - void setTopic(QString); - //void setNicks(QStringList); - void addNick(QString nick, QVariantMap props); - void renameNick(QString oldnick, QString newnick); - void removeNick(QString nick); - void updateNick(QString nick, QVariantMap props); - void setOwnNick(QString nick); - - void processUserInput(QString); - - private: - BufferId id; - bool active; - Type type; - - QVariantMap nicks; - QString _topic; - QString _ownNick; - QString _networkName, _bufferName; - BufferState *state; - - QList layoutQueue; - QList layoutedMsgs; +public: + Buffer(BufferInfo, QObject *parent = 0); + ~Buffer(); + + enum Type { + ServerBuffer, + ChannelBuffer, + QueryBuffer + }; + + enum Activity { + NoActivity = 0x00, + OtherActivity = 0x01, + NewMessage = 0x02, + Highlight = 0x40 + }; + Q_DECLARE_FLAGS(ActivityLevel, Activity) + + bool isStatusBuffer() const; + Type bufferType() const; + bool isActive() const; + + BufferInfo bufferInfo() const; + void updateBufferInfo(BufferInfo bufferid); + + uint networkId() const; + + QString networkName() const; + QString bufferName() const; + QString displayName() const; + + QList contents() const; + + QVariantMap nickList() const; + QString topic() const; + QString ownNick() const; + +signals: + void userInput(const BufferInfo &, QString); + void nickListChanged(QVariantMap nicks); + void topicSet(QString topic); + void ownNickSet(QString ownNick); + void bufferUpdated(Buffer *); + void bufferDestroyed(Buffer *); + + void msgAppended(AbstractUiMsg *); + void msgPrepended(AbstractUiMsg *); + void layoutQueueEmpty(); + +public slots: + void setActive(bool active = true); + void appendMsg(const Message &); + void prependMsg(const Message &); + bool layoutMsg(); + + // no longer needed +// void setTopic(QString); +// //void setNicks(QStringList); +// void addNick(QString nick, QVariantMap props); +// void renameNick(QString oldnick, QString newnick); +// void removeNick(QString nick); +// void updateNick(QString nick, QVariantMap props); +// void setOwnNick(QString nick); + + void processUserInput(QString); + +private: + BufferInfo _bufferInfo; + bool _active; + Type _type; + BufferState *state; + + QList layoutQueue; + QList layoutedMsgs; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Buffer::ActivityLevel) diff --git a/src/client/buffertreemodel.cpp b/src/client/buffertreemodel.cpp index b93f8584..fc9ea519 100644 --- a/src/client/buffertreemodel.cpp +++ b/src/client/buffertreemodel.cpp @@ -20,8 +20,10 @@ #include // FIXME Dependency on QtGui! -#include "client.h" #include "buffertreemodel.h" + +#include "bufferinfo.h" +#include "client.h" #include "signalproxy.h" /***************************************** @@ -33,7 +35,7 @@ BufferTreeItem::BufferTreeItem(Buffer *buffer, TreeItem *parent) : TreeItem(pare } uint BufferTreeItem::id() const { - return buf->bufferId().uid(); + return buf->bufferInfo().uid(); } void BufferTreeItem::setActivity(const Buffer::ActivityLevel &level) { @@ -80,8 +82,8 @@ QVariant BufferTreeItem::data(int column, int role) const { return buf->bufferType(); case BufferTreeModel::BufferActiveRole: return buf->isActive(); - case BufferTreeModel::BufferIdRole: - return buf->bufferId().uid(); + case BufferTreeModel::BufferInfoRole: + return buf->bufferInfo().uid(); default: return QVariant(); } @@ -117,7 +119,7 @@ Qt::ItemFlags NetworkTreeItem::flags() const { BufferTreeModel::BufferTreeModel(QObject *parent) : TreeModel(BufferTreeModel::defaultHeader(), parent) { - Client::signalProxy()->attachSignal(this, SIGNAL(fakeUserInput(BufferId, QString)), SIGNAL(sendInput(BufferId, QString))); + Client::signalProxy()->attachSignal(this, SIGNAL(fakeUserInput(BufferInfo, QString)), SIGNAL(sendInput(BufferInfo, QString))); } QListBufferTreeModel::defaultHeader() { @@ -158,7 +160,7 @@ QModelIndex BufferTreeModel::getOrCreateBufferItemIndex(Buffer *buffer) { NetworkTreeItem *networkItem = static_cast(networkItemIndex.internalPointer()); TreeItem *bufferItem; - if(not(bufferItem = networkItem->childById(buffer->bufferId().uid()))) { + if(not(bufferItem = networkItem->childById(buffer->bufferInfo().uid()))) { int nextRow = networkItem->childCount(); bufferItem = new BufferTreeItem(buffer, networkItem); @@ -175,7 +177,7 @@ QStringList BufferTreeModel::mimeTypes() const { QStringList types; types << "application/Quassel/BufferItem/row" << "application/Quassel/BufferItem/network" - << "application/Quassel/BufferItem/bufferId"; + << "application/Quassel/BufferItem/bufferInfo"; return types; } @@ -186,7 +188,7 @@ QMimeData *BufferTreeModel::mimeData(const QModelIndexList &indexes) const { mimeData->setData("application/Quassel/BufferItem/row", QByteArray::number(index.row())); mimeData->setData("application/Quassel/BufferItem/network", getBufferByIndex(index)->networkName().toUtf8()); - mimeData->setData("application/Quassel/BufferItem/bufferId", QByteArray::number(getBufferByIndex(index)->bufferId().uid())); + mimeData->setData("application/Quassel/BufferItem/bufferInfo", QByteArray::number(getBufferByIndex(index)->bufferInfo().uid())); return mimeData; } @@ -241,7 +243,7 @@ void BufferTreeModel::doubleClickReceived(const QModelIndex &clicked) { if(isBufferIndex(clicked)) { Buffer *buffer = getBufferByIndex(clicked); if(!buffer->isStatusBuffer()) - emit fakeUserInput(buffer->bufferId(), QString("/join " + buffer->bufferName())); + emit fakeUserInput(buffer->bufferInfo(), QString("/join " + buffer->bufferName())); } } diff --git a/src/client/buffertreemodel.h b/src/client/buffertreemodel.h index 2d170ece..7053ef75 100644 --- a/src/client/buffertreemodel.h +++ b/src/client/buffertreemodel.h @@ -24,6 +24,7 @@ #include #include "treemodel.h" +class BufferInfo; #include "buffer.h" /***************************************** @@ -78,7 +79,7 @@ public: BufferTypeRole = Qt::UserRole, BufferActiveRole, BufferNameRole, - BufferIdRole + BufferInfoRole }; BufferTreeModel(QObject *parent = 0); @@ -94,7 +95,7 @@ public slots: signals: void bufferSelected(Buffer *); void invalidateFilter(); - void fakeUserInput(BufferId, QString); + void fakeUserInput(BufferInfo, QString); void selectionChanged(const QModelIndex &); private: diff --git a/src/client/client.cpp b/src/client/client.cpp index b561fd12..55bf9c54 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -20,40 +20,32 @@ #include "client.h" -#include "buffer.h" +#include "networkinfo.h" +#include "ircuser.h" +#include "ircchannel.h" + +#include "message.h" + +#include "bufferinfo.h" #include "buffertreemodel.h" #include "quasselui.h" #include "signalproxy.h" +#include "synchronizer.h" #include "util.h" -Client * Client::instanceptr = 0; - -bool Client::connectedToCore = false; -Client::ClientMode Client::clientMode; -QVariantMap Client::coreConnectionInfo; -QHash Client::buffers; -QHash Client::bufferIds; -QHash > Client::nicks; -QHash Client::netConnected; -QStringList Client::netsAwaitingInit; -QHash Client::ownNick; +QPointer Client::instanceptr = 0; +// ============================== +// public Static Methods +// ============================== Client *Client::instance() { - if(instanceptr) return instanceptr; - instanceptr = new Client(); + if(!instanceptr) + instanceptr = new Client(); return instanceptr; } void Client::destroy() { delete instanceptr; - instanceptr = 0; -} - -Client::Client() { - _signalProxy = new SignalProxy(SignalProxy::Client, 0, this); - - connectedToCore = false; - socket = 0; } void Client::init(AbstractUi *ui) { @@ -61,33 +53,135 @@ void Client::init(AbstractUi *ui) { instance()->init(); } +QList Client::networkInfos() { + return instance()->_networkInfo.values(); +} + +NetworkInfo *Client::networkInfo(uint networkid) { + if(instance()->_networkInfo.contains(networkid)) + return instance()->_networkInfo[networkid]; + else + return 0; +} + +QList Client::allBufferInfos() { + QList bufferids; + foreach(Buffer *buffer, buffers()) { + bufferids << buffer->bufferInfo(); + } + return bufferids; +} + +QList Client::buffers() { + return instance()->_buffers.values(); +} + +Buffer *Client::buffer(uint bufferUid) { + if(instance()->_buffers.contains(bufferUid)) + return instance()->_buffers[bufferUid]; + else + return 0; +} + +Buffer *Client::buffer(BufferInfo id) { + Buffer *buff = buffer(id.uid()); + + if(!buff) { + Client *client = Client::instance(); + Buffer *buff = new Buffer(id, client); + + connect(buff, SIGNAL(userInput(BufferInfo, QString)), + client, SLOT(userInput(BufferInfo, QString))); + connect(buff, SIGNAL(bufferUpdated(Buffer *)), + client, SIGNAL(bufferUpdated(Buffer *))); + connect(buff, SIGNAL(bufferDestroyed(Buffer *)), + client, SIGNAL(bufferDestroyed(Buffer *))); + connect(buff, SIGNAL(bufferDestroyed(Buffer *)), + client, SLOT(removeBuffer(Buffer *))); + + client->_buffers[id.uid()] = buff; + emit client->bufferUpdated(buff); + } + + return buff; +} + +// FIXME switch to netids! +// WHEN IS THIS NEEDED ANYHOW!? +BufferInfo Client::bufferInfo(QString net, QString buf) { + foreach(Buffer *buffer_, buffers()) { + BufferInfo bufferInfo = buffer_->bufferInfo(); + if(bufferInfo.network() == net && bufferInfo.buffer() == buf) + return bufferInfo; + } + Q_ASSERT(false); // should never happen! + return BufferInfo(); +} + +BufferInfo Client::statusBufferInfo(QString net) { + return bufferInfo(net, ""); +} + +BufferTreeModel *Client::bufferModel() { + return instance()->_bufferModel; +} + +SignalProxy *Client::signalProxy() { + return instance()->_signalProxy; +} + +// ============================== +// Constructor / Decon +// ============================== +Client::Client(QObject *parent) + : QObject(parent), + socket(0), + _signalProxy(new SignalProxy(SignalProxy::Client, 0, this)), + mainUi(0), + _bufferModel(0), + connectedToCore(false) +{ +} + +Client::~Client() { +// since we're now the parent of buffers this should be no longer needed + +// foreach(Buffer *buf, buffers.values()) delete buf; // this is done by disconnectFromCore()! FIXME? +// Q_ASSERT(!buffers.count()); +} + void Client::init() { blockSize = 0; _bufferModel = new BufferTreeModel(this); - connect(this, SIGNAL(bufferSelected(Buffer *)), _bufferModel, SLOT(selectBuffer(Buffer *))); - connect(this, SIGNAL(bufferUpdated(Buffer *)), _bufferModel, SLOT(bufferUpdated(Buffer *))); - connect(this, SIGNAL(bufferActivity(Buffer::ActivityLevel, Buffer *)), _bufferModel, SLOT(bufferActivity(Buffer::ActivityLevel, Buffer *))); + connect(this, SIGNAL(bufferSelected(Buffer *)), + _bufferModel, SLOT(selectBuffer(Buffer *))); + connect(this, SIGNAL(bufferUpdated(Buffer *)), + _bufferModel, SLOT(bufferUpdated(Buffer *))); + connect(this, SIGNAL(bufferActivity(Buffer::ActivityLevel, Buffer *)), + _bufferModel, SLOT(bufferActivity(Buffer::ActivityLevel, Buffer *))); SignalProxy *p = signalProxy(); - p->attachSignal(this, SIGNAL(sendSessionData(const QString &, const QVariant &)), SIGNAL(clientSessionDataChanged(const QString &, const QVariant &))); - p->attachSlot(SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)), this, SLOT(recvSessionData(const QString &, const QVariant &))); - p->attachSlot(SIGNAL(coreState(const QVariant &)), this, SLOT(recvCoreState(const QVariant &))); - p->attachSlot(SIGNAL(networkState(QString, QVariant)), this, SLOT(recvNetworkState(QString, QVariant))); - p->attachSlot(SIGNAL(networkConnected(QString)), this, SLOT(networkConnected(QString))); - p->attachSlot(SIGNAL(networkDisconnected(QString)), this, SLOT(networkDisconnected(QString))); - p->attachSlot(SIGNAL(displayMsg(const Message &)), this, SLOT(recvMessage(const Message &))); - p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString))); - p->attachSlot(SIGNAL(topicSet(QString, QString, QString)), this, SLOT(setTopic(QString, QString, QString))); - p->attachSlot(SIGNAL(nickAdded(QString, QString, QVariantMap)), this, SLOT(addNick(QString, QString, QVariantMap))); - p->attachSlot(SIGNAL(nickRemoved(QString, QString)), this, SLOT(removeNick(QString, QString))); - p->attachSlot(SIGNAL(nickRenamed(QString, QString, QString)), this, SLOT(renameNick(QString, QString, QString))); - p->attachSlot(SIGNAL(nickUpdated(QString, QString, QVariantMap)), this, SLOT(updateNick(QString, QString, QVariantMap))); - p->attachSlot(SIGNAL(ownNickSet(QString, QString)), this, SLOT(setOwnNick(QString, QString))); - p->attachSlot(SIGNAL(backlogData(BufferId, const QVariantList &, bool)), this, SLOT(recvBacklogData(BufferId, const QVariantList &, bool))); - p->attachSlot(SIGNAL(bufferIdUpdated(BufferId)), this, SLOT(updateBufferId(BufferId))); - p->attachSignal(this, SIGNAL(sendInput(BufferId, QString))); + p->attachSignal(this, SIGNAL(sendSessionData(const QString &, const QVariant &)), + SIGNAL(clientSessionDataChanged(const QString &, const QVariant &))); + p->attachSlot(SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)), + this, SLOT(recvSessionData(const QString &, const QVariant &))); + p->attachSlot(SIGNAL(coreState(const QVariant &)), + this, SLOT(recvCoreState(const QVariant &))); + p->attachSlot(SIGNAL(networkConnected(uint)), + this, SLOT(networkConnected(uint))); + p->attachSlot(SIGNAL(networkDisconnected(uint)), + this, SLOT(networkDisconnected(uint))); + p->attachSlot(SIGNAL(displayMsg(const Message &)), + this, SLOT(recvMessage(const Message &))); + p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)), + this, SLOT(recvStatusMsg(QString, QString))); + + + p->attachSlot(SIGNAL(backlogData(BufferInfo, const QVariantList &, bool)), this, SLOT(recvBacklogData(BufferInfo, const QVariantList &, bool))); + p->attachSlot(SIGNAL(bufferInfoUpdated(BufferInfo)), this, SLOT(updateBufferInfo(BufferInfo))); + p->attachSignal(this, SIGNAL(sendInput(BufferInfo, QString))); p->attachSignal(this, SIGNAL(requestNetworkStates())); connect(mainUi, SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &))); @@ -99,33 +193,25 @@ void Client::init() { layoutTimer->setInterval(0); layoutTimer->setSingleShot(false); connect(layoutTimer, SIGNAL(timeout()), this, SLOT(layoutMsg())); -} - -Client::~Client() { - foreach(Buffer *buf, buffers.values()) delete buf; // this is done by disconnectFromCore()! FIXME? - Q_ASSERT(!buffers.count()); -} - -BufferTreeModel *Client::bufferModel() { - return instance()->_bufferModel; -} -SignalProxy *Client::signalProxy() { - return instance()->_signalProxy; } bool Client::isConnected() { - return connectedToCore; + return instance()->connectedToCore; } void Client::connectToCore(const QVariantMap &conn) { // TODO implement SSL coreConnectionInfo = conn; + if(isConnected()) { emit coreConnectionError(tr("Already connected to Core!")); return; } - if(socket != 0) socket->deleteLater(); + + if(socket != 0) + socket->deleteLater(); + if(conn["Host"].toString().isEmpty()) { clientMode = LocalCore; socket = new QBuffer(this); @@ -174,24 +260,26 @@ void Client::coreSocketConnected() { } void Client::coreSocketDisconnected() { - connectedToCore = false; + instance()->connectedToCore = false; emit disconnected(); socket->deleteLater(); blockSize = 0; /* Clear internal data. Hopefully nothing relies on it at this point. */ _bufferModel->clear(); - // Buffers, if deleted, send a signal that causes their removal from buffers and bufferIds. + // Buffers, if deleted, send a signal that causes their removal from buffers and bufferInfos. // So we cannot simply go through the array in a loop (or use qDeleteAll) for deletion... - while(buffers.count()) { delete buffers.take(buffers.keys()[0]); } - Q_ASSERT(!buffers.count()); // should be empty now! - Q_ASSERT(!bufferIds.count()); + while(!_buffers.empty()) { + delete _buffers.take(_buffers.keys()[0]); + } + Q_ASSERT(_buffers.empty()); + + while(!_networkInfo.empty()) { + delete _networkInfo.take(_networkInfo.keys()[0]); + } + coreConnectionInfo.clear(); sessionData.clear(); - nicks.clear(); - netConnected.clear(); - netsAwaitingInit.clear(); - ownNick.clear(); layoutQueue.clear(); layoutTimer->stop(); } @@ -214,30 +302,84 @@ void Client::syncToCore(const QVariant &coreState) { disconnectFromCore(); return; } + QVariantMap sessionState = coreState.toMap()["SessionState"].toMap(); - QVariantMap sessData = sessionState["SessionData"].toMap(); - foreach(QString key, sessData.keys()) { + // store sessionData + QVariantMap sessData = sessionState["SessionData"].toMap(); + foreach(QString key, sessData.keys()) recvSessionData(key, sessData[key]); - } - QList coreBuffers = sessionState["Buffers"].toList(); + + // store Buffer details + QVariantList coreBuffers = sessionState["Buffers"].toList(); /* make lookups by id faster */ foreach(QVariant vid, coreBuffers) { - BufferId id = vid.value(); - bufferIds[id.uid()] = id; // make lookups by id faster - buffer(id); // create all buffers, so we see them in the network views + buffer(vid.value()); // create all buffers, so we see them in the network views + } + + // create networkInfo objects + QVariantList networkids = sessionState["Networks"].toList(); + foreach(QVariant networkid, networkids) { + networkConnected(networkid.toUInt()); } - netsAwaitingInit = sessionState["Networks"].toStringList(); - connectedToCore = true; - if(netsAwaitingInit.count()) { + + instance()->connectedToCore = true; + updateCoreConnectionProgress(); +} + +void Client::updateCoreConnectionProgress() { + // we'll do this in three steps: + // 1.) networks + // 2.) channels + // 3.) ircusers + + int numNets = networkInfos().count(); + int numNetsWaiting = 0; + + int numIrcUsers = 0; + int numIrcUsersWaiting = 0; + + int numChannels = 0; + int numChannelsWaiting = 0; + + foreach(NetworkInfo *net, networkInfos()) { + if(not net->initialized()) + numNetsWaiting++; + + numIrcUsers += net->ircUsers().count(); + foreach(IrcUser *user, net->ircUsers()) { + if(not user->initialized()) + numIrcUsersWaiting++; + } + + numChannels += net->ircChannels().count(); + foreach(IrcChannel *channel, net->ircChannels()) { + if(not channel->initialized()) + numChannelsWaiting++; + } + + } + + if(numNetsWaiting > 0) { emit coreConnectionMsg(tr("Requesting network states...")); - emit coreConnectionProgress(0, netsAwaitingInit.count()); - emit requestNetworkStates(); + emit coreConnectionProgress(numNets - numNetsWaiting, numNets); + return; } - else { - emit coreConnectionProgress(1, 1); - emit connected(); + + if(numIrcUsersWaiting > 0) { + emit coreConnectionMsg(tr("Requesting User states...")); + emit coreConnectionProgress(numIrcUsers - numIrcUsersWaiting, numIrcUsers); + return; } + + if(numChannelsWaiting > 0) { + emit coreConnectionMsg(tr("Requesting Channel states...")); + emit coreConnectionProgress(numChannels - numChannelsWaiting, numChannels); + return; + } + + emit coreConnectionProgress(1,1); + emit connected(); } void Client::recvSessionData(const QString &key, const QVariant &data) { @@ -280,92 +422,42 @@ void Client::coreHasData() { } } -void Client::networkConnected(QString net) { - Q_ASSERT(!netsAwaitingInit.contains(net)); - netConnected[net] = true; - BufferId id = statusBufferId(net); - Buffer *b = buffer(id); - b->setActive(true); - //b->displayMsg(Message(id, Message::Server, tr("Connected."))); - // TODO buffersUpdated(); -} +void Client::networkConnected(uint netid) { + // TODO: create statusBuffer / switch to networkids + //BufferInfo id = statusBufferInfo(net); + //Buffer *b = buffer(id); + //b->setActive(true); -void Client::networkDisconnected(QString net) { - foreach(BufferId id, buffers.keys()) { - if(id.network() != net) continue; - Buffer *b = buffer(id); - //b->displayMsg(Message(id, Message::Server, tr("Server disconnected."))); FIXME - b->setActive(false); - } - netConnected[net] = false; - if(netsAwaitingInit.contains(net)) { - qDebug() << "Network" << net << "disconnected while not yet initialized!"; - netsAwaitingInit.removeAll(net); - emit coreConnectionProgress(netConnected.count(), netConnected.count() + netsAwaitingInit.count()); - if(!netsAwaitingInit.count()) emit connected(); - } + NetworkInfo *netinfo = new NetworkInfo(netid, signalProxy(), this); + connect(netinfo, SIGNAL(initDone()), this, SLOT(updateCoreConnectionProgress())); + connect(netinfo, SIGNAL(ircUserInitDone()), this, SLOT(updateCoreConnectionProgress())); + connect(netinfo, SIGNAL(ircChannelInitDone()), this, SLOT(updateCoreConnectionProgress())); + _networkInfo[netid] = netinfo; } -void Client::updateBufferId(BufferId id) { - bufferIds[id.uid()] = id; // make lookups by id faster - buffer(id); -} +void Client::networkDisconnected(uint networkid) { + foreach(Buffer *buffer, buffers()) { + if(buffer->bufferInfo().networkId() != networkid) + continue; -BufferId Client::bufferId(QString net, QString buf) { - foreach(BufferId id, buffers.keys()) { - if(id.network() == net && id.buffer() == buf) return id; + //buffer->displayMsg(Message(bufferid, Message::Server, tr("Server disconnected."))); FIXME + buffer->setActive(false); } - Q_ASSERT(false); // should never happen! - return BufferId(); -} - -BufferId Client::statusBufferId(QString net) { - return bufferId(net, ""); -} - - -Buffer * Client::buffer(BufferId id) { - Client *client = Client::instance(); - if(!buffers.contains(id)) { - Buffer *b = new Buffer(id); - b->setOwnNick(ownNick[id.network()]); - connect(b, SIGNAL(userInput(BufferId, QString)), client, SLOT(userInput(BufferId, QString))); - connect(b, SIGNAL(bufferUpdated(Buffer *)), client, SIGNAL(bufferUpdated(Buffer *))); - connect(b, SIGNAL(bufferDestroyed(Buffer *)), client, SIGNAL(bufferDestroyed(Buffer *))); - connect(b, SIGNAL(bufferDestroyed(Buffer *)), client, SLOT(removeBuffer(Buffer *))); - buffers[id] = b; - emit client->bufferUpdated(b); + + Q_ASSERT(networkInfo(networkid)); + if(!networkInfo(networkid)->initialized()) { + qDebug() << "Network" << networkid << "disconnected while not yet initialized!"; + updateCoreConnectionProgress(); } - return buffers[id]; } -QList Client::allBufferIds() { - return buffers.keys(); +void Client::updateBufferInfo(BufferInfo id) { + buffer(id)->updateBufferInfo(id); } + void Client::removeBuffer(Buffer *b) { - buffers.remove(b->bufferId()); - bufferIds.remove(b->bufferId().uid()); -} - -void Client::recvNetworkState(QString net, QVariant state) { - netsAwaitingInit.removeAll(net); - netConnected[net] = true; - setOwnNick(net, state.toMap()["OwnNick"].toString()); - buffer(statusBufferId(net))->setActive(true); - QVariantMap t = state.toMap()["Topics"].toMap(); - QVariantMap n = state.toMap()["Nicks"].toMap(); - foreach(QVariant v, t.keys()) { - QString buf = v.toString(); - BufferId id = bufferId(net, buf); - buffer(id)->setActive(true); - setTopic(net, buf, t[buf].toString()); - } - foreach(QString nick, n.keys()) { - addNick(net, nick, n[nick].toMap()); - } - emit coreConnectionProgress(netConnected.count(), netConnected.count() + netsAwaitingInit.count()); - if(!netsAwaitingInit.count()) emit connected(); + _buffers.remove(b->bufferInfo().uid()); } void Client::recvMessage(const Message &msg) { @@ -385,10 +477,9 @@ void Client::recvMessage(const Message &msg) { void Client::recvStatusMsg(QString /*net*/, QString /*msg*/) { //recvMessage(net, Message::server("", QString("[STATUS] %1").arg(msg))); - } -void Client::recvBacklogData(BufferId id, QVariantList msgs, bool /*done*/) { +void Client::recvBacklogData(BufferInfo id, QVariantList msgs, bool /*done*/) { Buffer *b = buffer(id); foreach(QVariant v, msgs) { Message msg = v.value(); @@ -401,79 +492,19 @@ void Client::recvBacklogData(BufferId id, QVariantList msgs, bool /*done*/) { void Client::layoutMsg() { if(layoutQueue.count()) { Buffer *b = layoutQueue.takeFirst(); // TODO make this the current buffer - if(b->layoutMsg()) layoutQueue.append(b); // Buffer has more messages in its queue --> Round Robin + if(b->layoutMsg()) + layoutQueue.append(b); // Buffer has more messages in its queue --> Round Robin } - if(!layoutQueue.count()) layoutTimer->stop(); + + if(!layoutQueue.count()) + layoutTimer->stop(); } AbstractUiMsg *Client::layoutMsg(const Message &msg) { return instance()->mainUi->layoutMsg(msg); } -void Client::userInput(BufferId id, QString msg) { +void Client::userInput(BufferInfo id, QString msg) { emit sendInput(id, msg); } -void Client::setTopic(QString net, QString buf, QString topic) { - BufferId id = bufferId(net, buf); - if(!netConnected[id.network()]) return; - Buffer *b = buffer(id); - b->setTopic(topic); - //if(!b->isActive()) { - // b->setActive(true); - // buffersUpdated(); - //} -} - -void Client::addNick(QString net, QString nick, QVariantMap props) { - if(!netConnected[net]) return; - nicks[net][nick] = props; - QVariantMap chans = props["Channels"].toMap(); - QStringList c = chans.keys(); - foreach(QString bufname, c) { - buffer(bufferId(net, bufname))->addNick(nick, props); - } -} - -void Client::renameNick(QString net, QString oldnick, QString newnick) { - if(!netConnected[net]) return; - QStringList chans = nicks[net][oldnick]["Channels"].toMap().keys(); - foreach(QString c, chans) { - buffer(bufferId(net, c))->renameNick(oldnick, newnick); - } - nicks[net][newnick] = nicks[net].take(oldnick); -} - -void Client::updateNick(QString net, QString nick, QVariantMap props) { - if(!netConnected[net]) return; - QStringList oldchans = nicks[net][nick]["Channels"].toMap().keys(); - QStringList newchans = props["Channels"].toMap().keys(); - foreach(QString c, newchans) { - if(oldchans.contains(c)) buffer(bufferId(net, c))->updateNick(nick, props); - else buffer(bufferId(net, c))->addNick(nick, props); - } - foreach(QString c, oldchans) { - if(!newchans.contains(c)) buffer(bufferId(net, c))->removeNick(nick); - } - nicks[net][nick] = props; -} - -void Client::removeNick(QString net, QString nick) { - if(!netConnected[net]) return; - QVariantMap chans = nicks[net][nick]["Channels"].toMap(); - foreach(QString bufname, chans.keys()) { - buffer(bufferId(net, bufname))->removeNick(nick); - } - nicks[net].remove(nick); -} - -void Client::setOwnNick(QString net, QString nick) { - if(!netConnected[net]) return; - ownNick[net] = nick; - foreach(BufferId id, buffers.keys()) { - if(id.network() == net) { - buffers[id]->setOwnNick(nick); - } - } -} - diff --git a/src/client/client.h b/src/client/client.h index 2496c668..8a824c37 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -26,132 +26,137 @@ #include #include -#include "buffer.h" -#include "message.h" +#include "buffer.h" // needed for activity lvl +class BufferInfo; +class Message; + +class NetworkInfo; class AbstractUi; +class AbstractUiMsg; class BufferTreeModel; -class QtGui; class SignalProxy; class QTimer; + class Client : public QObject { Q_OBJECT - public: - static Client *instance(); - static void init(AbstractUi *); - static void destroy(); - - static QList allBufferIds(); - static Buffer *buffer(BufferId); - static BufferId statusBufferId(QString net); - static BufferId bufferId(QString net, QString buf); - - static BufferTreeModel *bufferModel(); - static SignalProxy *signalProxy(); - - static AbstractUiMsg *layoutMsg(const Message &); - - static bool isConnected(); - - static void storeSessionData(const QString &key, const QVariant &data); - static QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant()); - static QStringList sessionDataKeys(); - - enum ClientMode { LocalCore, RemoteCore }; - static ClientMode clientMode; - - signals: - void sendInput(BufferId, QString message); - void showBuffer(Buffer *); - void bufferSelected(Buffer *); - void bufferUpdated(Buffer *); - void bufferActivity(Buffer::ActivityLevel, Buffer *); - void bufferDestroyed(Buffer *); - void backlogReceived(Buffer *, QList); - void requestBacklog(BufferId, QVariant, QVariant); - void requestNetworkStates(); - - void recvPartialItem(uint avail, uint size); - void coreConnectionError(QString errorMsg); - void coreConnectionMsg(const QString &msg); - void coreConnectionProgress(uint part, uint total); - - void connected(); - void disconnected(); - - void sessionDataChanged(const QString &key); - void sessionDataChanged(const QString &key, const QVariant &data); - void sendSessionData(const QString &key, const QVariant &data); - - public slots: - //void selectBuffer(Buffer *); - //void connectToLocalCore(); - void connectToCore(const QVariantMap &); - void disconnectFromCore(); - - private slots: - void recvCoreState(const QVariant &state); - void recvSessionData(const QString &key, const QVariant &data); - - void coreSocketError(QAbstractSocket::SocketError); - void coreHasData(); - void coreSocketConnected(); - void coreSocketDisconnected(); - void coreSocketStateChanged(QAbstractSocket::SocketState); - - void userInput(BufferId, QString); - void networkConnected(QString); - void networkDisconnected(QString); - void recvNetworkState(QString, QVariant); - void recvMessage(const Message &message); - void recvStatusMsg(QString network, QString message); - void setTopic(QString net, QString buf, QString); - void addNick(QString net, QString nick, QVariantMap props); - void removeNick(QString net, QString nick); - void renameNick(QString net, QString oldnick, QString newnick); - void updateNick(QString net, QString nick, QVariantMap props); - void setOwnNick(QString net, QString nick); - void recvBacklogData(BufferId, QVariantList, bool); - void updateBufferId(BufferId); - - void removeBuffer(Buffer *); - - void layoutMsg(); - - private: - Client(); - ~Client(); - void init(); - static Client *instanceptr; - - void syncToCore(const QVariant &coreState); - QVariant connectToLocalCore(QString user, QString passwd); // defined in main.cpp - void disconnectFromLocalCore(); // defined in main.cpp - - AbstractUi *mainUi; - SignalProxy *_signalProxy; - BufferTreeModel *_bufferModel; - - QPointer socket; - quint32 blockSize; - - static bool connectedToCore; - static QVariantMap coreConnectionInfo; - static QHash buffers; - static QHash bufferIds; - static QHash > nicks; - static QHash netConnected; - static QStringList netsAwaitingInit; - static QHash ownNick; - - QTimer *layoutTimer; - QList layoutQueue; - - QVariantMap sessionData; +public: + static Client *instance(); + static void destroy(); + static void init(AbstractUi *); + + static QList networkInfos(); + static NetworkInfo *networkInfo(uint networkid); + + static QList allBufferInfos(); + static QList buffers(); + static Buffer *buffer(uint bufferUid); + static Buffer *buffer(BufferInfo); + static BufferInfo statusBufferInfo(QString net); + static BufferInfo bufferInfo(QString net, QString buf); + + static BufferTreeModel *bufferModel(); + static SignalProxy *signalProxy(); + + static AbstractUiMsg *layoutMsg(const Message &); + + static bool isConnected(); + + static void storeSessionData(const QString &key, const QVariant &data); + static QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant()); + static QStringList sessionDataKeys(); + + enum ClientMode { LocalCore, RemoteCore }; + +signals: + void sendInput(BufferInfo, QString message); + void showBuffer(Buffer *); + void bufferSelected(Buffer *); + void bufferUpdated(Buffer *); + void bufferActivity(Buffer::ActivityLevel, Buffer *); + void bufferDestroyed(Buffer *); + void backlogReceived(Buffer *, QList); + void requestBacklog(BufferInfo, QVariant, QVariant); + void requestNetworkStates(); + + void recvPartialItem(uint avail, uint size); + void coreConnectionError(QString errorMsg); + void coreConnectionMsg(const QString &msg); + void coreConnectionProgress(uint part, uint total); + + void connected(); + void disconnected(); + + void sessionDataChanged(const QString &key); + void sessionDataChanged(const QString &key, const QVariant &data); + void sendSessionData(const QString &key, const QVariant &data); + +public slots: + //void selectBuffer(Buffer *); + //void connectToLocalCore(); + void connectToCore(const QVariantMap &); + void disconnectFromCore(); + +private slots: + void recvCoreState(const QVariant &state); + void recvSessionData(const QString &key, const QVariant &data); + + void coreSocketError(QAbstractSocket::SocketError); + void coreHasData(); + void coreSocketConnected(); + void coreSocketDisconnected(); + void coreSocketStateChanged(QAbstractSocket::SocketState); + + void userInput(BufferInfo, QString); + + void networkConnected(uint); + void networkDisconnected(uint); + + void updateCoreConnectionProgress(); + void recvMessage(const Message &message); + void recvStatusMsg(QString network, QString message); + void recvBacklogData(BufferInfo, QVariantList, bool); + void updateBufferInfo(BufferInfo); + + void removeBuffer(Buffer *); + + void layoutMsg(); + +private: + Client(QObject *parent = 0); + virtual ~Client(); + void init(); + + void syncToCore(const QVariant &coreState); + QVariant connectToLocalCore(QString user, QString passwd); // defined in main.cpp + void disconnectFromLocalCore(); // defined in main.cpp + + static QPointer instanceptr; + + QPointer socket; + QPointer _signalProxy; + QPointer mainUi; + QPointer _bufferModel; + + ClientMode clientMode; + + quint32 blockSize; + bool connectedToCore; + + QVariantMap coreConnectionInfo; + QHash _buffers; + QHash _networkInfo; + + QTimer *layoutTimer; + QList layoutQueue; + + QVariantMap sessionData; + + }; #endif diff --git a/src/client/quasselui.h b/src/client/quasselui.h index 414d5993..327c37f6 100644 --- a/src/client/quasselui.h +++ b/src/client/quasselui.h @@ -31,7 +31,7 @@ class AbstractUiMsg { virtual QString sender() const = 0; virtual QString text() const = 0; virtual MsgId msgId() const = 0; - virtual BufferId bufferId() const = 0; + virtual BufferInfo bufferInfo() const = 0; virtual QDateTime timeStamp() const = 0; }; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 26e087a6..b03ef455 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,6 +1,6 @@ -SET(common_SRCS global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp ircuser.cpp) +SET(common_SRCS global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp synchronizer.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp) SET(common_HDRS global.h message.h util.h) -SET(common_MOCS logger.h ircuser.h settings.h signalproxy.h) +SET(common_MOCS logger.h synchronizer.h networkinfo.h ircuser.h ircchannel.h settings.h signalproxy.h) QT4_WRAP_CPP(_MOC ${common_MOCS}) ADD_LIBRARY(common ${common_SRCS} ${_MOC}) diff --git a/src/common/bufferinfo.cpp b/src/common/bufferinfo.cpp new file mode 100644 index 00000000..c7cdd73e --- /dev/null +++ b/src/common/bufferinfo.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel IRC Development Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include + +#include "bufferinfo.h" + +#include "util.h" + +BufferInfo::BufferInfo() + : _id(0), + _netid(0), + _gid(0), + _networkName(QString()), + _bufferName(QString()) { +} + +BufferInfo::BufferInfo(uint id, uint networkid, uint gid, QString net, QString buf) + : _id(id), + _netid(networkid), + _gid(gid), + _networkName(net), + _bufferName(buf) { +} + +QString BufferInfo::buffer() const { + if(isChannelName(_bufferName)) + return _bufferName; + else + return nickFromMask(_bufferName); +} + +QDataStream &operator<<(QDataStream &out, const BufferInfo &bufferInfo) { + out << bufferInfo._id << bufferInfo._netid << bufferInfo._gid << bufferInfo._networkName.toUtf8() << bufferInfo._bufferName.toUtf8(); + return out; +} + +QDataStream &operator>>(QDataStream &in, BufferInfo &bufferInfo) { + QByteArray n, b; + in >> bufferInfo._id >> bufferInfo._netid >> bufferInfo._gid >> n >> b; + bufferInfo._networkName = QString::fromUtf8(n); + bufferInfo._bufferName = QString::fromUtf8(b); + return in; +} + +uint qHash(const BufferInfo &bufferid) { + return qHash(bufferid._id); +} + diff --git a/src/common/bufferinfo.h b/src/common/bufferinfo.h new file mode 100644 index 00000000..b7430549 --- /dev/null +++ b/src/common/bufferinfo.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel IRC Development Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef _BUFFERINFO_H_ +#define _BUFFERINFO_H_ + +#include + +class QString; +class QDataStream; + +class BufferInfo { +public: + BufferInfo(); + BufferInfo(uint id, uint networkid, uint gid = 0, QString net = QString(), QString buf = QString()); + + inline uint uid() const { return _id; } + inline uint networkId() const { return _netid; } + inline uint groupId() const { return _gid; } + inline QString network() const { return _networkName; } + QString buffer() const; + + void setGroupId(uint gid) { _gid = gid; } + + inline bool operator==(const BufferInfo &other) const { return _id == other._id; } + +private: + uint _id; + uint _netid; + uint _gid; + QString _networkName; // WILL BE REMOVED + QString _bufferName; + + friend uint qHash(const BufferInfo &); + friend QDataStream &operator<<(QDataStream &out, const BufferInfo &bufferInfo); + friend QDataStream &operator>>(QDataStream &in, BufferInfo &bufferInfo); +}; + +QDataStream &operator<<(QDataStream &out, const BufferInfo &bufferInfo); +QDataStream &operator>>(QDataStream &in, BufferInfo &bufferInfo); + +Q_DECLARE_METATYPE(BufferInfo); + +uint qHash(const BufferInfo &); + +#endif diff --git a/src/common/common.pri b/src/common/common.pri index c218ee9e..0df5568f 100644 --- a/src/common/common.pri +++ b/src/common/common.pri @@ -1,4 +1,4 @@ DEPMOD = contrib/qxt QT_MOD = network -SRCS += global.cpp ircuser.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp -HDRS += global.h ircuser.h logger.h message.h settings.h signalproxy.h util.h +SRCS += global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp synchronizer.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp bufferinfo.cpp +HDRS += global.h logger.h message.h settings.h signalproxy.h util.h synchronizer.h networkinfo.h ircuser.h ircchannel.h bufferinfo.h diff --git a/src/common/global.cpp b/src/common/global.cpp index ed2d1df8..cdb33765 100644 --- a/src/common/global.cpp +++ b/src/common/global.cpp @@ -46,47 +46,6 @@ void Global::initIconMap() { } */ -/**************************************************************************************/ -BufferId::BufferId() - : _id(0), - _netid(0), - _gid(0), - _networkName(QString()), - _bufferName(QString()) { -} - -BufferId::BufferId(uint id, uint networkid, uint gid, QString net, QString buf) - : _id(id), - _netid(networkid), - _gid(gid), - _networkName(net), - _bufferName(buf) { -} - -QString BufferId::buffer() const { - if(isChannelName(_bufferName)) - return _bufferName; - else - return nickFromMask(_bufferName); -} - -QDataStream &operator<<(QDataStream &out, const BufferId &bufferId) { - out << bufferId._id << bufferId._netid << bufferId._gid << bufferId._networkName.toUtf8() << bufferId._bufferName.toUtf8(); - return out; -} - -QDataStream &operator>>(QDataStream &in, BufferId &bufferId) { - QByteArray n, b; - in >> bufferId._id >> bufferId._netid >> bufferId._gid >> n >> b; - bufferId._networkName = QString::fromUtf8(n); - bufferId._bufferName = QString::fromUtf8(b); - return in; -} - -uint qHash(const BufferId &bufferid) { - return qHash(bufferid._id); -} - /** * Retrieves an icon determined by its symbolic name. The mapping shall later * be performed by a theme manager or something like that. diff --git a/src/common/global.h b/src/common/global.h index 1d1d3759..fd285ca0 100644 --- a/src/common/global.h +++ b/src/common/global.h @@ -55,38 +55,4 @@ struct Exception { }; -class BufferId { -public: - BufferId(); - BufferId(uint _id, uint _networkid, uint _gid = 0, QString _net = QString(), QString _buf = QString()); - - inline uint uid() const { return _id; } - inline uint networkId() const { return _netid; } - inline uint groupId() const { return _gid; } - inline QString network() const { return _networkName; } - QString buffer() const; - - void setGroupId(uint gid) { _gid = gid; } - - inline bool operator==(const BufferId &other) const { return _id == other._id; } - -private: - uint _id; - uint _netid; - uint _gid; - QString _networkName; // WILL BE REMOVED - QString _bufferName; // IS this actually needed? - - friend uint qHash(const BufferId &); - friend QDataStream &operator<<(QDataStream &out, const BufferId &bufferId); - friend QDataStream &operator>>(QDataStream &in, BufferId &bufferId); -}; - -QDataStream &operator<<(QDataStream &out, const BufferId &bufferId); -QDataStream &operator>>(QDataStream &in, BufferId &bufferId); - -Q_DECLARE_METATYPE(BufferId); - -uint qHash(const BufferId &); - #endif diff --git a/src/common/ircchannel.cpp b/src/common/ircchannel.cpp new file mode 100644 index 00000000..95d0ed11 --- /dev/null +++ b/src/common/ircchannel.cpp @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "ircchannel.h" + +#include "networkinfo.h" +#include "signalproxy.h" +#include "ircuser.h" + +#include +#include + +#include + + +IrcChannel::IrcChannel(const QString &channelname, NetworkInfo *networkinfo) + : QObject(networkinfo), + _initialized(false), + _name(channelname), + _topic(QString()), + networkInfo(networkinfo) +{ + setObjectName(QString::number(networkInfo->networkId()) + "/" + channelname); +} + +// ==================== +// PUBLIC: +// ==================== +bool IrcChannel::isKnownUser(IrcUser *ircuser) const { + bool isknown = true; + + if(ircuser == 0) { + qWarning() << "Channel" << name() << "received IrcUser Nullpointer!"; + isknown = false; + } + + if(!_userModes.contains(ircuser) && ircuser) { + qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick(); + isknown = false; + } + + return isknown; +} + +bool IrcChannel::isValidChannelUserMode(const QString &mode) const { + bool isvalid = true; + if(mode.size() > 1) { + qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode; + isvalid = false; + } + return isvalid; +} + +bool IrcChannel::initialized() const { + return _initialized; +} + +QString IrcChannel::name() const { + return _name; +} + +QString IrcChannel::topic() const { + return _topic; +} + +QList IrcChannel::ircUsers() const { + return _userModes.keys(); +} + +QString IrcChannel::userMode(IrcUser *ircuser) const { + if(_userModes.contains(ircuser)) + return _userModes[ircuser]; + else + return QString(); +} + +QString IrcChannel::userMode(const QString &nick) const { + return userMode(networkInfo->ircUser(nick)); +} + +// ==================== +// PUBLIC SLOTS: +// ==================== +void IrcChannel::setTopic(const QString &topic) { + _topic = topic; + emit topicSet(topic); +} + +void IrcChannel::join(IrcUser *ircuser) { + if(!_userModes.contains(ircuser) && ircuser) { + _userModes[ircuser] = QString(); + ircuser->joinChannel(name()); + // no emit here since the join is propagated by IrcUser + } +} + +void IrcChannel::join(const QString &nick) { + join(networkInfo->ircUser(nick)); +} + +void IrcChannel::part(IrcUser *ircuser) { + if(isKnownUser(ircuser)) { + _userModes.remove(ircuser); + ircuser->partChannel(name()); + // no emit here since the part is propagated by IrcUser + } +} + +void IrcChannel::part(const QString &nick) { + part(networkInfo->ircUser(nick)); +} + +// SET USER MODE +void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes) { + if(isKnownUser(ircuser)) { + _userModes[ircuser] = modes; + emit userModesSet(ircuser->nick(), modes); + } +} + +void IrcChannel::setUserModes(const QString &nick, const QString &modes) { + setUserModes(networkInfo->ircUser(nick), modes); +} + +// ADD USER MODE +void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode) { + if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode)) + return; + + if(!_userModes[ircuser].contains(mode)) { + _userModes[ircuser] += mode; + emit userModeAdded(ircuser->nick(), mode); + } + +} + +void IrcChannel::addUserMode(const QString &nick, const QString &mode) { + addUserMode(networkInfo->ircUser(nick), mode); +} + + +// REMOVE USER MODE +void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode) { + if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode)) + return; + + if(_userModes[ircuser].contains(mode)) { + _userModes[ircuser].remove(mode); + emit userModeRemoved(ircuser->nick(), mode); + } + +} + +void IrcChannel::removeUserMode(const QString &nick, const QString &mode) { + removeUserMode(networkInfo->ircUser(nick), mode); +} + +// INIT SET USER MODES +QVariantMap IrcChannel::initUserModes() const { + QVariantMap usermodes; + QHashIterator iter(_userModes); + while(iter.hasNext()) { + iter.next(); + usermodes[iter.key()->nick()] = iter.value(); + } + return usermodes; +} + +void IrcChannel::initSetUserModes(const QVariantMap &usermodes) { + QMapIterator iter(usermodes); + while(iter.hasNext()) { + iter.next(); + setUserModes(iter.key(), iter.value().toString()); + } +} + +void IrcChannel::ircUserDestroyed() { + part(qobject_cast(sender())); +} + +void IrcChannel::setInitialized() { + _initialized = true; + emit initDone(); +} + diff --git a/src/common/ircchannel.h b/src/common/ircchannel.h new file mode 100644 index 00000000..2b438761 --- /dev/null +++ b/src/common/ircchannel.h @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _IRCCHANNEL_H_ +#define _IRCCHANNEL_H_ + +#include +#include +#include +#include + +class SignalProxy; +class NetworkInfo; +class IrcUser; + +class IrcChannel : public QObject { + Q_OBJECT + + Q_PROPERTY(QString name READ name STORED false) + Q_PROPERTY(QString topic READ topic WRITE setTopic STORED false) + +public: + IrcChannel(const QString &channelname, NetworkInfo *networkInfo); + + bool isKnownUser(IrcUser *ircuser) const; + bool isValidChannelUserMode(const QString &mode) const; + + bool initialized() const; + + QString name() const; + QString topic() const; + + QList ircUsers() const; + + QString userMode(IrcUser *ircuser) const; + QString userMode(const QString &nick) const; + + +public slots: + void setTopic(const QString &topic); + + void join(IrcUser *ircuser); + void join(const QString &nick); + + void part(IrcUser *ircuser); + void part(const QString &nick); + + void setUserModes(IrcUser *ircuser, const QString &modes); + void setUserModes(const QString &nick, const QString &modes); + + void addUserMode(IrcUser *ircuser, const QString &mode); + void addUserMode(const QString &nick, const QString &mode); + + void removeUserMode(IrcUser *ircuser, const QString &mode); + void removeUserMode(const QString &nick, const QString &mode); + + // init geters + QVariantMap initUserModes() const; + + // init seters + void initSetUserModes(const QVariantMap &usermodes); + + void ircUserDestroyed(); + + void setInitialized(); + +signals: + void topicSet(QString topic); + void userModesSet(QString nick, QString modes); + void userModeAdded(QString nick, QString mode); + void userModeRemoved(QString nick, QString mode); + + void initDone(); + +private: + bool _initialized; + QString _name; + QString _topic; + + QHash _userModes; + + NetworkInfo *networkInfo; +}; + +#endif diff --git a/src/common/ircuser.cpp b/src/common/ircuser.cpp index be5f49ab..665b10ff 100644 --- a/src/common/ircuser.cpp +++ b/src/common/ircuser.cpp @@ -21,94 +21,161 @@ #include "ircuser.h" #include "util.h" -IrcUser::IrcUser(QObject *parent) - : QObject(parent) { +#include "networkinfo.h" +#include "signalproxy.h" +#include "ircchannel.h" + +#include + +IrcUser::IrcUser(const QString &hostmask, NetworkInfo *networkinfo) + : QObject(networkinfo), + _initialized(false), + _nick(nickFromMask(hostmask)), + _user(userFromMask(hostmask)), + _host(hostFromMask(hostmask)), + networkInfo(networkinfo) +{ + setObjectName(QString::number(networkInfo->networkId()) + "/" + IrcUser::hostmask()); } -IrcUser::IrcUser(const QString &hostmask, QObject *parent) - : QObject(parent), - nick_(nickFromMask(hostmask)), - user_(userFromMask(hostmask)), - host_(hostFromMask(hostmask)) { +// ==================== +// PUBLIC: +// ==================== +bool IrcUser::initialized() const { + return _initialized; } -IrcUser::~IrcUser() { +QString IrcUser::user() const { + return _user; } -void IrcUser::setUser(const QString &user) { - user_ = user; +QString IrcUser::host() const { + return _host; } -QString IrcUser::user() const { - return user_; +QString IrcUser::nick() const { + return _nick; } -void IrcUser::setHost(const QString &host) { - host_ = host; +QString IrcUser::hostmask() const { + return QString("%1!%2@%3").arg(nick()).arg(user()).arg(host()); } -QString IrcUser::host() const { - return host_; +QString IrcUser::userModes() const { + return _userModes; } -void IrcUser::setNick(const QString &nick) { - nick_ = nick; +QStringList IrcUser::channels() const { + return _channels.toList(); } -QString IrcUser::nick() const { - return nick_; +void IrcUser::updateObjectName() { + setObjectName(QString::number(networkInfo->networkId()) + "/" + hostmask()); + emit objectNameSet(); +} + +// ==================== +// PUBLIC SLOTS: +// ==================== +void IrcUser::setUser(const QString &user) { + if(!user.isEmpty() && _user != user) { + _user = user; + emit userSet(user); + + setObjectName(hostmask()); + emit objectNameSet(); + } } -void IrcUser::setUsermodes(const QSet &usermodes) { - usermodes_ = usermodes; +void IrcUser::setHost(const QString &host) { + if(!host.isEmpty() && _host != host) { + _host = host; + emit hostSet(host); + updateObjectName(); + } } -QSet IrcUser::usermodes() const { - return usermodes_; +void IrcUser::setNick(const QString &nick) { + if(!nick.isEmpty() && nick != _nick) { + QString oldnick(_nick); + _nick = nick; + emit nickSet(nick); + updateObjectName(); + } } -void IrcUser::setChannelmode(const QString &channel, const QSet &channelmode) { - if(channelmodes_.contains(channel)) - channelmodes_[channel] |= channelmode; - else - channelmodes_[channel] = channelmode; +void IrcUser::updateHostmask(const QString &mask) { + if(mask == hostmask()) + return; + + QString user = userFromMask(mask); + QString host = hostFromMask(mask); + + // we only need to check user and hostmask. + // nick can't have changed since we're identifying IrcUsers by nick + + // we don't use setUser and setHost here. + // though this is unpretty code duplication this saves us one emit objectNameSet() + // the second one would be erroneous + + if(!user.isEmpty() && _user != user) { + _user = user; + } + + if(!host.isEmpty() && _host != host) { + _host = host; + } + + emit hostmaskUpdated(mask); + updateObjectName(); } -QSet IrcUser::channelmode(const QString &channel) const { - if(channelmodes_.contains(channel)) - //throw NoSuchChannelException(); - Q_ASSERT(false); // FIXME: exception disabled for qtopia testing - else - return QSet(); +void IrcUser::joinChannel(const QString &channel) { + if(!_channels.contains(channel)) { + _channels.insert(channel); + networkInfo->newIrcChannel(channel)->join(this); + emit channelJoined(channel); + } } -void IrcUser::updateChannelmode(const QString &channel, const QString &channelmode, bool add) { - if(add) - addChannelmode(channel, channelmode); - else - removeChannelmode(channel, channelmode); +void IrcUser::partChannel(const QString &channel) { + if(_channels.contains(channel)) { + _channels.remove(channel); + + Q_ASSERT(networkInfo->ircChannel(channel)); + networkInfo->ircChannel(channel)->part(this); + + emit channelParted(channel); + } } -void IrcUser::addChannelmode(const QString &channel, const QString &channelmode) { - if(!channelmodes_.contains(channel)) - channelmodes_[channel] = QSet(); - channelmodes_[channel] << channelmode; +void IrcUser::setUserModes(const QString &modes) { + _userModes = modes; + emit userModesSet(modes); } -void IrcUser::removeChannelmode(const QString &channel, const QString &channelmode) { - if(channelmodes_.contains(channel)) - channelmodes_[channel].remove(channelmode); +void IrcUser::addUserMode(const QString &mode) { + if(!_userModes.contains(mode)) { + _userModes += mode; + emit userModeAdded(mode); + } } -QStringList IrcUser::channels() const { - return channelmodes_.keys(); +void IrcUser::removeUserMode(const QString &mode) { + if(_userModes.contains(mode)) { + _userModes.remove(mode); + emit userModeRemoved(mode); + } } -void IrcUser::joinChannel(const QString &channel) { - if(!channelmodes_.contains(channel)) - channelmodes_[channel] = QSet(); +void IrcUser::initSetChannels(const QStringList channels) { + foreach(QString channel, channels) { + joinChannel(channel); + } } -void IrcUser::partChannel(const QString &channel) { - channelmodes_.remove(channel); +void IrcUser::setInitialized() { + _initialized = true; + emit initDone(); } + diff --git a/src/common/ircuser.h b/src/common/ircuser.h index b6c4b324..4fe3f37a 100644 --- a/src/common/ircuser.h +++ b/src/common/ircuser.h @@ -21,73 +21,102 @@ #ifndef _IRCUSER_H_ #define _IRCUSER_H_ -#include -#include -#include #include #include #include +#include -#include "global.h" +class SignalProxy; +class NetworkInfo; +class IrcChannel; class IrcUser : public QObject { Q_OBJECT -// Q_PROPERTY(QString user READ user WRITE setUser) -// Q_PROPERTY(QString host READ host WRITE setHost) -// Q_PROPERTY(QString nick READ nick WRITE setNick) -// Q_PROPERTY(QSet usermodes READ usermodes WRITE setUsermodes) -// Q_PROPERTY(QStringList channels READ channels) + Q_PROPERTY(QString user READ user WRITE setUser STORED false) + Q_PROPERTY(QString host READ host WRITE setHost STORED false) + Q_PROPERTY(QString nick READ nick WRITE setNick STORED false) + + Q_PROPERTY(QStringList channels READ channels STORED false) + // Q_PROPERTY(QStringList usermodes READ usermodes WRITE setUsermodes) + public: - IrcUser(QObject *parent = 0); - IrcUser(const QString &hostmask, QObject *parent = 0); - ~IrcUser(); - - void setUser(const QString &user); + IrcUser(const QString &hostmask, NetworkInfo *networkInfo); + + bool initialized() const; + QString user() const; - - void setHost(const QString &host); QString host() const; - - void setNick(const QString &nick); QString nick() const; - - void setUsermodes(const QSet &usermodes); - QSet usermodes() const; - - void setChannelmode(const QString &channel, const QSet &channelmode); - QSet channelmode(const QString &channel) const; - - void updateChannelmode(const QString &channel, const QString &channelmode, bool add=true); - void addChannelmode(const QString &channel, const QString &channelmode); - void removeChannelmode(const QString &channel, const QString &channelmode); + QString hostmask() const; + + QString userModes() const; QStringList channels() const; - + + void updateObjectName(); + +public slots: + void setUser(const QString &user); + void setHost(const QString &host); + void setNick(const QString &nick); + void updateHostmask(const QString &mask); + + void setUserModes(const QString &modes); + void joinChannel(const QString &channel); void partChannel(const QString &channel); + + void addUserMode(const QString &mode); + void removeUserMode(const QString &mode); + + // init seters + void initSetChannels(const QStringList channels); + + void setInitialized(); + +signals: + void userSet(QString user); + void hostSet(QString host); + void nickSet(QString newnick); + void hostmaskUpdated(QString mask); + + void channelsSet(QStringList channels); + void userModesSet(QString modes); + + void channelJoined(QString channel); + void channelParted(QString channel); + + void userModeAdded(QString mode); + void userModeRemoved(QString mode); + + void objectNameSet(); +// void setUsermodes(const QSet &usermodes); +// QSet usermodes() const; + + void initDone(); + private: inline bool operator==(const IrcUser &ircuser2) { - return (nick_.toLower() == ircuser2.nick().toLower()); + return (_nick.toLower() == ircuser2.nick().toLower()); } inline bool operator==(const QString &nickname) { - return (nick_.toLower() == nickname.toLower()); + return (_nick.toLower() == nickname.toLower()); } - - QString nick_; - QString user_; - QString host_; - - QHash > channelmodes_; //keys: channelnames; values: Set of Channelmodes - QSet usermodes_; -}; -struct IrcUserException : public Exception {}; -struct NoSuchChannelException : public IrcUserException {}; -struct NoSuchNickException : public IrcUserException {}; + bool _initialized; + + QString _nick; + QString _user; + QString _host; + QSet _channels; + QString _userModes; + + NetworkInfo *networkInfo; +}; #endif diff --git a/src/common/main.cpp b/src/common/main.cpp index 897208f8..b86f2261 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -61,10 +61,10 @@ int main(int argc, char **argv) { qRegisterMetaType("QVariant"); qRegisterMetaType("Message"); - qRegisterMetaType("BufferId"); + qRegisterMetaType("BufferInfo"); qRegisterMetaTypeStreamOperators("QVariant"); qRegisterMetaTypeStreamOperators("Message"); - qRegisterMetaTypeStreamOperators("BufferId"); + qRegisterMetaTypeStreamOperators("BufferInfo"); #if defined BUILD_CORE Global::runMode = Global::CoreOnly; diff --git a/src/common/message.cpp b/src/common/message.cpp index c4c9bf13..797dfbbf 100644 --- a/src/common/message.cpp +++ b/src/common/message.cpp @@ -19,15 +19,17 @@ ***************************************************************************/ #include "message.h" + #include "util.h" + #include -Message::Message(BufferId __buffer, Type __type, QString __text, QString __sender, quint8 __flags) +Message::Message(BufferInfo __buffer, Type __type, QString __text, QString __sender, quint8 __flags) : _buffer(__buffer), _text(__text), _sender(__sender), _type(__type), _flags(__flags) { _timeStamp = QDateTime::currentDateTime().toUTC(); } -Message::Message(QDateTime __ts, BufferId __buffer, Type __type, QString __text, QString __sender, quint8 __flags) +Message::Message(QDateTime __ts, BufferInfo __buffer, Type __type, QString __text, QString __sender, quint8 __flags) : _timeStamp(__ts), _buffer(__buffer), _text(__text), _sender(__sender), _type(__type), _flags(__flags) { } @@ -40,7 +42,7 @@ void Message::setMsgId(MsgId _id) { _msgId = _id; } -BufferId Message::buffer() const { +BufferInfo Message::buffer() const { return _buffer; } @@ -161,7 +163,7 @@ QDataStream &operator>>(QDataStream &in, Message &msg) { quint8 t, f; quint32 ts; QByteArray s, m; - BufferId buf; + BufferInfo buf; in >> ts >> t >> f >> buf >> s >> m; msg._type = (Message::Type)t; msg._flags = (quint8)f; diff --git a/src/common/message.h b/src/common/message.h index 05d402e0..878acfad 100644 --- a/src/common/message.h +++ b/src/common/message.h @@ -25,6 +25,7 @@ #include #include +#include "bufferinfo.h" #include "global.h" class Message { @@ -35,14 +36,14 @@ class Message { enum Type { Plain, Notice, Action, Nick, Mode, Join, Part, Quit, Kick, Kill, Server, Info, Error }; enum Flags { None = 0, Self = 1, PrivMsg = 2, Highlight = 4 }; - Message(BufferId buffer = BufferId(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None); + Message(BufferInfo buffer = BufferInfo(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None); - Message(QDateTime ts, BufferId buffer = BufferId(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None); + Message(QDateTime ts, BufferInfo buffer = BufferInfo(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None); MsgId msgId() const; void setMsgId(MsgId id); - BufferId buffer() const; + BufferInfo buffer() const; QString text() const; QString sender() const; Type type() const; @@ -58,7 +59,7 @@ class Message { private: QDateTime _timeStamp; MsgId _msgId; - BufferId _buffer; + BufferInfo _buffer; QString _text; QString _sender; Type _type; diff --git a/src/common/networkinfo.cpp b/src/common/networkinfo.cpp new file mode 100644 index 00000000..114287ac --- /dev/null +++ b/src/common/networkinfo.cpp @@ -0,0 +1,376 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "networkinfo.h" + +#include "signalproxy.h" +#include "synchronizer.h" +#include "ircuser.h" +#include "ircchannel.h" + +#include + +#include "util.h" + +// ==================== +// Public: +// ==================== +NetworkInfo::NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent) + : QObject(parent), + _networkId(networkid), + _initialized(false), + _myNick(QString()), + _networkName(QString()), + _currentServer(QString()), + _prefixes(QString()), + _prefixModes(QString()) +{ + setObjectName(QString::number(networkid)); + _synchronizer = new Synchronizer(this, proxy); +} + +// I think this is unnecessary since IrcUsers have us as their daddy :) +// NetworkInfo::~NetworkInfo() { +// QHashIterator ircuser(_ircUsers); +// while (ircuser.hasNext()) { +// ircuser.next(); +// delete ircuser.value(); +// } +// } + +uint NetworkInfo::networkId() const { + return _networkId; +} + +bool NetworkInfo::initialized() const { + return _initialized; +} + +Synchronizer *NetworkInfo::synchronizer() { + return _synchronizer; +} + +bool NetworkInfo::isMyNick(const QString &nick) const { + return (myNick().toLower() == nick.toLower()); +} + +bool NetworkInfo::isMyNick(IrcUser *ircuser) const { + return (ircuser->nick().toLower() == myNick()); +} + +bool NetworkInfo::isChannelName(const QString &channelname) const { + if(channelname.isEmpty()) + return false; + + if(supports("CHANTYPES")) + return support("CHANTYPES").contains(channelname[0]); + else + return QString("#&!+").contains(channelname[0]); +} + +QString NetworkInfo::prefixToMode(const QString &prefix) { + if(prefixes().contains(prefix)) + return QString(prefixModes()[prefixes().indexOf(prefix)]); + else + return QString(); +} + +QString NetworkInfo::prefixToMode(const QCharRef &prefix) { + return prefixToMode(QString(prefix)); +} + +QString NetworkInfo::modeToPrefix(const QString &mode) { + if(prefixModes().contains(mode)) + return QString(prefixes()[prefixModes().indexOf(mode)]); + else + return QString(); +} + +QString NetworkInfo::modeToPrefix(const QCharRef &mode) { + return modeToPrefix(QString(mode)); +} + +QString NetworkInfo::networkName() const { + return _networkName; +} + +QString NetworkInfo::currentServer() const { + return _currentServer; +} + +QString NetworkInfo::myNick() const { + return _myNick; +} + +QStringList NetworkInfo::nicks() const { + // we don't use _ircUsers.keys() since the keys may be + // not up to date after a nick change + QStringList nicks; + foreach(IrcUser *ircuser, _ircUsers.values()) { + nicks << ircuser->nick(); + } + return nicks; +} + +QStringList NetworkInfo::channels() const { + return _ircChannels.keys(); +} + +QString NetworkInfo::prefixes() { + if(_prefixes.isNull()) + determinePrefixes(); + + return _prefixes; +} + +QString NetworkInfo::prefixModes() { + if(_prefixModes.isNull()) + determinePrefixes(); + + return _prefixModes; +} + +bool NetworkInfo::supports(const QString ¶m) const { + return _supports.contains(param); +} + +QString NetworkInfo::support(const QString ¶m) const { + QString support_ = param.toUpper(); + if(_supports.contains(support_)) + return _supports[support_]; + else + return QString(); +} + +IrcUser *NetworkInfo::newIrcUser(const QString &hostmask) { + QString nick(nickFromMask(hostmask)); + if(!_ircUsers.contains(nick)) { + IrcUser *ircuser = new IrcUser(hostmask, this); + new Synchronizer(ircuser, synchronizer()->proxy()); + connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString))); + connect(ircuser, SIGNAL(initDone()), this, SIGNAL(ircUserInitDone())); + connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed())); + _ircUsers[nick] = ircuser; + emit ircUserAdded(hostmask); + } + return _ircUsers[nick]; +} + +IrcUser *NetworkInfo::ircUser(const QString &nickname) const { + if(_ircUsers.contains(nickname)) + return _ircUsers[nickname]; + else + return 0; +} + +QList NetworkInfo::ircUsers() const { + return _ircUsers.values(); +} + +IrcChannel *NetworkInfo::newIrcChannel(const QString &channelname) { + if(!_ircChannels.contains(channelname)) { + IrcChannel *channel = new IrcChannel(channelname, this); + new Synchronizer(channel, synchronizer()->proxy()); + connect(channel, SIGNAL(initDone()), this, SIGNAL(ircChannelInitDone())); + connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed())); + _ircChannels[channelname] = channel; + emit ircChannelAdded(channelname); + } + return _ircChannels[channelname]; +} + + +IrcChannel *NetworkInfo::ircChannel(const QString &channelname) { + if(_ircChannels.contains(channelname)) + return _ircChannels[channelname]; + else + return 0; +} + +QList NetworkInfo::ircChannels() const { + return _ircChannels.values(); +} + +// ==================== +// Public Slots: +// ==================== +void NetworkInfo::setNetworkName(const QString &networkName) { + _networkName = networkName; + emit networkNameSet(networkName); +} + +void NetworkInfo::setCurrentServer(const QString ¤tServer) { + _currentServer = currentServer; + emit currentServerSet(currentServer); +} + +void NetworkInfo::setMyNick(const QString &nickname) { + _myNick = nickname; + emit myNickSet(nickname); +} + +void NetworkInfo::addSupport(const QString ¶m, const QString &value) { + if(!_supports.contains(param)) { + _supports[param] = value; + emit supportAdded(param, value); + } +} + +void NetworkInfo::removeSupport(const QString ¶m) { + if(_supports.contains(param)) { + _supports.remove(param); + emit supportRemoved(param); + } +} + +QVariantMap NetworkInfo::initSupports() const { + QVariantMap supports; + QHashIterator iter(_supports); + while(iter.hasNext()) { + iter.next(); + supports[iter.key()] = iter.value(); + } + return supports; +} + +QStringList NetworkInfo::initIrcUsers() const { + QStringList hostmasks; + foreach(IrcUser *ircuser, ircUsers()) { + hostmasks << ircuser->hostmask(); + } + return hostmasks; +} + +QStringList NetworkInfo::initIrcChannels() const { + return _ircChannels.keys(); +} + +void NetworkInfo::initSetSupports(const QVariantMap &supports) { + QMapIterator iter(supports); + while(iter.hasNext()) { + iter.next(); + addSupport(iter.key(), iter.value().toString()); + } +} + +void NetworkInfo::initSetIrcUsers(const QStringList &hostmasks) { + if(!_ircUsers.empty()) + return; + foreach(QString hostmask, hostmasks) { + newIrcUser(hostmask); + } +} + +void NetworkInfo::initSetChannels(const QStringList &channels) { + if(!_ircChannels.empty()) + return; + foreach(QString channel, channels) + newIrcChannel(channel); +} + +IrcUser *NetworkInfo::updateNickFromMask(const QString &mask) { + QString nick(nickFromMask(mask)); + IrcUser *ircuser; + + if(_ircUsers.contains(nick)) { + ircuser = _ircUsers[nick]; + ircuser->updateHostmask(mask); + } else { + ircuser = newIrcUser(mask); + } + return ircuser; +} + +void NetworkInfo::ircUserNickChanged(QString newnick) { + QString oldnick = _ircUsers.key(qobject_cast(sender())); + if(oldnick.isNull()) + return; + + _ircUsers[newnick] = _ircUsers.take(oldnick); + + if(myNick() == oldnick) + setMyNick(newnick); +} + +void NetworkInfo::ircUserDestroyed() { + IrcUser *ircuser = qobject_cast(sender()); + QHash::iterator i = _ircUsers.begin(); + while(i != _ircUsers.end()) { + if(i.value() == ircuser) { + i = _ircUsers.erase(i); + } else { + i++; + } + } +} + +void NetworkInfo::channelDestroyed() { + IrcChannel *channel = qobject_cast(sender()); + QHash::iterator i = _ircChannels.begin(); + while(i != _ircChannels.end()) { + if(i.value() == channel) { + i = _ircChannels.erase(i); + } else { + i++; + } + } +} + +void NetworkInfo::setInitialized() { + _initialized = true; + emit initDone(); +} + +// ==================== +// Private: +// ==================== +void NetworkInfo::determinePrefixes() { + // seems like we have to construct them first + QString PREFIX = support("PREFIX"); + + if(PREFIX.startsWith("(") && PREFIX.contains(")")) { + _prefixes = PREFIX.section(")", 1); + _prefixModes = PREFIX.mid(1).section(")", 0, 0); + } else { + QString defaultPrefixes("@%+"); + QString defaultPrefixModes("ohv"); + + // we just assume that in PREFIX are only prefix chars stored + for(int i = 0; i < defaultPrefixes.size(); i++) { + if(PREFIX.contains(defaultPrefixes[i])) { + _prefixes += defaultPrefixes[i]; + _prefixModes += defaultPrefixModes[i]; + } + } + // check for success + if(!_prefixes.isNull()) + return; + + // well... our assumption was obviously wrong... + // check if it's only prefix modes + for(int i = 0; i < defaultPrefixes.size(); i++) { + if(PREFIX.contains(defaultPrefixModes[i])) { + _prefixes += defaultPrefixes[i]; + _prefixModes += defaultPrefixModes[i]; + } + } + // now we've done all we've could... + } +} + diff --git a/src/common/networkinfo.h b/src/common/networkinfo.h new file mode 100644 index 00000000..6f2ab482 --- /dev/null +++ b/src/common/networkinfo.h @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _NETWORKINFO_H_ +#define _NETWORKINFO_H_ + +#include +#include +#include +#include +#include +#include + +class SignalProxy; +class Synchronizer; +class IrcUser; +class IrcChannel; + + +class NetworkInfo : public QObject { + Q_OBJECT + + Q_PROPERTY(QString networkName READ networkName WRITE setNetworkName STORED false) + Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer STORED false) + Q_PROPERTY(QString myNick READ myNick WRITE setMyNick STORED false) + +public: + NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent = 0); + // virtual ~NetworkInfo(); + + uint networkId() const; + bool initialized() const; + Synchronizer *synchronizer(); + + bool isMyNick(const QString &nick) const; + bool isMyNick(IrcUser *ircuser) const; + + bool isChannelName(const QString &channelname) const; + + QString prefixToMode(const QString &prefix); + QString prefixToMode(const QCharRef &prefix); + QString modeToPrefix(const QString &mode); + QString modeToPrefix(const QCharRef &mode); + + QString networkName() const; + QString currentServer() const; + QString myNick() const; + QStringList nicks() const; + QStringList channels() const; + + QString prefixes(); + QString prefixModes(); + + bool supports(const QString ¶m) const; + QString support(const QString ¶m) const; + + IrcUser *newIrcUser(const QString &hostmask); + IrcUser *ircUser(const QString &nickname) const; + QList ircUsers() const; + + IrcChannel *newIrcChannel(const QString &channelname); + IrcChannel *ircChannel(const QString &channelname); + QList ircChannels() const; + +public slots: + void setNetworkName(const QString &networkName); + void setCurrentServer(const QString ¤tServer); + void setMyNick(const QString &mynick); + + void addSupport(const QString ¶m, const QString &value = QString()); + void removeSupport(const QString ¶m); + + inline void addIrcUser(const QString &hostmask) { newIrcUser(hostmask); } + + //init geters + QVariantMap initSupports() const; + QStringList initIrcUsers() const; + QStringList initIrcChannels() const; + + //init seters + void initSetSupports(const QVariantMap &supports); + void initSetIrcUsers(const QStringList &hostmasks); + void initSetChannels(const QStringList &channels); + + IrcUser *updateNickFromMask(const QString &mask); + + // these slots are to keep the hashlists of all users and the + // channel lists up to date + void ircUserNickChanged(QString newnick); + + void ircUserDestroyed(); + void channelDestroyed(); + + void setInitialized(); + +signals: + void networkNameSet(const QString &networkName); + void currentServerSet(const QString ¤tServer); + void myNickSet(const QString &mynick); + + void supportAdded(const QString ¶m, const QString &value = QString()); + void supportRemoved(const QString ¶m); + + void ircUserAdded(QString hostmask); + void ircChannelAdded(QString channelname); + + void initDone(); + void ircUserInitDone(); + void ircChannelInitDone(); + +private: + uint _networkId; + bool _initialized; + + QString _myNick; + QString _networkName; + QString _currentServer; + + QString _prefixes; + QString _prefixModes; + + QHash _ircUsers; // stores all known nicks for the server + QHash _ircChannels; // stores all known channels + QHash _supports; // stores results from RPL_ISUPPORT + + //QVariantMap networkSettings; + //QVariantMap identity; + + QPointer _synchronizer; + + void determinePrefixes(); +}; + +#endif diff --git a/src/common/signalproxy.h b/src/common/signalproxy.h index 2f68f944..3e7136ad 100644 --- a/src/common/signalproxy.h +++ b/src/common/signalproxy.h @@ -34,6 +34,7 @@ class SignalProxy : public QObject { SignalProxy(ProxyType type, QIODevice *device = 0, QObject *parent = 0); ~SignalProxy(); + ProxyType proxyType() const { return type; } void attachSignal(QObject* sender, const char* signal, const QByteArray& rpcFunction = QByteArray()); void attachSlot(const QByteArray& rpcFunction, QObject* recv, const char* slot); diff --git a/src/common/synchronizer.cpp b/src/common/synchronizer.cpp new file mode 100644 index 00000000..8c294007 --- /dev/null +++ b/src/common/synchronizer.cpp @@ -0,0 +1,343 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "synchronizer.h" + +#include +#include +#include +#include + +#include "util.h" +#include "signalproxy.h" + +#include +#include + +// ==================== +// Public: +// ==================== +Synchronizer::Synchronizer(QObject *parent, SignalProxy *signalproxy) + : QObject(parent), + _initialized(false), + _signalproxy(signalproxy) +{ + attach(); + if(!getMethodByName("objectNameSet()").isEmpty()) + connect(parent,SIGNAL(objectNameSet()), this, SLOT(parentChangedName())); +} + +bool Synchronizer::initialized() const { + return _initialized; +} + +SignalProxy *Synchronizer::proxy() const { + return _signalproxy; +} + +QVariantMap Synchronizer::initData() const { + QVariantMap properties; + + // we collect data from properties + foreach(QMetaProperty property, parentProperties()) { + QString name = QString(property.name()); + QVariant value = property.read(parent()); + properties[name] = value; + // qDebug() << ">>> SYNC:" << name << value; + } + + // ...as well as methods, which have names starting with "init" + foreach(QMetaMethod method, parentSlots()) { + QString methodname = QString(method.signature()).section("(", 0, 0); + if(methodname.startsWith("initSet") || + !methodname.startsWith("init")) + continue; + + QVariant value = QVariant(QVariant::nameToType(method.typeName())); + QGenericReturnArgument genericvalue = QGenericReturnArgument(method.typeName(), &value); + QMetaObject::invokeMethod(parent(), methodname.toAscii(), genericvalue); + + properties[methodBaseName(method)] = value; + // qDebug() << ">>> SYNC:" << methodBaseName(method) << value; + } + + // properties["Payload"] = QByteArray(10000000, 'a'); // for testing purposes + return properties; +} + +void Synchronizer::setInitData(const QVariantMap &properties) { + if(initialized()) + return; + + const QMetaObject *metaobject = parent()->metaObject(); + QMapIterator iterator(properties); + while(iterator.hasNext()) { + iterator.next(); + QString name = iterator.key(); + int propertyIndex = metaobject->indexOfProperty(name.toAscii()); + if(propertyIndex == -1) { + setInitValue(name, iterator.value()); + } else { + if((metaobject->property(propertyIndex)).isWritable()) + parent()->setProperty(name.toAscii(), iterator.value()); + else + setInitValue(name, iterator.value()); + } + // qDebug() << "<<< SYNC:" << name << iterator.value(); + } + + _initialized = true; + emit initDone(); +} + +// ==================== +// Public Slots +// ==================== +void Synchronizer::synchronizeClients() const { + emit sendInitData(initData()); +} + +void Synchronizer::recvInitData(QVariantMap properties) { + proxy()->detachObject(this); + setInitData(properties); +} + +void Synchronizer::parentChangedName() { + proxy()->detachObject(parent()); + proxy()->detachObject(this); + attach(); + if(proxy()->proxyType() == SignalProxy::Client && initialized()) + proxy()->detachObject(this); +} + +// ==================== +// Private +// ==================== +QString Synchronizer::signalPrefix() const { + return QString(parent()->metaObject()->className()) + "_" + QString(parent()->objectName()) + "_"; +} + +QString Synchronizer::initSignal() const { + return QString(metaObject()->className()) + + "_" + QString(parent()->metaObject()->className()) + + "_" + QString(parent()->objectName()) + + "_" + QString(SIGNAL(sendInitData(QVariantMap))); +} + +QString Synchronizer::requestSyncSignal() const { + return QString(metaObject()->className()) + + "_" + QString(parent()->metaObject()->className()) + + "_" + QString(parent()->objectName()) + + "_" + QString(SIGNAL(requestSync())); +} + +QString Synchronizer::methodBaseName(const QMetaMethod &method) const { + QString methodname = QString(method.signature()).section("(", 0, 0); + + // determine where we have to chop: + if(method.methodType() == QMetaMethod::Slot) { + // we take evertyhing from the first uppercase char if it's slot + methodname = methodname.mid(methodname.indexOf(QRegExp("[A-Z]"))); + } else { + // and if it's a signal we discard everything from the last uppercase char + methodname = methodname.left(methodname.lastIndexOf(QRegExp("[A-Z]"))); + } + + methodname[0] = methodname[0].toUpper(); + + return methodname; +} + +bool Synchronizer::methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const { + // if we don't even have the same basename it's a sure NO + if(methodBaseName(signal) != methodBaseName(slot)) + return false; + + const QMetaObject *metaobject = parent()->metaObject(); + + // are the signatures compatible? + if(! metaobject->checkConnectArgs(signal.signature(), slot.signature())) + return false; + + // we take an educated guess if the signals and slots match + QString signalsuffix = QString(signal.signature()).section("(", 0, 0); + signalsuffix = signalsuffix.mid(signalsuffix.lastIndexOf(QRegExp("[A-Z]"))).toLower(); + + QString slotprefix = QString(slot.signature()).section("(", 0, 0); + slotprefix = slotprefix.left(slotprefix.indexOf(QRegExp("[A-Z]"))).toLower(); + + uint sizediff; + if(signalsuffix.size() < slotprefix.size()) + sizediff = slotprefix.size() - signalsuffix.size(); + else + sizediff = signalsuffix.size() - slotprefix.size(); + + int ratio = editingDistance(slotprefix, signalsuffix) - sizediff; + + return (ratio < 2); +} + +QList Synchronizer::parentProperties() const { + QList _properties; + + const QMetaObject *metaobject = parent()->metaObject(); + for(int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); i++) { + _properties << metaobject->property(i); + } + + return _properties; +} + +QList Synchronizer::parentSlots() const { + QList _slots; + + const QMetaObject *metaobject = parent()->metaObject(); + for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) { + QMetaMethod method = metaobject->method(i); + if(method.methodType() == QMetaMethod::Slot) + _slots << method; + } + + return _slots; +} + + +QList Synchronizer::parentSignals() const { + QList _signals; + + const QMetaObject *metaobject = parent()->metaObject(); + for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) { + QMetaMethod method = metaobject->method(i); + if(method.methodType() == QMetaMethod::Signal) + _signals << method; + } + + return _signals; +} + +QList Synchronizer::getMethodByName(const QString &methodname) { + QList _methods; + + const QMetaObject* metaobject = parent()->metaObject(); + for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) { + if(QString(metaobject->method(i).signature()).startsWith(methodname)) + _methods << metaobject->method(i); + } + + return _methods; +} + +void Synchronizer::attach() { + if(proxy()->proxyType() == SignalProxy::Server) + attachAsMaster(); + else + attachAsSlave(); +} + +void Synchronizer::attachAsSlave() { + QList signals_ = parentSignals(); + + foreach(QMetaMethod slot, parentSlots()) { + if(signals_.empty()) + break; + + for(int i = 0; i < signals_.count(); i++) { + QMetaMethod signal = signals_[i]; + if(!methodsMatch(signal, slot)) + continue; + + // we could simply put a "1" in front of the normalized signature + // but to guarantee future compatibility we construct a dummy signal + // and replace the known the fake signature by ours... + QString dummySlot = QString(SIGNAL(dummy())); + QString proxySignal = signalPrefix() + QString(signal.signature()); + QString slotsignature = dummySlot.replace("dummy()", QString(slot.signature())); + + // qDebug() << "attachSlot:" << proxySignal << slotsignature; + proxy()->attachSlot(proxySignal.toAscii(), parent(), slotsignature.toAscii()); + signals_.removeAt(i); + break; + } + } + + // and then we connect ourself, so we can receive init data + // qDebug() << "attachSlot:" << initSignal() << "recvInitData(QVariantMap)"; + // qDebug() << "attachSignal:" << "requestSync()" << requestSyncSignal(); + proxy()->attachSlot(initSignal().toAscii(), this, SLOT(recvInitData(QVariantMap))); + proxy()->attachSignal(this, SIGNAL(requestSync()), requestSyncSignal().toAscii()); + + if(!getMethodByName("setInitialized()").isEmpty()) + connect(this, SIGNAL(initDone()), parent(), SLOT(setInitialized())); + + emit requestSync(); +} + +void Synchronizer::attachAsMaster() { + QList slots_ = parentSlots(); + + foreach(QMetaMethod signal, parentSignals()) { + if(slots_.isEmpty()) + break; + + // we don't attach all signals, just the ones that have a maching counterpart + for(int i = 0; i < slots_.count(); i++) { + QMetaMethod slot = slots_[i]; + if(!methodsMatch(signal, slot)) + continue; + + // we could simply put a "2" in front of the normalized signature + // but to guarantee future compatibility we construct a dummy signal + // and replace the known the fake signature by ours... + QString dummySignal = QString(SIGNAL(dummy())); + QString proxySignal = signalPrefix() + QString(signal.signature()); + QString signalsignature = dummySignal.replace("dummy()", QString(signal.signature())); + + // qDebug() << "attachSignal:" << signalsignature << proxySignal; + proxy()->attachSignal(parent(), signalsignature.toAscii(), proxySignal.toAscii()); + slots_.removeAt(i); + break; + } + } + + // and then we connect ourself, so we can initialize slaves + // qDebug() << "attachSignal:" << "sendInitData(QVariantMap)" << initSignal(); + // qDebug() << "attachSlot:" << "synchronizeClients()" << requestSyncSignal(); + proxy()->attachSignal(this, SIGNAL(sendInitData(QVariantMap)), initSignal().toAscii()); + proxy()->attachSlot(requestSyncSignal().toAscii(), this, SLOT(synchronizeClients())); +} + +bool Synchronizer::setInitValue(const QString &property, const QVariant &value) { + QString handlername = QString("initSet") + property; + handlername[7] = handlername[7].toUpper(); + + //determine param type + QByteArray paramtype; + foreach(QMetaMethod method, getMethodByName(handlername)) { + if(method.parameterTypes().size() == 1) { + paramtype = method.parameterTypes()[0]; + break; + } + } + + if(paramtype.isNull()) + return false; + + QGenericArgument param = QGenericArgument(paramtype, &value); + return QMetaObject::invokeMethod(parent(), handlername.toAscii(), param); +} diff --git a/src/common/synchronizer.h b/src/common/synchronizer.h new file mode 100644 index 00000000..97453b29 --- /dev/null +++ b/src/common/synchronizer.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _SYNCHRONIZER_H_ +#define _SYNCHRONIZER_H_ + +class SignalProxy; + +#include ; +#include ; +#include ; +#include ; +#include ; +#include + +class Synchronizer : public QObject { + Q_OBJECT + +public: + Synchronizer(QObject *parent, SignalProxy *signalproxy); + + bool initialized() const; + SignalProxy *proxy() const; + + QVariantMap initData() const; + void setInitData(const QVariantMap &properties); + +public slots: + void synchronizeClients() const; + void recvInitData(QVariantMap properties); + void parentChangedName(); + +signals: + void requestSync() const; + void sendInitData(QVariantMap properties) const; + void initDone(); + +private: + bool _initialized; + QPointer _signalproxy; + + QString signalPrefix() const; + QString initSignal() const; + QString requestSyncSignal() const; + + QString methodBaseName(const QMetaMethod &method) const; + bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const; + + QList parentProperties() const; + QList parentSlots() const; + QList parentSignals() const; + + QList getMethodByName(const QString &methodname); + + void attach(); + void attachAsSlave(); + void attachAsMaster(); + + bool setInitValue(const QString &property, const QVariant &value); +}; + +#endif diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cc12ff7c..c9f715f3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,6 @@ -SET(core_SRCS core.cpp coresession.cpp server.cpp serverinfo.cpp sqlitestorage.cpp storage.cpp) +SET(core_SRCS core.cpp coresession.cpp server.cpp basichandler.cpp ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp sqlitestorage.cpp storage.cpp) SET(core_HDRS ) -SET(core_MOCS core.h coresession.h server.h serverinfo.h sqlitestorage.h storage.h) +SET(core_MOCS core.h coresession.h server.h basichandler.h ircserverhandler.h userinputhandler.h ctcphandler.h sqlitestorage.h storage.h) QT4_WRAP_CPP(_MOC ${core_MOCS}) ADD_LIBRARY(core ${core_SRCS} ${_MOC}) diff --git a/src/core/basichandler.cpp b/src/core/basichandler.cpp new file mode 100644 index 00000000..87c7e085 --- /dev/null +++ b/src/core/basichandler.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "basichandler.h" + +#include + +#include "server.h" + +BasicHandler::BasicHandler(Server *parent) + : QObject(parent), + server(parent) { + + connect(this, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), + server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8))); + + connect(this, SIGNAL(putCmd(QString, QStringList, QString)), + server, SLOT(putCmd(QString, QStringList, QString))); + + connect(this, SIGNAL(putRawLine(QString)), + server, SLOT(putRawLine(QString))); +} + +QStringList BasicHandler::providesHandlers() const { + QStringList handlers; + for(int i=0; i < metaObject()->methodCount(); i++) { + QString methodSignature(metaObject()->method(i).signature()); + if(!methodSignature.startsWith("handle")) + continue; + + methodSignature = methodSignature.section('(',0,0); // chop the attribute list + methodSignature = methodSignature.mid(6); // strip "handle" + handlers << methodSignature; + } + return handlers; +} + + +void BasicHandler::handle(const QString &member, const QGenericArgument &val0, + const QGenericArgument &val1, const QGenericArgument &val2, + const QGenericArgument &val3, const QGenericArgument &val4, + const QGenericArgument &val5, const QGenericArgument &val6, + const QGenericArgument &val7, const QGenericArgument &val8) { + + // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-) + QString handler = member.toLower(); + handler[0] = handler[0].toUpper(); + handler = "handle" + handler; + + if(!QMetaObject::invokeMethod(this, handler.toAscii(), val0, val1, val2, val3, val4, val5, val6, val7, val8)) + // Ok. Default handler it is. + QMetaObject::invokeMethod(this, "defaultHandler", Q_ARG(QString, member), val0, val1, val2, val3, val4, val5, val6, val7, val8); + +} + +// ==================== +// protected: +// ==================== +NetworkInfo *BasicHandler::networkInfo() const { + return server->networkInfo(); +} diff --git a/src/core/basichandler.h b/src/core/basichandler.h new file mode 100644 index 00000000..61a3f2e9 --- /dev/null +++ b/src/core/basichandler.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _BASICHANDLER_H_ +#define _BASICHANDLER_H_ + +#include +#include +#include +#include + +#include "message.h" + +class Server; +class NetworkInfo; + +class BasicHandler : public QObject { + Q_OBJECT + +public: + BasicHandler(Server *parent = 0); + + QStringList providesHandlers() const; + +signals: + void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void putCmd(QString cmd, QStringList params, QString prefix = 0); + void putRawLine(QString msg); + +protected: + virtual void handle(const QString &member, const QGenericArgument &val0 = QGenericArgument(0), + const QGenericArgument &val1 = QGenericArgument(), const QGenericArgument &val2 = QGenericArgument(), + const QGenericArgument &val3 = QGenericArgument(), const QGenericArgument &val4 = QGenericArgument(), + const QGenericArgument &val5 = QGenericArgument(), const QGenericArgument &val6 = QGenericArgument(), + const QGenericArgument &val7 = QGenericArgument(), const QGenericArgument &val8 = QGenericArgument()); + + Server *server; + + +protected: + NetworkInfo *networkInfo() const; + +}; +#endif diff --git a/src/core/core.cpp b/src/core/core.cpp index 5159f93a..7b576618 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -25,7 +25,7 @@ Core *Core::instanceptr = 0; -Core * Core::instance() { +Core *Core::instance() { if(instanceptr) return instanceptr; instanceptr = new Core(); instanceptr->init(); @@ -38,7 +38,6 @@ void Core::destroy() { } Core::Core() { - } void Core::init() { @@ -121,7 +120,7 @@ void Core::clientHasData() { return; } } - blockSizes[socket] = bsize = 0; // FIXME blockSizes aufräum0rn! + blockSizes[socket] = bsize = 0; // FIXME blockSizes aufräum0rn! } // FIXME: no longer called, since connection handling is now in SignalProxy @@ -163,10 +162,10 @@ void Core::processClientInit(QTcpSocket *socket, const QVariant &v) { QVariant Core::initSession(UserId uid) { // Find or create session for validated user CoreSession *sess; - if(sessions.contains(uid)) sess = sessions[uid]; - else { + if(sessions.contains(uid)) + sess = sessions[uid]; + else sess = createSession(uid); - } QVariantMap reply; reply["SessionState"] = sess->sessionState(); return reply; diff --git a/src/core/core.pri b/src/core/core.pri index 03c1b8c5..32427c17 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -1,4 +1,4 @@ DEPMOD = common contrib/qxt QT_MOD = core network sql -SRCS = core.cpp coresession.cpp server.cpp serverinfo.cpp sqlitestorage.cpp storage.cpp -HDRS = core.h coresession.h server.h serverinfo.h sqlitestorage.h storage.h +SRCS = core.cpp coresession.cpp server.cpp sqlitestorage.cpp storage.cpp basichandler.cpp ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp +HDRS = core.h coresession.h server.h sqlitestorage.h storage.h basichandler.h ircserverhandler.h userinputhandler.h ctcphandler.h diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index bdd2978d..28a074f5 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -20,12 +20,24 @@ #include "coresession.h" #include "server.h" + #include "signalproxy.h" #include "storage.h" + +#include "synchronizer.h" +#include "networkinfo.h" +#include "ircuser.h" +#include "ircchannel.h" + #include "util.h" -CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) : QObject(parent), user(uid), storage(_storage) { - _signalProxy = new SignalProxy(SignalProxy::Server, 0, this); + +CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) + : QObject(parent), + user(uid), + _signalProxy(new SignalProxy(SignalProxy::Server, 0, this)), + storage(_storage) +{ QSettings s; s.beginGroup(QString("SessionData/%1").arg(user)); @@ -37,17 +49,16 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) : QObje SignalProxy *p = signalProxy(); - p->attachSlot(SIGNAL(requestNetworkStates()), this, SIGNAL(serverStateRequested())); + p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(serverStateRequested())); p->attachSlot(SIGNAL(requestConnect(QString)), this, SLOT(connectToNetwork(QString))); - p->attachSlot(SIGNAL(sendInput(BufferId, QString)), this, SLOT(msgFromGui(BufferId, QString))); + p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromGui(BufferInfo, QString))); p->attachSlot(SIGNAL(importOldBacklog()), storage, SLOT(importOldBacklog())); - p->attachSlot(SIGNAL(requestBacklog(BufferId, QVariant, QVariant)), this, SLOT(sendBacklog(BufferId, QVariant, QVariant))); - p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(sendServerStates())); + p->attachSlot(SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)), this, SLOT(sendBacklog(BufferInfo, QVariant, QVariant))); p->attachSignal(this, SIGNAL(displayMsg(Message))); p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString))); - p->attachSignal(this, SIGNAL(backlogData(BufferId, QVariantList, bool))); - p->attachSignal(this, SIGNAL(bufferIdUpdated(BufferId))); - p->attachSignal(storage, SIGNAL(bufferIdUpdated(BufferId))); + p->attachSignal(this, SIGNAL(backlogData(BufferInfo, QVariantList, bool))); + p->attachSignal(this, SIGNAL(bufferInfoUpdated(BufferInfo))); + p->attachSignal(storage, SIGNAL(bufferInfoUpdated(BufferInfo))); p->attachSignal(this, SIGNAL(sessionDataChanged(const QString &, const QVariant &)), SIGNAL(coreSessionDataChanged(const QString &, const QVariant &))); p->attachSlot(SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)), this, SLOT(storeSessionData(const QString &, const QVariant &))); /* Autoconnect. (When) do we actually do this? @@ -63,7 +74,6 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) : QObje } CoreSession::~CoreSession() { - } UserId CoreSession::userId() const { @@ -91,41 +101,36 @@ QVariant CoreSession::retrieveSessionData(const QString &key, const QVariant &de return data; } +// FIXME switch to NetworkIDs void CoreSession::connectToNetwork(QString network) { - QStringList networks; networks << network; // FIXME obsolete crap - foreach(QString net, networks) { - if(servers.contains(net)) { - - } else { - Server *server = new Server(userId(), net); - connect(this, SIGNAL(serverStateRequested()), server, SLOT(sendState())); - 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(connected(QString)), this, SLOT(serverConnected(QString))); - connect(server, SIGNAL(disconnected(QString)), this, SLOT(serverDisconnected(QString))); - connect(server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8))); - connect(server, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString))); - - SignalProxy *p = signalProxy(); - p->attachSignal(server, SIGNAL(serverState(QString, QVariantMap)), SIGNAL(networkState(QString, QVariantMap))); - p->attachSignal(server, SIGNAL(modeSet(QString, QString, QString))); - p->attachSignal(server, SIGNAL(nickAdded(QString, QString, QVariantMap))); - p->attachSignal(server, SIGNAL(nickRenamed(QString, QString, QString))); - p->attachSignal(server, SIGNAL(nickRemoved(QString, QString))); - p->attachSignal(server, SIGNAL(nickUpdated(QString, QString, QVariantMap))); - p->attachSignal(server, SIGNAL(ownNickSet(QString, QString))); - p->attachSignal(server, SIGNAL(queryRequested(QString, QString))); - // TODO add error handling - p->attachSignal(server, SIGNAL(connected(QString)), SIGNAL(networkConnected(QString))); - p->attachSignal(server, SIGNAL(disconnected(QString)), SIGNAL(networkDisconnected(QString))); - - server->start(); - servers[net] = server; - } - emit connectToIrc(net); + uint networkid = getNetworkId(network); + if(!servers.contains(networkid)) { + Server *server = new Server(userId(), networkid, network); + attachServer(server); + server->start(); + servers[networkid] = server; } + emit connectToIrc(network); +} + +void CoreSession::attachServer(Server *server) { + connect(this, SIGNAL(connectToIrc(QString)), server, SLOT(connectToIrc(QString))); + connect(this, SIGNAL(disconnectFromIrc(QString)), server, SLOT(disconnectFromIrc(QString))); + connect(this, SIGNAL(msgFromGui(uint, QString, QString)), server, SLOT(userInput(uint, QString, QString))); + + connect(server, SIGNAL(connected(uint)), this, SLOT(serverConnected(uint))); + connect(server, SIGNAL(disconnected(uint)), this, SLOT(serverDisconnected(uint))); + connect(server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8))); + connect(server, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString))); + + // connect serversignals to proxy + signalProxy()->attachSignal(server, SIGNAL(serverState(QString, QVariantMap)), SIGNAL(networkState(QString, QVariantMap))); + signalProxy()->attachSignal(server, SIGNAL(connected(uint)), SIGNAL(networkConnected(uint))); + signalProxy()->attachSignal(server, SIGNAL(disconnected(uint)), SIGNAL(networkDisconnected(uint))); + // TODO add error handling +} + +void CoreSession::serverStateRequested() { } void CoreSession::addClient(QIODevice *device) { @@ -136,31 +141,29 @@ SignalProxy *CoreSession::signalProxy() const { return _signalProxy; } -void CoreSession::serverConnected(QString net) { - storage->getBufferId(userId(), net); // create status buffer +void CoreSession::serverConnected(uint networkid) { + storage->getBufferInfo(userId(), servers[networkid]->networkName()); // create status buffer } -void CoreSession::serverDisconnected(QString net) { - delete servers[net]; - servers.remove(net); - signalProxy()->sendSignal(SIGNAL(networkDisconnected(QString)), net); // FIXME does this work? +void CoreSession::serverDisconnected(uint networkid) { + servers.remove(networkid); + delete servers[networkid]; } -void CoreSession::msgFromGui(BufferId bufid, QString msg) { - emit msgFromGui(bufid.network(), bufid.buffer(), msg); +void CoreSession::msgFromGui(BufferInfo bufid, QString msg) { + emit msgFromGui(bufid.networkId(), bufid.buffer(), msg); } // ALL messages coming pass through these functions before going to the GUI. // So this is the perfect place for storing the backlog and log stuff. - void CoreSession::recvMessageFromServer(Message::Type type, QString target, QString text, QString sender, quint8 flags) { Server *s = qobject_cast(this->sender()); Q_ASSERT(s); - BufferId buf; + BufferInfo buf; if((flags & Message::PrivMsg) && !(flags & Message::Self)) { - buf = storage->getBufferId(user, s->getNetwork(), nickFromMask(sender)); + buf = storage->getBufferInfo(user, s->networkName(), nickFromMask(sender)); } else { - buf = storage->getBufferId(user, s->getNetwork(), target); + buf = storage->getBufferInfo(user, s->networkName(), target); } Message msg(buf, type, text, sender, flags); msg.setMsgId(storage->logMessage(msg)); @@ -171,33 +174,41 @@ void CoreSession::recvMessageFromServer(Message::Type type, QString target, QStr void CoreSession::recvStatusMsgFromServer(QString msg) { Server *s = qobject_cast(sender()); Q_ASSERT(s); - emit displayStatusMsg(s->getNetwork(), msg); + emit displayStatusMsg(s->networkName(), msg); } -QList CoreSession::buffers() const { +uint CoreSession::getNetworkId(const QString &net) const { + return storage->getNetworkId(user, net); +} + +QList CoreSession::buffers() const { return storage->requestBuffers(user); } QVariant CoreSession::sessionState() { QVariantMap v; - QList bufs; - foreach(BufferId id, storage->requestBuffers(user)) { bufs.append(QVariant::fromValue(id)); } + + QVariantList bufs; + foreach(BufferInfo id, storage->requestBuffers(user)) + bufs.append(QVariant::fromValue(id)); v["Buffers"] = bufs; + mutex.lock(); v["SessionData"] = sessionData; mutex.unlock(); - v["Networks"] = QVariant(servers.keys()); + + QVariantList networks; + foreach(uint networkid, servers.keys()) + networks.append(QVariant(networkid)); + v["Networks"] = QVariant(networks); + // v["Payload"] = QByteArray(100000000, 'a'); // for testing purposes return v; } -void CoreSession::sendServerStates() { - emit serverStateRequested(); -} - -void CoreSession::sendBacklog(BufferId id, QVariant v1, QVariant v2) { +void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) { QList log; QList msglist; if(v1.type() == QVariant::DateTime) { diff --git a/src/core/coresession.h b/src/core/coresession.h index 66e27354..009a2ef2 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -34,63 +34,65 @@ class Storage; class CoreSession : public QObject { Q_OBJECT - public: - CoreSession(UserId, Storage *, QObject *parent = 0); - ~CoreSession(); - - QList buffers() const; - UserId userId() const; - QVariant sessionState(); - - public slots: - //! Store a piece session-wide data and distribute it to connected clients. - void storeSessionData(const QString &key, const QVariant &data); - - void addClient(QIODevice *connection); - - public: - //! Retrieve a piece of session-wide data. - QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant()); - - SignalProxy *signalProxy() const; - - public slots: - void connectToNetwork(QString); - //void processSignal(ClientSignal, QVariant, QVariant, QVariant); - void sendBacklog(BufferId, QVariant, QVariant); - void msgFromGui(BufferId, QString message); - void sendServerStates(); - - signals: - void msgFromGui(QString net, QString buf, QString message); - void displayMsg(Message message); - void displayStatusMsg(QString, QString); - - void connectToIrc(QString net); - void disconnectFromIrc(QString net); - void serverStateRequested(); - - void backlogData(BufferId, QVariantList, bool done); - - void bufferIdUpdated(BufferId); - void sessionDataChanged(const QString &key); - void sessionDataChanged(const QString &key, const QVariant &data); - - private slots: - void recvStatusMsgFromServer(QString msg); - void recvMessageFromServer(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); - void serverConnected(QString net); - void serverDisconnected(QString net); - - private: - UserId user; - - SignalProxy *_signalProxy; - Storage *storage; - QHash servers; - - QVariantMap sessionData; - QMutex mutex; +public: + CoreSession(UserId, Storage *, QObject *parent = 0); + virtual ~CoreSession(); + + uint getNetworkId(const QString &network) const; + QList buffers() const; + UserId userId() const; + QVariant sessionState(); + + //! Retrieve a piece of session-wide data. + QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant()); + + SignalProxy *signalProxy() const; + + void attachServer(Server *server); + +public slots: + //! Store a piece session-wide data and distribute it to connected clients. + void storeSessionData(const QString &key, const QVariant &data); + + void serverStateRequested(); + + void addClient(QIODevice *connection); + + void connectToNetwork(QString); + + //void processSignal(ClientSignal, QVariant, QVariant, QVariant); + void sendBacklog(BufferInfo, QVariant, QVariant); + void msgFromGui(BufferInfo, QString message); + +signals: + void msgFromGui(uint netid, QString buf, QString message); + void displayMsg(Message message); + void displayStatusMsg(QString, QString); + + void connectToIrc(QString net); + void disconnectFromIrc(QString net); + + void backlogData(BufferInfo, QVariantList, bool done); + + void bufferInfoUpdated(BufferInfo); + void sessionDataChanged(const QString &key); + void sessionDataChanged(const QString &key, const QVariant &data); + +private slots: + void recvStatusMsgFromServer(QString msg); + void recvMessageFromServer(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void serverConnected(uint networkid); + void serverDisconnected(uint networkid); + +private: + UserId user; + + SignalProxy *_signalProxy; + Storage *storage; + QHash servers; + + QVariantMap sessionData; + QMutex mutex; }; #endif diff --git a/src/core/ctcphandler.cpp b/src/core/ctcphandler.cpp new file mode 100644 index 00000000..788055c3 --- /dev/null +++ b/src/core/ctcphandler.cpp @@ -0,0 +1,155 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "ctcphandler.h" + +#include "util.h" +#include "message.h" + +CtcpHandler::CtcpHandler(Server *parent) + : BasicHandler(parent) { + + QString MQUOTE = QString('\020'); + ctcpMDequoteHash[MQUOTE + '0'] = QString('\000'); + ctcpMDequoteHash[MQUOTE + 'n'] = QString('\n'); + ctcpMDequoteHash[MQUOTE + 'r'] = QString('\r'); + ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE; + + XDELIM = QString('\001'); + QString XQUOTE = QString('\134'); + ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; + ctcpXDelimDequoteHash[XQUOTE + QString('a')] = XDELIM; +} + +QString CtcpHandler::dequote(QString message) { + QString dequotedMessage; + QString messagepart; + QHash::iterator ctcpquote; + + // copy dequote Message + for(int i = 0; i < message.size(); i++) { + messagepart = message[i]; + if(i+1 < message.size()) { + for(ctcpquote = ctcpMDequoteHash.begin(); ctcpquote != ctcpMDequoteHash.end(); ++ctcpquote) { + if(message.mid(i,2) == ctcpquote.key()) { + dequotedMessage += ctcpquote.value(); + i++; + break; + } + } + } + dequotedMessage += messagepart; + } + return dequotedMessage; +} + + +QString CtcpHandler::XdelimDequote(QString message) { + QString dequotedMessage; + QString messagepart; + QHash::iterator xdelimquote; + + for(int i = 0; i < message.size(); i++) { + messagepart = message[i]; + if(i+1 < message.size()) { + for(xdelimquote = ctcpXDelimDequoteHash.begin(); xdelimquote != ctcpXDelimDequoteHash.end(); ++xdelimquote) { + if(message.mid(i,2) == xdelimquote.key()) { + messagepart = xdelimquote.value(); + i++; + break; + } + } + } + dequotedMessage += messagepart; + } + return dequotedMessage; +} + +QStringList CtcpHandler::parse(CtcpType ctcptype, QString prefix, QString target, QString message) { + QStringList messages; + QString ctcp; + + //lowlevel message dequote + QString dequotedMessage = dequote(message); + + // extract tagged / extended data + while(dequotedMessage.contains(XDELIM)) { + messages << dequotedMessage.section(XDELIM,0,0); + ctcp = XdelimDequote(dequotedMessage.section(XDELIM,1,1)); + dequotedMessage = dequotedMessage.section(XDELIM,2,2); + + //dispatch the ctcp command + QString ctcpcmd = ctcp.section(' ', 0, 0); + QString ctcpparam = ctcp.section(' ', 1); + + handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam)); + } + if(!dequotedMessage.isEmpty()) { + messages << dequotedMessage; + } + return messages; +} + +QString CtcpHandler::pack(QString ctcpTag, QString message) { + return XDELIM + ctcpTag + ' ' + message + XDELIM; +} + +void CtcpHandler::query(QString bufname, QString ctcpTag, QString message) { + QStringList params; + params << bufname << pack(ctcpTag, message); + emit putCmd("PRIVMSG", params); +} + +void CtcpHandler::reply(QString bufname, QString ctcpTag, QString message) { + QStringList params; + params << bufname << pack(ctcpTag, message); + emit putCmd("NOTICE", params); +} + +//******************************/ +// CTCP HANDLER +//******************************/ +void CtcpHandler::handleAction(CtcpType ctcptype, QString prefix, QString target, QString param) { + emit displayMsg(Message::Action, target, param, prefix); +} + +void CtcpHandler::handlePing(CtcpType ctcptype, QString prefix, QString target, QString param) { + if(ctcptype == CtcpQuery) { + reply(nickFromMask(prefix), "PING", param); + emit displayMsg(Message::Server, "", tr("Received CTCP PING request from %1").arg(prefix)); + } else { + // display ping answer + } +} + +void CtcpHandler::handleVersion(CtcpType ctcptype, QString prefix, QString target, QString param) { + if(ctcptype == CtcpQuery) { + // FIXME use real Info about quassel :) + reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC (Pre-Release) - http://www.quassel-irc.org")); + emit displayMsg(Message::Server, "", tr("Received CTCP VERSION request by %1").arg(prefix)); + } else { + // TODO display Version answer + } +} + +void CtcpHandler::defaultHandler(QString cmd, CtcpType ctcptype, QString prefix, QString target, QString param) { + emit displayMsg(Message::Error, "", tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix)); +} + + diff --git a/src/core/ctcphandler.h b/src/core/ctcphandler.h new file mode 100644 index 00000000..9cb2c78d --- /dev/null +++ b/src/core/ctcphandler.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _CTCPHANDLER_H_ +#define _CTCPHANDLER_H_ + +#include +#include + +#include "basichandler.h" + +class CtcpHandler : public BasicHandler { + Q_OBJECT + +public: + CtcpHandler(Server *parent = 0); + + enum CtcpType {CtcpQuery, CtcpReply}; + + QStringList parse(CtcpType, QString, QString, QString); + + QString dequote(QString); + QString XdelimDequote(QString); + + QString pack(QString ctcpTag, QString message); + void query(QString bufname, QString ctcpTag, QString message); + void reply(QString bufname, QString ctcpTag, QString message); + +public slots: + void handleAction(CtcpType, QString prefix, QString target, QString param); + void handlePing(CtcpType, QString prefix, QString target, QString param); + void handleVersion(CtcpType, QString prefix, QString target, QString param); + + void defaultHandler(QString cmd, CtcpType ctcptype, QString prefix, QString target, QString param); + +private: + QString XDELIM; + QHash ctcpMDequoteHash; + QHash ctcpXDelimDequoteHash; + + +}; + + +#endif diff --git a/src/core/ircserverhandler.cpp b/src/core/ircserverhandler.cpp new file mode 100644 index 00000000..ab5c85c9 --- /dev/null +++ b/src/core/ircserverhandler.cpp @@ -0,0 +1,428 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "ircserverhandler.h" + +#include "util.h" + +#include "server.h" +#include "networkinfo.h" +#include "ctcphandler.h" + +#include "ircuser.h" +#include "ircchannel.h" + +#include + +IrcServerHandler::IrcServerHandler(Server *parent) + : BasicHandler(parent) { +} + +IrcServerHandler::~IrcServerHandler() { +} + +/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */ +void IrcServerHandler::handleServerMsg(QByteArray rawmsg) { + try { + if(rawmsg.isEmpty()) { + qWarning() << "Received empty string from server!"; + return; + } + // TODO Implement encoding conversion + /* At this point, we have a raw message as a byte array. This needs to be converted to a QString somewhere. + * Problem is, that at this point we don't know which encoding to use for the various parts of the message. + * This is something the command handler needs to take care of (e.g. PRIVMSG needs to first parse for CTCP, + * and then convert the raw strings into the correct encoding. + * We _can_ safely assume Server encoding for prefix and cmd, but not for the params. Therefore, we need to + * change from a QStringList to a QList in all the handlers, and have the handlers call decodeString + * where needed... + */ + QString msg = QString::fromLatin1(rawmsg); + + // OK, first we split the raw message into its various parts... + QString prefix = ""; + QString cmd; + QStringList params; + + // a colon as the first chars indicates the existance of a prefix + if(msg[0] == ':') { + msg.remove(0,1); + prefix = msg.section(' ', 0, 0); + msg = msg.section(' ', 1); + } + + // next string without a whitespace is the command + cmd = msg.section(' ', 0, 0).toUpper(); + msg = msg.mid(cmd.length()); + + // get the parameters + QString trailing = ""; + if(msg.contains(" :")) { + trailing = msg.section(" :", 1); + msg = msg.section(" :", 0, 0); + } + if(!msg.isEmpty()) { + params << msg.split(' ', QString::SkipEmptyParts); + } + if(!trailing.isEmpty()) { + params << trailing; + } + + // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this! + uint num = cmd.toUInt(); + if(num > 0) { + Q_ASSERT(params.count() > 0); // Violation to RFC + params.removeFirst(); + } + + // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-) + handle(cmd, Q_ARG(QString, prefix), Q_ARG(QStringList, params)); + //handle(cmd, Q_ARG(QString, prefix)); + } catch(Exception e) { + emit displayMsg(Message::Error, "", e.msg()); + } +} + + +void IrcServerHandler::defaultHandler(QString cmd, QString prefix, QStringList params) { + uint num = cmd.toUInt(); + if(num) { + // 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 displayMsg(Message::Server, "", params.join(" "), prefix); + break; + // Server error messages without param, just display them + case 409: case 411: case 412: case 422: case 424: case 445: case 446: case 451: case 462: + case 463: case 464: case 465: case 466: case 472: case 481: case 483: case 485: case 491: case 501: case 502: + case 431: // ERR_NONICKNAMEGIVEN + emit displayMsg(Message::Error, "", params.join(" "), prefix); + break; + // Server error messages, display them in red. First param will be appended. + case 401: case 402: case 403: case 404: case 406: case 408: case 415: case 421: case 442: + { QString p = params.takeFirst(); + emit displayMsg(Message::Error, "", params.join(" ") + " " + p, prefix); + break; + } + // Server error messages which will be displayed with a colon between the first param and the rest + case 413: case 414: case 423: case 441: case 444: case 461: + case 467: case 471: case 473: case 474: case 475: case 476: case 477: case 478: case 482: + case 436: // ERR_NICKCOLLISION + { QString p = params.takeFirst(); + emit displayMsg(Message::Error, "", p + ": " + params.join(" ")); + break; + } + // Ignore these commands. + case 366: case 376: + break; + + // Everything else will be marked in red, so we can add them somewhere. + default: + emit displayMsg(Message::Error, "", cmd + " " + params.join(" "), prefix); + } + //qDebug() << prefix <<":"<updateNickFromMask(prefix); + emit displayMsg(Message::Join, channel, channel, prefix); + + ircuser->joinChannel(channel); +} + +void IrcServerHandler::handleKick(QString prefix, QStringList params) { + networkInfo()->updateNickFromMask(prefix); + IrcUser *victim = networkInfo()->ircUser(params[1]); + QString channel = params[0]; + Q_ASSERT(victim); + + victim->partChannel(channel); + + QString msg; + if(params.count() > 2) // someone got a reason! + msg = QString("%1 %2").arg(victim->nick()).arg(params[2]); + else + msg = victim->nick(); + + emit displayMsg(Message::Kick, params[0], msg, prefix); +} + +void IrcServerHandler::handleMode(QString prefix, QStringList params) { +// if(isChannelName(params[0])) { +// // TODO only channel-user modes supported by now +// QString prefixes = serverSupports["PrefixModes"].toString(); +// QString modes = params[1]; +// int p = 2; +// int m = 0; +// bool add = true; +// while(m < modes.length()) { +// if(modes[m] == '+') { add = true; m++; continue; } +// if(modes[m] == '-') { add = false; m++; continue; } +// if(prefixes.contains(modes[m])) { // it's a user channel mode +// Q_ASSERT(params.count() > m); +// QString nick = params[p++]; +// if(nicks.contains(nick)) { // sometimes, a server might try to set a MODE on a nick that is no longer there +// QVariantMap n = nicks[nick]; QVariantMap clist = n["Channels"].toMap(); QVariantMap chan = clist[params[0]].toMap(); +// QString mstr = chan["Mode"].toString(); +// add ? mstr += modes[m] : mstr.remove(modes[m]); +// chan["Mode"] = mstr; clist[params[0]] = chan; n["Channels"] = clist; nicks[nick] = n; +// emit nickUpdated(network, nick, n); +// } +// m++; +// } else { +// // TODO add more modes +// m++; +// } +// } +// emit displayMsg(Message::Mode, params[0], params.join(" "), prefix); +// } else { +// //Q_ASSERT(nicks.contains(params[0])); +// //QVariantMap n = nicks[params[0]].toMap(); +// //QString mode = n["Mode"].toString(); +// emit displayMsg(Message::Mode, "", params.join(" ")); +// } +} + +void IrcServerHandler::handleNick(QString prefix, QStringList params) { + IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix); + Q_ASSERT(ircuser); + QString newnick = params[0]; + QString oldnick = ircuser->nick(); + + foreach(QString channel, ircuser->channels()) { + if(networkInfo()->isMyNick(oldnick)) + emit displayMsg(Message::Nick, channel, newnick, prefix); + else + emit displayMsg(Message::Nick, channel, newnick, newnick); + } + ircuser->setNick(newnick); +} + +void IrcServerHandler::handleNotice(QString prefix, QStringList params) { + if(networkInfo()->currentServer().isEmpty() || networkInfo()->currentServer() == prefix) + emit displayMsg(Message::Server, "", params[1], prefix); + else + emit displayMsg(Message::Notice, "", params[1], prefix); +} + +void IrcServerHandler::handlePart(QString prefix, QStringList params) { + IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix); + QString channel = params[0]; + Q_ASSERT(ircuser); + + ircuser->partChannel(channel); + + QString msg; + if(params.count() > 1) + msg = params[1]; + + emit displayMsg(Message::Part, params[0], msg, prefix); +} + +void IrcServerHandler::handlePing(QString prefix, QStringList params) { + emit putCmd("PONG", params); +} + +void IrcServerHandler::handlePrivmsg(QString prefix, QStringList params) { + networkInfo()->updateNickFromMask(prefix); + Q_ASSERT(params.count() >= 2); + if(params.count()<2) + emit displayMsg(Message::Plain, params[0], "", prefix); + else { + // it's possible to pack multiple privmsgs into one param using ctcp + QStringList messages = server->ctcpHandler()->parse(CtcpHandler::CtcpQuery, prefix, params[0], params[1]); + + // are we the target or is it a channel? + if(networkInfo()->isMyNick(params[0])) { + foreach(QString message, messages) { + if(!message.isEmpty()) { + emit displayMsg(Message::Plain, "", message, prefix, Message::PrivMsg); + } + } + + } else { + Q_ASSERT(isChannelName(params[0])); // should be channel! + foreach(QString message, messages) { + if(!message.isEmpty()) { + emit displayMsg(Message::Plain, params[0], message, prefix); + } + } + } + } +} + +void IrcServerHandler::handleQuit(QString prefix, QStringList params) { + IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix); + Q_ASSERT(ircuser); + + QString msg; + if(params.count()) + msg = params[0]; + + foreach(QString channel, ircuser->channels()) + emit displayMsg(Message::Quit, channel, msg, prefix); + + ircuser->deleteLater(); +} + +void IrcServerHandler::handleTopic(QString prefix, QStringList params) { + IrcUser *ircuser = networkInfo()->updateNickFromMask(prefix); + QString channel = params[0]; + QString topic = params[1]; + Q_ASSERT(ircuser); + + networkInfo()->ircChannel(channel)->setTopic(topic); + + emit displayMsg(Message::Server, params[0], tr("%1 has changed topic for %2 to: \"%3\"").arg(ircuser->nick()).arg(channel).arg(topic)); +} + +/* RPL_WELCOME */ +void IrcServerHandler::handle001(QString prefix, QStringList params) { + // there should be only one param: "Welcome to the Internet Relay Network !@" + QString myhostmask = params[0].section(' ', -1, -1); + networkInfo()->setCurrentServer(prefix); + networkInfo()->setMyNick(nickFromMask(myhostmask)); + + emit displayMsg(Message::Server, "", params[0], prefix); + + // TODO: reimplement perform List! + //// send performlist + //QStringList performList = networkSettings["Perform"].toString().split( "\n" ); + //int count = performList.count(); + //for(int a = 0; a < count; a++) { + // if(!performList[a].isEmpty() ) { + // userInput(network, "", performList[a]); + // } + //} +} + +/* RPL_ISUPPORT */ +// TODO Complete 005 handling, also use sensible defaults for non-sent stuff +void IrcServerHandler::handle005(QString prefix, QStringList params) { + QString rpl_isupport_suffix = params.takeLast(); + if(rpl_isupport_suffix.toLower() != QString("are supported by this server")) { + qWarning() << "Received invalid RPL_ISUPPORT! Suffix is:" << rpl_isupport_suffix << "Excpected: are supported by this server"; + return; + } + + foreach(QString param, params) { + QString key = param.section("=", 0, 0); + QString value = param.section("=", 1); + networkInfo()->addSupport(key, value); + } +} + + +/* RPL_NOTOPIC */ +void IrcServerHandler::handle331(QString prefix, QStringList params) { + networkInfo()->ircChannel(params[0])->setTopic(QString()); + emit displayMsg(Message::Server, params[0], tr("No topic is set for %1.").arg(params[0])); +} + +/* RPL_TOPIC */ +void IrcServerHandler::handle332(QString prefix, QStringList params) { + networkInfo()->ircChannel(params[0])->setTopic(params[1]); + emit displayMsg(Message::Server, params[0], tr("Topic for %1 is \"%2\"").arg(params[0]).arg(params[1])); +} + +/* Topic set by... */ +void IrcServerHandler::handle333(QString prefix, QStringList params) { + emit displayMsg(Message::Server, params[0], tr("Topic set by %1 on %2").arg(params[1]).arg(QDateTime::fromTime_t(params[2].toUInt()).toString())); +} + +/* RPL_NAMREPLY */ +void IrcServerHandler::handle353(QString prefix, QStringList params) { + params.removeFirst(); // either "=", "*" or "@" indicating a public, private or secret channel + QString channelname = params.takeFirst(); + + foreach(QString nick, params.takeFirst().split(' ')) { + QString mode = QString(); + + if(networkInfo()->prefixes().contains(nick[0])) { + mode = networkInfo()->prefixToMode(nick[0]); + nick = nick.mid(1); + } + + IrcUser *ircuser = networkInfo()->newIrcUser(nick); + ircuser->joinChannel(channelname); + + if(!mode.isNull()) + networkInfo()->ircChannel(channelname)->addUserMode(ircuser, mode); + } +} + +/* ERR_ERRONEUSNICKNAME */ +void IrcServerHandler::handle432(QString prefix, QStringList params) { +// if(params.size() < 2) { +// // handle unreal-ircd bug, where unreal ircd doesnt supply a TARGET in ERR_ERRONEUSNICKNAME during registration phase: +// // nick @@@ +// // :irc.scortum.moep.net 432 @@@ :Erroneous Nickname: Illegal characters +// // correct server reply: +// // :irc.scortum.moep.net 432 * @@@ :Erroneous Nickname: Illegal characters +// emit displayMsg(Message::Error, "", tr("There is a nickname in your identity's nicklist which contains illegal characters")); +// emit displayMsg(Message::Error, "", tr("Due to a bug in Unreal IRCd (and maybe other irc-servers too) we're unable to determine the erroneous nick")); +// emit displayMsg(Message::Error, "", tr("Please use: /nick to continue or clean up your nicklist")); +// } else { +// QString errnick = params[0]; +// emit displayMsg(Message::Error, "", tr("Nick %1 contains illegal characters").arg(errnick)); +// // if there is a problem while connecting to the server -> we handle it +// // TODO rely on another source... +// if(currentServer.isEmpty()) { +// QStringList desiredNicks = identity["NickList"].toStringList(); +// int nextNick = desiredNicks.indexOf(errnick) + 1; +// if (desiredNicks.size() > nextNick) { +// putCmd("NICK", QStringList(desiredNicks[nextNick])); +// } else { +// emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick to continue")); +// } +// } +// } +} + +/* ERR_NICKNAMEINUSE */ +void IrcServerHandler::handle433(QString prefix, QStringList params) { +// QString errnick = params[0]; +// emit displayMsg(Message::Error, "", tr("Nick %1 is already taken").arg(errnick)); +// // if there is a problem while connecting to the server -> we handle it +// // TODO rely on another source... +// if(currentServer.isEmpty()) { +// QStringList desiredNicks = identity["NickList"].toStringList(); +// int nextNick = desiredNicks.indexOf(errnick) + 1; +// if (desiredNicks.size() > nextNick) { +// putCmd("NICK", QStringList(desiredNicks[nextNick])); +// } else { +// emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick to continue")); +// } +// } +} + +/***********************************************************************************/ + + diff --git a/src/core/ircserverhandler.h b/src/core/ircserverhandler.h new file mode 100644 index 00000000..fe7f4f2d --- /dev/null +++ b/src/core/ircserverhandler.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _IRCSERVERHANDLER_H_ +#define _IRCSERVERHANDLER_H_ + +#include "basichandler.h" + +class IrcServerHandler : public BasicHandler { + Q_OBJECT + +public: + IrcServerHandler(Server *parent = 0); + ~IrcServerHandler(); + + void handleServerMsg(QByteArray rawMsg); + +public slots: + void handleJoin(QString, QStringList); + void handleKick(QString, QStringList); + void handleMode(QString, QStringList); + void handleNick(QString, QStringList); + void handleNotice(QString, QStringList); + void handlePart(QString, QStringList); + void handlePing(QString, QStringList); + void handlePrivmsg(QString, QStringList); + void handleQuit(QString, QStringList); + void handleTopic(QString, QStringList); + + void handle001(QString, QStringList); // RPL_WELCOME + void handle005(QString, QStringList); // RPL_ISUPPORT + void handle331(QString, QStringList); // RPL_NOTOPIC + void handle332(QString, QStringList); // RPL_TOPIC + void handle333(QString, QStringList); // Topic set by... + void handle353(QString, QStringList); // RPL_NAMREPLY + void handle432(QString, QStringList); // ERR_ERRONEUSNICKNAME + void handle433(QString, QStringList); // ERR_NICKNAMEINUSE + + void defaultHandler(QString cmd, QString prefix, QStringList params); +}; + + +#endif diff --git a/src/core/server.cpp b/src/core/server.cpp index 9123801c..3af2119d 100644 --- a/src/core/server.cpp +++ b/src/core/server.cpp @@ -27,23 +27,28 @@ #include "core.h" #include "coresession.h" -Server::Server(UserId uid, QString net) : user(uid), network(net) { - QString MQUOTE = QString('\020'); - ctcpMDequoteHash[MQUOTE + '0'] = QString('\000'); - ctcpMDequoteHash[MQUOTE + 'n'] = QString('\n'); - ctcpMDequoteHash[MQUOTE + 'r'] = QString('\r'); - ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE; +#include "networkinfo.h" +#include "synchronizer.h" - XDELIM = QString('\001'); - QString XQUOTE = QString('\134'); - ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; - ctcpXDelimDequoteHash[XQUOTE + QString('a')] = XDELIM; - - serverinfo = new ServerInfo(); +#include "ircserverhandler.h" +#include "userinputhandler.h" +#include "ctcphandler.h" + +Server::Server(UserId uid, uint networkId, QString net) + : _userId(uid), + _networkId(networkId), + _ircServerHandler(new IrcServerHandler(this)), + _userInputHandler(new UserInputHandler(this)), + _ctcpHandler(new CtcpHandler(this)), + _networkInfo(new NetworkInfo(networkId, coreSession()->signalProxy(), this)) +{ + networkInfo()->setNetworkName(net); } Server::~Server() { - delete serverinfo; + delete _ircServerHandler; + delete _userInputHandler; + delete _ctcpHandler; } void Server::run() { @@ -56,25 +61,15 @@ void Server::run() { exec(); } -void Server::sendState() { - QVariantMap s; - QVariantMap n, t; - foreach(QString key, nicks.keys()) { n[key] = nicks[key]; } - foreach(QString key, topics.keys()) { t[key] = topics[key];} - s["Nicks"] = n; - s["Topics"] = t; - s["OwnNick"] = ownNick; - s["ServerSupports"] = serverSupports; - emit serverState(network, s); -} - void Server::connectToIrc(QString net) { - if(net != network) return; // not me! - CoreSession *sess = Core::session(user); - //networkSettings = Global::data(user, "Networks").toMap()[net].toMap(); + if(net != networkName()) + return; // not me! + + CoreSession *sess = coreSession(); networkSettings = sess->retrieveSessionData("Networks").toMap()[net].toMap(); - //identity = Global::data(user, "Identities").toMap()[networkSettings["Identity"].toString()].toMap(); identity = sess->retrieveSessionData("Identities").toMap()[networkSettings["Identity"].toString()].toMap(); + + //FIXME this will result in a pretty fuckup if there are no servers in the list QList servers = networkSettings["Servers"].toList(); QString host = servers[0].toMap()["Address"].toString(); quint16 port = servers[0].toMap()["Port"].toUInt(); @@ -83,841 +78,81 @@ void Server::connectToIrc(QString net) { } void Server::disconnectFromIrc(QString net) { - if(net != network) return; // not me! + if(net != networkName()) + return; // not me! socket.disconnectFromHost(); } void Server::socketHasData() { while(socket.canReadLine()) { QByteArray s = socket.readLine().trimmed(); - //qDebug() << "Read" << s; - //emit recvRawServerMsg(s); // signal not needed, and we should make sure we consider encodings where we need them - //Message *msg = Message::createFromServerString(this, s); - handleServerMsg(s); + ircServerHandler()->handleServerMsg(s); } } void Server::socketError( QAbstractSocket::SocketError err ) { //qDebug() << "Socket Error!"; - //emit error(err); } void Server::socketConnected( ) { - emit connected(network); + emit connected(networkId()); putRawLine(QString("NICK :%1").arg(identity["NickList"].toStringList()[0])); // FIXME: try more nicks if error occurs putRawLine(QString("USER %1 8 * :%2").arg(identity["Ident"].toString()).arg(identity["RealName"].toString())); } void Server::socketDisconnected( ) { - //qDebug() << "Socket disconnected!"; - emit disconnected(network); - topics.clear(); - nicks.clear(); + emit disconnected(networkId()); + // propagate to networkInfo, so we can clear up } void Server::socketStateChanged(QAbstractSocket::SocketState state) { //qDebug() << "Socket state changed: " << state; } -QString Server::updateNickFromMask(QString mask) { - QString user = userFromMask(mask); - QString host = hostFromMask(mask); - QString nick = nickFromMask(mask); - if(nicks.contains(nick) && !user.isEmpty() && !host.isEmpty()) { - QVariantMap n = nicks[nick]; - if(n["User"].toString() != user || n["Host"].toString() != host) { - if(!n["User"].toString().isEmpty() || !n["Host"].toString().isEmpty()) - qWarning(QString("Strange: Hostmask for nick %1 has changed!").arg(nick).toAscii()); - n["User"] = user; n["Host"] = host; - nicks[nick] = n; - emit nickUpdated(network, nick, n); - } - } - return nick; -} - -void Server::userInput(QString net, QString buf, QString 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; - } - handleUserInput(buf, msg); +void Server::userInput(uint netid, QString buf, QString msg) { + if(netid != networkId()) + return; // not me! + userInputHandler()->handleUserInput(buf, msg); } void Server::putRawLine(QString s) { -// qDebug() << "SentRaw: " << s; s += "\r\n"; socket.write(s.toAscii()); } void Server::putCmd(QString cmd, QStringList params, QString prefix) { - QString m; - if(!prefix.isEmpty()) m += ":" + prefix + " "; - m += cmd.toUpper(); - for(int i = 0; i < params.size() - 1; i++) { - m += " " + params[i]; - } - if(!params.isEmpty()) m += " :" + params.last(); -// qDebug() << "Sent: " << m; - m += "\r\n"; - socket.write(m.toAscii()); -} - -/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */ -void Server::handleServerMsg(QByteArray rawmsg) { - try { - if(rawmsg.isEmpty()) { - qWarning() << "Received empty string from server!"; - return; - } - // TODO Implement encoding conversion - /* At this point, we have a raw message as a byte array. This needs to be converted to a QString somewhere. - * Problem is, that at this point we don't know which encoding to use for the various parts of the message. - * This is something the command handler needs to take care of (e.g. PRIVMSG needs to first parse for CTCP, - * and then convert the raw strings into the correct encoding. - * We _can_ safely assume Server encoding for prefix and cmd, but not for the params. Therefore, we need to - * change from a QStringList to a QList in all the handlers, and have the handlers call decodeString - * where needed... - */ - QString msg = QString::fromLatin1(rawmsg); - - // OK, first we split the raw message into its various parts... - QString prefix = ""; - QString cmd; - QStringList params; - - // check for prefix by checking for a colon as the first char - if(msg[0] == ':') { - msg.remove(0,1); - prefix = msg.section(' ', 0, 0); - msg = msg.section(' ', 1); - } - - // next string without a whitespace is the command - cmd = msg.section(' ', 0, 0).toUpper(); - msg = msg.mid(cmd.length()); - - // get the parameters - QString trailing = ""; - if(msg.contains(" :")) { - trailing = msg.section(" :", 1); - msg = msg.section(" :", 0, 0); - } - if(!msg.isEmpty()) { - params << msg.split(' ', QString::SkipEmptyParts); - } - if(!trailing.isEmpty()) { - params << trailing; - } - - // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this! - uint num = cmd.toUInt(); - if(num > 0) { - Q_ASSERT(params.count() > 0); // Violation to RFC - params.removeFirst(); - } - - // 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 = "handleServer" + hname; - if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, prefix), Q_ARG(QStringList, params))) { - // Ok. Default handler it is. - defaultServerHandler(cmd, prefix, params); - } - } catch(Exception e) { - emit displayMsg(Message::Error, "", e.msg()); - } -} - -void Server::defaultServerHandler(QString cmd, QString prefix, QStringList params) { - uint num = cmd.toUInt(); - if(num) { - // 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 displayMsg(Message::Server, "", params.join(" "), prefix); - break; - // Server error messages without param, just display them - case 409: case 411: case 412: case 422: case 424: case 445: case 446: case 451: case 462: - case 463: case 464: case 465: case 466: case 472: case 481: case 483: case 485: case 491: case 501: case 502: - case 431: // ERR_NONICKNAMEGIVEN - emit displayMsg(Message::Error, "", params.join(" "), prefix); - break; - // Server error messages, display them in red. First param will be appended. - case 401: case 402: case 403: case 404: case 406: case 408: case 415: case 421: case 442: - { QString p = params.takeFirst(); - emit displayMsg(Message::Error, "", params.join(" ") + " " + p, prefix); - break; - } - // Server error messages which will be displayed with a colon between the first param and the rest - case 413: case 414: case 423: case 441: case 444: case 461: - case 467: case 471: case 473: case 474: case 475: case 476: case 477: case 478: case 482: - case 436: // ERR_NICKCOLLISION - { QString p = params.takeFirst(); - emit displayMsg(Message::Error, "", p + ": " + params.join(" ")); - break; - } - // Ignore these commands. - case 366: case 376: - break; - - // Everything else will be marked in red, so we can add them somewhere. - default: - emit displayMsg(Message::Error, "", cmd + " " + params.join(" "), prefix); - } - //qDebug() << prefix <<":"<methodCount(); i++) { - QString methodSignature(metaObject()->method(i).signature()); - if (methodSignature.startsWith("handleUser")) { - methodSignature = methodSignature.section('(',0,0); // chop the attribute list - methodSignature = methodSignature.mid(10); // strip "handleUser" - userHandlers << methodSignature; - } - } - return userHandlers; -} - -QString Server::ctcpDequote(QString message) { - QString dequotedMessage; - QString messagepart; - QHash::iterator ctcpquote; - - // copy dequote Message - for(int i = 0; i < message.size(); i++) { - messagepart = message[i]; - if(i+1 < message.size()) { - for(ctcpquote = ctcpMDequoteHash.begin(); ctcpquote != ctcpMDequoteHash.end(); ++ctcpquote) { - if(message.mid(i,2) == ctcpquote.key()) { - dequotedMessage += ctcpquote.value(); - i++; - break; - } - } - } - dequotedMessage += messagepart; - } - return dequotedMessage; -} - - -QString Server::ctcpXdelimDequote(QString message) { - QString dequotedMessage; - QString messagepart; - QHash::iterator xdelimquote; - - for(int i = 0; i < message.size(); i++) { - messagepart = message[i]; - if(i+1 < message.size()) { - for(xdelimquote = ctcpXDelimDequoteHash.begin(); xdelimquote != ctcpXDelimDequoteHash.end(); ++xdelimquote) { - if(message.mid(i,2) == xdelimquote.key()) { - messagepart = xdelimquote.value(); - i++; - break; - } - } - } - dequotedMessage += messagepart; - } - return dequotedMessage; -} - -QStringList Server::parseCtcp(CtcpType ctcptype, QString prefix, QString target, QString message) { - QStringList messages; - QString ctcp; - - //lowlevel message dequote - QString dequotedMessage = ctcpDequote(message); + QString msg; + if(!prefix.isEmpty()) + msg += ":" + prefix + " "; + msg += cmd.toUpper(); - // extract tagged / extended data - while(dequotedMessage.contains(XDELIM)) { - messages << dequotedMessage.section(XDELIM,0,0); - ctcp = ctcpXdelimDequote(dequotedMessage.section(XDELIM,1,1)); - dequotedMessage = dequotedMessage.section(XDELIM,2,2); - - //dispatch the ctcp command - QString ctcpcmd = ctcp.section(' ', 0, 0); - QString ctcpparam = ctcp.section(' ', 1); - - QString hname = ctcpcmd.toLower(); - hname[0] = hname[0].toUpper(); - hname = "handleCtcp" + hname; - if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam))) { - // Ok. Default handler it is. - defaultCtcpHandler(ctcptype, prefix, ctcpcmd, target, ctcpparam); - } - } - if(!dequotedMessage.isEmpty()) { - messages << dequotedMessage; + for(int i = 0; i < params.size() - 1; i++) { + msg += " " + params[i]; } - return messages; -} - -QString Server::ctcpPack(QString ctcpTag, QString message) { - return XDELIM + ctcpTag + ' ' + message + XDELIM; -} - -void Server::ctcpQuery(QString bufname, QString ctcpTag, QString message) { - QStringList params; - params << bufname << ctcpPack(ctcpTag, message); - putCmd("PRIVMSG", params); -} - -void Server::ctcpReply(QString bufname, QString ctcpTag, QString message) { - QStringList params; - params << bufname << ctcpPack(ctcpTag, message); - putCmd("NOTICE", params); -} - -/**********************************************************************************/ - -/* -void Server::handleUser(QString bufname, QString msg) { - - -} -*/ - -void Server::handleUserAway(QString bufname, QString msg) { - putCmd("AWAY", QStringList(msg)); -} - -void Server::handleUserDeop(QString bufname, QString msg) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o'; - QStringList params; - params << bufname << m << nicks; - putCmd("MODE", params); -} - -void Server::handleUserDevoice(QString bufname, QString msg) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'v'; - QStringList params; - params << bufname << m << nicks; - putCmd("MODE", params); -} - -void Server::handleUserInvite(QString bufname, QString msg) { - QStringList params; - params << msg << bufname; - putCmd("INVITE", params); -} - -void Server::handleUserJoin(QString bufname, QString msg) { - putCmd("JOIN", QStringList(msg)); -} - -void Server::handleUserKick(QString bufname, QString msg) { - QStringList params; - params << bufname << msg.split(' ', QString::SkipEmptyParts); - putCmd("KICK", params); -} - -void Server::handleUserList(QString bufname, QString msg) { - putCmd("LIST", msg.split(' ', QString::SkipEmptyParts)); -} - -void Server::handleUserMode(QString bufname, QString msg) { - putCmd("MODE", msg.split(' ', QString::SkipEmptyParts)); -} - -// TODO: show privmsgs -void Server::handleUserMsg(QString bufname, QString msg) { - QString nick = msg.section(" ", 0, 0); - msg = msg.section(" ", 1); - if(nick.isEmpty() || msg.isEmpty()) return; - QStringList params; - params << nick << msg; - putCmd("PRIVMSG", params); -} - -void Server::handleUserNick(QString bufname, QString msg) { - QString nick = msg.section(' ', 0, 0); - putCmd("NICK", QStringList(nick)); -} - -void Server::handleUserOp(QString bufname, QString msg) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'o'; - QStringList params; - params << bufname << m << nicks; - putCmd("MODE", params); -} - -void Server::handleUserPart(QString bufname, QString msg) { - QStringList params; - params << bufname << msg; - putCmd("PART", params); -} + if(!params.isEmpty()) + msg += " :" + params.last(); -// TODO: implement queries -void Server::handleUserQuery(QString bufname, QString msg) { - QString nick = msg.section(' ', 0, 0); - if(!nick.isEmpty()) emit queryRequested(network, nick); -} - -void Server::handleUserQuit(QString bufname, QString msg) { - putCmd("QUIT", QStringList(msg)); -} - -void Server::handleUserQuote(QString bufname, QString msg) { putRawLine(msg); } -void Server::handleUserSay(QString bufname, QString msg) { - if(bufname.isEmpty()) return; // server buffer - QStringList params; - params << bufname << msg; - putCmd("PRIVMSG", params); - if(isChannelName(bufname)) { - emit displayMsg(Message::Plain, params[0], msg, ownNick, Message::Self); - } else { - emit displayMsg(Message::Plain, params[0], msg, ownNick, Message::Self|Message::PrivMsg); - } -} - -void Server::handleUserMe(QString bufname, QString msg) { - if(bufname.isEmpty()) return; // server buffer - ctcpQuery(bufname, "ACTION", msg); - emit displayMsg(Message::Action, bufname, msg, ownNick); -} - -void Server::handleUserTopic(QString bufname, QString msg) { - if(bufname.isEmpty()) return; - QStringList params; - params << bufname << msg; - putCmd("TOPIC", params); -} - -void Server::handleUserVoice(QString bufname, QString msg) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'v'; - QStringList params; - params << bufname << m << nicks; - putCmd("MODE", params); -} - -/**********************************************************************************/ - -void Server::handleServerJoin(QString prefix, QStringList params) { - Q_ASSERT(params.count() == 1); - QString nick = updateNickFromMask(prefix); - emit displayMsg(Message::Join, params[0], params[0], prefix); - if(nick == ownNick) { - // Q_ASSERT(!buffers.contains(params[0])); // cannot join a buffer twice! - // Buffer *buf = new Buffer(params[0]); - // buffers[params[0]] = buf; - topics[params[0]] = ""; - emit topicSet(network, params[0], ""); - } //else { - QVariantMap n; - if(nicks.contains(nick)) { - n = nicks[nick]; - QVariantMap chans = n["Channels"].toMap(); - // Q_ASSERT(!chans.keys().contains(params[0])); TODO uncomment - chans[params[0]] = QVariantMap(); - n["Channels"] = chans; - nicks[nick] = n; - emit nickUpdated(network, nick, n); - } else { - QVariantMap chans; - chans[params[0]] = QVariantMap(); - n["Channels"] = chans; - n["User"] = userFromMask(prefix); - n["Host"] = hostFromMask(prefix); - nicks[nick] = n; - emit nickAdded(network, nick, n); - } - //emit displayMsg(Message::Join, params[0], params[0], prefix); - //} -} - -void Server::handleServerKick(QString prefix, QStringList params) { - QString kicker = updateNickFromMask(prefix); - QString nick = params[1]; - Q_ASSERT(nicks.contains(nick)); - QVariantMap n = nicks[nick]; - QVariantMap chans = n["Channels"].toMap(); - Q_ASSERT(chans.contains(params[0])); - chans.remove(params[0]); - QString msg = nick; - if(params.count() > 2) msg = QString("%1 %2").arg(msg).arg(params[2]); - emit displayMsg(Message::Kick, params[0], msg, prefix); - if(chans.count() > 0) { - n["Channels"] = chans; - nicks[nick] = n; - emit nickUpdated(network, nick, n); - } else { - nicks.remove(nick); - emit nickRemoved(network, nick); - } - if(nick == ownNick) { - topics.remove(params[0]); - } -} - -void Server::handleServerMode(QString prefix, QStringList params) { - if(isChannelName(params[0])) { - // TODO only channel-user modes supported by now - QString prefixes = serverSupports["PrefixModes"].toString(); - QString modes = params[1]; - int p = 2; - int m = 0; - bool add = true; - while(m < modes.length()) { - if(modes[m] == '+') { add = true; m++; continue; } - if(modes[m] == '-') { add = false; m++; continue; } - if(prefixes.contains(modes[m])) { // it's a user channel mode - Q_ASSERT(params.count() > m); - QString nick = params[p++]; - if(nicks.contains(nick)) { // sometimes, a server might try to set a MODE on a nick that is no longer there - QVariantMap n = nicks[nick]; QVariantMap clist = n["Channels"].toMap(); QVariantMap chan = clist[params[0]].toMap(); - QString mstr = chan["Mode"].toString(); - add ? mstr += modes[m] : mstr.remove(modes[m]); - chan["Mode"] = mstr; clist[params[0]] = chan; n["Channels"] = clist; nicks[nick] = n; - emit nickUpdated(network, nick, n); - } - m++; - } else { - // TODO add more modes - m++; - } - } - emit displayMsg(Message::Mode, params[0], params.join(" "), prefix); - } else { - //Q_ASSERT(nicks.contains(params[0])); - //QVariantMap n = nicks[params[0]].toMap(); - //QString mode = n["Mode"].toString(); - emit displayMsg(Message::Mode, "", params.join(" ")); - } -} - -void Server::handleServerNick(QString prefix, QStringList params) { - QString oldnick = updateNickFromMask(prefix); - QString newnick = params[0]; - QVariantMap v = nicks.take(oldnick); - nicks[newnick] = v; - QVariantMap chans = v["Channels"].toMap(); - foreach(QString c, chans.keys()) { - if(oldnick != ownNick) { emit displayMsg(Message::Nick, c, newnick, prefix); } - else { emit displayMsg(Message::Nick, c, newnick, newnick); } - } - emit nickRenamed(network, oldnick, newnick); - if(oldnick == ownNick) { - ownNick = newnick; - emit ownNickSet(network, newnick); - } -} - -void Server::handleServerNotice(QString prefix, QStringList params) { - //Message msg(Message::Notice, params[1], prefix); - if(currentServer.isEmpty() || prefix == currentServer) emit displayMsg(Message::Server, "", params[1], prefix); - else emit displayMsg(Message::Notice, "", params[1], prefix); -} - -void Server::handleServerPart(QString prefix, QStringList params) { - QString nick = updateNickFromMask(prefix); - Q_ASSERT(nicks.contains(nick)); - QVariantMap n = nicks[nick]; - QVariantMap chans = n["Channels"].toMap(); - Q_ASSERT(chans.contains(params[0])); - chans.remove(params[0]); - QString msg; - if(params.count() > 1) msg = params[1]; - emit displayMsg(Message::Part, params[0], msg, prefix); - if(chans.count() > 0) { - n["Channels"] = chans; - nicks[nick] = n; - emit nickUpdated(network, nick, n); - } else { - nicks.remove(nick); - emit nickRemoved(network, nick); - } - if(nick == ownNick) { - Q_ASSERT(topics.contains(params[0])); - topics.remove(params[0]); - } -} - -void Server::handleServerPing(QString prefix, QStringList params) { - putCmd("PONG", params); -} - -void Server::handleServerPrivmsg(QString prefix, QStringList params) { - updateNickFromMask(prefix); - Q_ASSERT(params.count() >= 2); - if(params.count()<2) emit displayMsg(Message::Plain, params[0], "", prefix); - else { - // it's possible to pack multiple privmsgs into one param using ctcp - QStringList messages = parseCtcp(Server::CtcpQuery, prefix, params[0], params[1]); - if(params[0].toLower() == ownNick.toLower()) { // Freenode sends nickname in lower case! - foreach(QString message, messages) { - if(!message.isEmpty()) { - emit displayMsg(Message::Plain, "", message, prefix, Message::PrivMsg); - } - } - - } else { - //qDebug() << prefix << params; - Q_ASSERT(isChannelName(params[0])); // should be channel! - foreach(QString message, messages) { - if(!message.isEmpty()) { - emit displayMsg(Message::Plain, params[0], message, prefix); - } - } - } - } -} - -void Server::handleServerQuit(QString prefix, QStringList params) { - QString nick = updateNickFromMask(prefix); - Q_ASSERT(nicks.contains(nick)); - QVariantMap chans = nicks[nick]["Channels"].toMap(); - QString msg; - if(params.count()) msg = params[0]; - foreach(QString c, chans.keys()) { - emit displayMsg(Message::Quit, c, msg, prefix); - } - nicks.remove(nick); - emit nickRemoved(network, nick); -} - -void Server::handleServerTopic(QString prefix, QStringList params) { - QString nick = updateNickFromMask(prefix); - Q_ASSERT(nicks.contains(nick)); - topics[params[0]] = params[1]; - emit topicSet(network, params[0], params[1]); - emit displayMsg(Message::Server, params[0], tr("%1 has changed topic for %2 to: \"%3\"").arg(nick).arg(params[0]).arg(params[1])); -} - -/* RPL_WELCOME */ -void Server::handleServer001(QString prefix, QStringList params) { - // there should be only one param: "Welcome to the Internet Relay Network !@" - currentServer = prefix; - ownNick = params[0].section(' ', -1, -1).section('!', 0, 0); - QVariantMap n; - n["Channels"] = QVariantMap(); - nicks[ownNick] = n; - emit ownNickSet(network, ownNick); - emit nickAdded(network, ownNick, QVariantMap()); - emit displayMsg(Message::Server, "", params[0], prefix); - // send performlist - QStringList performList = networkSettings["Perform"].toString().split( "\n" ); - int count = performList.count(); - for(int a = 0; a < count; a++) { - if(!performList[a].isEmpty() ) { - userInput(network, "", performList[a]); - } - } -} - -/* RPL_ISUPPORT */ -// TODO Complete 005 handling, also use sensible defaults for non-sent stuff -void Server::handleServer005(QString prefix, QStringList params) { - //qDebug() << prefix << params; - params.removeLast(); - foreach(QString p, params) { - QString key = p.section("=", 0, 0); - QString val = p.section("=", 1); - serverSupports[key] = val; - // handle some special cases - if(key == "PREFIX") { - QVariantMap foo; QString modes, prefixes; - Q_ASSERT(val.contains(')') && val.startsWith('(')); - int m = 1, p; - for(p = 2; p < val.length(); p++) if(val[p] == ')') break; - p++; - for(; val[m] != ')'; m++, p++) { - Q_ASSERT(p < val.length()); - foo[QString(val[m])] = QString(val[p]); - modes += val[m]; prefixes += val[p]; - } - serverSupports["PrefixModes"] = modes; serverSupports["Prefixes"] = prefixes; - serverSupports["ModePrefixMap"] = foo; - } - } -} - - -/* RPL_NOTOPIC */ -void Server::handleServer331(QString prefix, QStringList params) { - topics[params[0]] = ""; - emit topicSet(network, params[0], ""); - emit displayMsg(Message::Server, params[0], tr("No topic is set for %1.").arg(params[0])); -} - -/* RPL_TOPIC */ -void Server::handleServer332(QString prefix, QStringList params) { - topics[params[0]] = params[1]; - emit topicSet(network, params[0], params[1]); - emit displayMsg(Message::Server, params[0], tr("Topic for %1 is \"%2\"").arg(params[0]).arg(params[1])); -} - -/* Topic set by... */ -void Server::handleServer333(QString prefix, QStringList params) { - emit displayMsg(Message::Server, params[0], - tr("Topic set by %1 on %2").arg(params[1]).arg(QDateTime::fromTime_t(params[2].toUInt()).toString())); -} - -/* RPL_NAMREPLY */ -void Server::handleServer353(QString prefix, QStringList params) { - params.removeFirst(); // = or * - QString buf = params.takeFirst(); - QString prefixes = serverSupports["Prefixes"].toString(); - foreach(QString nick, params[0].split(' ')) { - QString mode = "", pfx = ""; - if(prefixes.contains(nick[0])) { - pfx = nick[0]; - for(int i = 0;; i++) - if(prefixes[i] == nick[0]) { mode = serverSupports["PrefixModes"].toString()[i]; break; } - nick.remove(0,1); - } - QVariantMap c; c["Mode"] = mode; c["Prefix"] = pfx; - if(nicks.contains(nick)) { - QVariantMap n = nicks[nick]; - QVariantMap chans = n["Channels"].toMap(); - chans[buf] = c; - n["Channels"] = chans; - nicks[nick] = n; - emit nickUpdated(network, nick, n); - } else { - QVariantMap n; QVariantMap c; QVariantMap chans; - c["Mode"] = mode; - chans[buf] = c; - n["Channels"] = chans; - nicks[nick] = n; - emit nickAdded(network, nick, n); - } - } -} - -/* ERR_ERRONEUSNICKNAME */ -void Server::handleServer432(QString prefix, QStringList params) { - if(params.size() < 2) { - // handle unreal-ircd bug, where unreal ircd doesnt supply a TARGET in ERR_ERRONEUSNICKNAME during registration phase: - // nick @@@ - // :irc.scortum.moep.net 432 @@@ :Erroneous Nickname: Illegal characters - // correct server reply: - // :irc.scortum.moep.net 432 * @@@ :Erroneous Nickname: Illegal characters - emit displayMsg(Message::Error, "", tr("There is a nickname in your identity's nicklist which contains illegal characters")); - emit displayMsg(Message::Error, "", tr("Due to a bug in Unreal IRCd (and maybe other irc-servers too) we're unable to determine the erroneous nick")); - emit displayMsg(Message::Error, "", tr("Please use: /nick to continue or clean up your nicklist")); - } else { - QString errnick = params[0]; - emit displayMsg(Message::Error, "", tr("Nick %1 contains illegal characters").arg(errnick)); - // if there is a problem while connecting to the server -> we handle it - // TODO rely on another source... - if(currentServer.isEmpty()) { - QStringList desiredNicks = identity["NickList"].toStringList(); - int nextNick = desiredNicks.indexOf(errnick) + 1; - if (desiredNicks.size() > nextNick) { - putCmd("NICK", QStringList(desiredNicks[nextNick])); - } else { - emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick to continue")); - } - } - } -} - -/* ERR_NICKNAMEINUSE */ -void Server::handleServer433(QString prefix, QStringList params) { - QString errnick = params[0]; - emit displayMsg(Message::Error, "", tr("Nick %1 is already taken").arg(errnick)); - // if there is a problem while connecting to the server -> we handle it - // TODO rely on another source... - if(currentServer.isEmpty()) { - QStringList desiredNicks = identity["NickList"].toStringList(); - int nextNick = desiredNicks.indexOf(errnick) + 1; - if (desiredNicks.size() > nextNick) { - putCmd("NICK", QStringList(desiredNicks[nextNick])); - } else { - emit displayMsg(Message::Error, "", tr("No free and valid nicks in nicklist found. use: /nick to continue")); - } - } -} - -/***********************************************************************************/ -// CTCP HANDLER -void Server::handleCtcpAction(CtcpType ctcptype, QString prefix, QString target, QString param) { - emit displayMsg(Message::Action, target, param, prefix); -} - -void Server::handleCtcpPing(CtcpType ctcptype, QString prefix, QString target, QString param) { - if(ctcptype == CtcpQuery) { - ctcpReply(nickFromMask(prefix), "PING", param); - emit displayMsg(Message::Server, "", tr("Received CTCP PING request by %1").arg(prefix)); - } else { - // display ping answer - } +uint Server::networkId() const { + return _networkId; } -void Server::handleCtcpVersion(CtcpType ctcptype, QString prefix, QString target, QString param) { - if(ctcptype == CtcpQuery) { - // FIXME use real Info about quassel :) - //ctcpReply(nickFromMask(prefix), "VERSION", QString("Quassel:pre Release:*nix")); - ctcpReply(nickFromMask(prefix), "VERSION", QString("Quassel IRC (Pre-Release) - http://www.quassel-irc.org")); - emit displayMsg(Message::Server, "", tr("Received CTCP VERSION request by %1").arg(prefix)); - } else { - // TODO display Version answer - } +QString Server::networkName() { + return networkInfo()->networkName(); } -void Server::defaultCtcpHandler(CtcpType ctcptype, QString prefix, QString cmd, QString target, QString param) { - emit displayMsg(Message::Error, "", tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix)); +CoreSession *Server::coreSession() const { + return Core::session(userId()); } - -/***********************************************************************************/ - /* Exception classes for message handling */ Server::ParseError::ParseError(QString cmd, QString prefix, QStringList params) { _msg = QString("Command Parse Error: ") + cmd + params.join(" "); - } Server::UnknownCmdError::UnknownCmdError(QString cmd, QString prefix, QStringList params) { _msg = QString("Unknown Command: ") + cmd; - } diff --git a/src/core/server.h b/src/core/server.h index 360bed85..1b92f16d 100644 --- a/src/core/server.h +++ b/src/core/server.h @@ -29,8 +29,14 @@ #include #include "message.h" -#include "serverinfo.h" +#include "signalproxy.h" +class NetworkInfo; + +class IrcServerHandler; +class UserInputHandler; +class CtcpHandler; +class CoreSession; /*! * This is a server object, managing a single connection to an IRC server, handling the associated channels and so on. @@ -41,152 +47,83 @@ class Server : public QThread { Q_OBJECT - public: - Server(UserId uid, QString network); - ~Server(); - - UserId userId() const { return user; } - // serverState state(); - bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; } - QString getNetwork() { return network; } - QStringList providesUserHandlers(); - - enum CtcpType {CtcpQuery, CtcpReply}; - - public slots: - // void setServerOptions(); - void sendState(); - void connectToIrc(QString net); - void disconnectFromIrc(QString net); - void userInput(QString net, QString buffer, QString msg); - - void putRawLine(QString input); - void putCmd(QString cmd, QStringList params, QString prefix = 0); - - //void exitThread(); - - signals: - void serverState(QString net, QVariantMap data); - void recvRawServerMsg(QString); - void displayStatusMsg(QString); - //void displayMsg(Message msg); - void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); - void connected(QString network); - void disconnected(QString network); - - void nickAdded(QString network, QString nick, QVariantMap props); - void nickRenamed(QString network, QString oldnick, QString newnick); - void nickRemoved(QString network, QString nick); - void nickUpdated(QString network, QString nick, QVariantMap props); - void modeSet(QString network, QString target, QString mode); - void topicSet(QString network, QString buffer, QString topic); - void ownNickSet(QString network, QString newNick); - void queryRequested(QString network, QString nick); - - - private slots: - void run(); - void socketHasData(); - void socketError(QAbstractSocket::SocketError); - void socketConnected(); - void socketDisconnected(); - void socketStateChanged(QAbstractSocket::SocketState); - - /* Message Handlers */ - - /* void handleUser(QString, QString); */ - void handleUserAway(QString, QString); - void handleUserDeop(QString, QString); - void handleUserDevoice(QString, QString); - void handleUserInvite(QString, QString); - void handleUserJoin(QString, QString); - void handleUserKick(QString, QString); - void handleUserList(QString, QString); - void handleUserMode(QString, QString); - void handleUserMsg(QString, QString); - void handleUserNick(QString, QString); - void handleUserOp(QString, QString); - void handleUserPart(QString, QString); - void handleUserQuery(QString, QString); - void handleUserQuit(QString, QString); - void handleUserQuote(QString, QString); - void handleUserSay(QString, QString); - void handleUserTopic(QString, QString); - void handleUserVoice(QString, QString); - void handleUserMe(QString, QString); - - /* void handleServer(QString, QStringList); */ - void handleServerJoin(QString, QStringList); - void handleServerKick(QString, QStringList); - void handleServerMode(QString, QStringList); - void handleServerNick(QString, QStringList); - void handleServerNotice(QString, QStringList); - void handleServerPart(QString, QStringList); - void handleServerPing(QString, QStringList); - void handleServerPrivmsg(QString, QStringList); - void handleServerQuit(QString, QStringList); - void handleServerTopic(QString, QStringList); - - void handleServer001(QString, QStringList); // RPL_WELCOME - void handleServer005(QString, QStringList); // RPL_ISUPPORT - void handleServer331(QString, QStringList); // RPL_NOTOPIC - void handleServer332(QString, QStringList); // RPL_TOPIC - void handleServer333(QString, QStringList); // Topic set by... - void handleServer353(QString, QStringList); // RPL_NAMREPLY - void handleServer432(QString, QStringList); // ERR_ERRONEUSNICKNAME - void handleServer433(QString, QStringList); // ERR_NICKNAMEINUSE - - void handleCtcpAction(CtcpType, QString, QString, QString); - void handleCtcpPing(CtcpType, QString, QString, QString); - void handleCtcpVersion(CtcpType, QString, QString, QString); - - void defaultServerHandler(QString cmd, QString prefix, QStringList params); - void defaultUserHandler(QString buf, QString cmd, QString msg); - void defaultCtcpHandler(CtcpType ctcptype, QString prefix, QString cmd, QString target, QString param); - - private: - UserId user; - QString network; - QTcpSocket socket; - //QHash buffers; - - QString ownNick; - QString currentServer; - QVariantMap networkSettings; - QVariantMap identity; - QHash nicks; // stores all known nicks for the server - QHash topics; // stores topics for each buffer - QVariantMap serverSupports; // stores results from RPL_ISUPPORT - - void handleServerMsg(QByteArray rawMsg); - void handleUserInput(QString buffer, QString usrMsg); - - // CTCP Stuff - QString XDELIM; - QHash ctcpMDequoteHash; - QHash ctcpXDelimDequoteHash; - QString ctcpDequote(QString); - QString ctcpXdelimDequote(QString); - QStringList parseCtcp(CtcpType, QString, QString, QString); - - QString ctcpPack(QString ctcpTag, QString message); - void ctcpQuery(QString bufname, QString ctcpTag, QString message); - void ctcpReply(QString bufname, QString ctcpTag, QString message); - - QString updateNickFromMask(QString mask); +public: + Server(UserId uid, uint networkId, QString network); + ~Server(); + + UserId userId() const { return _userId; } + + // serverState state(); + bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; } + + uint networkId() const; + QString networkName(); // hasbeen getNetwork() + + NetworkInfo *networkInfo() { return _networkInfo; } + IrcServerHandler *ircServerHandler() {return _ircServerHandler; } + UserInputHandler *userInputHandler() {return _userInputHandler; } + CtcpHandler *ctcpHandler() {return _ctcpHandler; } + +public slots: + // void setServerOptions(); + void connectToIrc(QString net); + void disconnectFromIrc(QString net); + void userInput(uint netid, QString buffer, QString msg); + + void putRawLine(QString input); + void putCmd(QString cmd, QStringList params, QString prefix = 0); + + //void exitThread(); + +signals: + void serverState(QString net, QVariantMap data); + void recvRawServerMsg(QString); + void displayStatusMsg(QString); + //void displayMsg(Message msg); + void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void connected(uint networkId); + void disconnected(uint networkId); - class ParseError : public Exception { - public: - ParseError(QString cmd, QString prefix, QStringList params); - }; + void synchronizeClients(); + + void queryRequested(QString network, QString nick); - class UnknownCmdError : public Exception { - public: - UnknownCmdError(QString cmd, QString prefix, QStringList params); - }; + +private slots: + void run(); + void socketHasData(); + void socketError(QAbstractSocket::SocketError); + void socketConnected(); + void socketDisconnected(); + void socketStateChanged(QAbstractSocket::SocketState); + +private: + UserId _userId; + uint _networkId; + + QTcpSocket socket; + + IrcServerHandler *_ircServerHandler; + UserInputHandler *_userInputHandler; + CtcpHandler *_ctcpHandler; + + NetworkInfo *_networkInfo; + + QVariantMap networkSettings; + QVariantMap identity; + + CoreSession *coreSession() const; + + class ParseError : public Exception { + public: + ParseError(QString cmd, QString prefix, QStringList params); + }; + + class UnknownCmdError : public Exception { + public: + UnknownCmdError(QString cmd, QString prefix, QStringList params); + }; - // stuff needed for new separation of server information - ServerInfo *serverinfo; }; #endif diff --git a/src/core/serverinfo.cpp b/src/core/serverinfo.cpp deleted file mode 100644 index bc9fe640..00000000 --- a/src/core/serverinfo.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005-07 by The Quassel Team * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include "serverinfo.h" - -ServerInfo::ServerInfo(QObject *parent) - : QObject(parent) { -} - -ServerInfo::~ServerInfo() { -} - -void ServerInfo::setNetworkname(const QString &networkname) { - networkname_ = networkname; -} - -QString ServerInfo::networkname() const { - return networkname_; -} - -void ServerInfo::setCurrentServer(const QString ¤tServer) { - currentServer_ = currentServer; -} - -QString ServerInfo::currentServer() const { - return currentServer_; -} - -void ServerInfo::setOwnNick(const QString &ownnick) { - ownNick_ = ownnick; -} - -QString ServerInfo::ownNick() const { - return ownNick_; -} - -QList ServerInfo::ircUsers() const { - return ircUsers_.values(); -} - - -IrcUser *ServerInfo::newIrcUser(const QString &hostmask) { - IrcUser *ircuser = new IrcUser(hostmask); - return ircUsers_[ircuser->nick()] = ircuser; -} - -IrcUser *ServerInfo::ircUser(const QString &nickname) const { - if(ircUsers_.contains(nickname)) - return ircUsers_[nickname]; - else - throw NoSuchNickException(); -} - -void ServerInfo::setTopics(const QHash &topics) { - topics_ = topics; -} - -QHash ServerInfo::topics() const { - return topics_; -} - -void ServerInfo::updateTopic(const QString &channel, const QString &topic) { - topics_[channel] = topic; -} - -QString ServerInfo::topic(const QString &channel) const { - if(topics_.contains(channel)) - return topics_[channel]; - else - throw NoSuchChannelException(); -} - -void ServerInfo::setSupports(const QHash &supports) { - supports_ = supports; -} - -QHash ServerInfo::supports() const { - return supports_; -} - -QString ServerInfo::supports(const QString &feature) const { - if(supports_.contains(feature)) - return supports_[feature]; - else - throw UnsupportedFeatureException(); -} - -bool ServerInfo::isOwnNick(const QString &nick) const { - return (ownNick_.toLower() == nick.toLower()); -} - -bool ServerInfo::isOwnNick(const IrcUser &ircuser) const { - return (ircuser.nick().toLower() == ownNick_.toLower()); -} - - diff --git a/src/core/serverinfo.h b/src/core/serverinfo.h deleted file mode 100644 index 958c90af..00000000 --- a/src/core/serverinfo.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005/06 by The Quassel Team * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#ifndef _SERVERINFO_H_ -#define _SERVERINFO_H_ - -#include -#include -#include - -#include "global.h" -#include "ircuser.h" - -class ServerInfo : public QObject { - Q_OBJECT - - Q_PROPERTY(QString networkname READ networkname WRITE setNetworkname) - Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer) - Q_PROPERTY(QString ownNick READ ownNick WRITE setOwnNick) - Q_PROPERTY(QList ircUsers READ ircUsers) - -public: - ServerInfo(QObject *parent = 0); - ~ServerInfo(); - - void setNetworkname(const QString &networkname); - QString networkname() const; - - void setCurrentServer(const QString ¤tServer); - QString currentServer() const; - - void setOwnNick(const QString &ownnick); - QString ownNick() const; - - QList ircUsers() const; - IrcUser *newIrcUser(const QString &hostmask); - IrcUser *ircUser(const QString &nickname) const; - - void setTopics(const QHash &topics); - QHash topics() const; - - void updateTopic(const QString &channel, const QString &topic); - QString topic(const QString &channel) const; - - void setSupports(const QHash &supports); - QHash supports() const; - QString supports(const QString &feature) const; - - bool isOwnNick(const QString &nick) const; - bool isOwnNick(const IrcUser &ircuser) const; - -private: - QString networkname_; - QString currentServer_; - QString ownNick_; - - //QVariantMap networkSettings; - //QVariantMap identity; - - QHash ircUsers_; // stores all known nicks for the server - QHash topics_; // stores topics for each buffer - QHash supports_; // stores results from RPL_ISUPPORT -}; - -struct UnsupportedFeatureException : public Exception {}; - -#endif diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index 3d26a9b4..7ba61fcd 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -53,8 +53,8 @@ SqliteStorage::SqliteStorage() { createNetworkQuery = new QSqlQuery(logDb); createNetworkQuery->prepare("INSERT INTO network (userid, networkname) VALUES (:userid, :networkname)"); - getBufferIdQuery = new QSqlQuery(logDb); - getBufferIdQuery->prepare("SELECT bufferid FROM buffer " + getBufferInfoQuery = new QSqlQuery(logDb); + getBufferInfoQuery->prepare("SELECT bufferid FROM buffer " "JOIN network ON buffer.networkid = network.networkid " "WHERE network.networkname = :networkname AND buffer.userid = :userid AND buffer.buffername = :buffername "); @@ -120,7 +120,7 @@ SqliteStorage::~SqliteStorage() { delete requestMsgRangeQuery; delete createNetworkQuery; delete createBufferQuery; - delete getBufferIdQuery; + delete getBufferInfoQuery; logDb.close(); } @@ -307,32 +307,32 @@ uint SqliteStorage::getNetworkId(UserId user, const QString &network) { return 0; } -BufferId SqliteStorage::getBufferId(UserId user, const QString &network, const QString &buffer) { - BufferId bufferid; +BufferInfo SqliteStorage::getBufferInfo(UserId user, const QString &network, const QString &buffer) { + BufferInfo bufferid; uint networkId = getNetworkId(user, network); - getBufferIdQuery->bindValue(":networkname", network); - getBufferIdQuery->bindValue(":userid", user); - getBufferIdQuery->bindValue(":buffername", buffer); - getBufferIdQuery->exec(); + getBufferInfoQuery->bindValue(":networkname", network); + getBufferInfoQuery->bindValue(":userid", user); + getBufferInfoQuery->bindValue(":buffername", buffer); + getBufferInfoQuery->exec(); - if(!getBufferIdQuery->first()) { + if(!getBufferInfoQuery->first()) { createBuffer(user, network, buffer); - getBufferIdQuery->exec(); - if(getBufferIdQuery->first()) { - bufferid = BufferId(getBufferIdQuery->value(0).toUInt(), networkId, 0, network, buffer); - emit bufferIdUpdated(bufferid); + getBufferInfoQuery->exec(); + if(getBufferInfoQuery->first()) { + bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer); + emit bufferInfoUpdated(bufferid); } } else { - bufferid = BufferId(getBufferIdQuery->value(0).toUInt(), networkId, 0, network, buffer); + bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer); } - Q_ASSERT(!getBufferIdQuery->next()); + Q_ASSERT(!getBufferInfoQuery->next()); return bufferid; } -QList SqliteStorage::requestBuffers(UserId user, QDateTime since) { - QList bufferlist; +QList SqliteStorage::requestBuffers(UserId user, QDateTime since) { + QList bufferlist; QSqlQuery query(logDb); query.prepare("SELECT DISTINCT buffer.bufferid, networkname, buffername FROM buffer " "JOIN network ON buffer.networkid = network.networkid " @@ -348,7 +348,7 @@ QList SqliteStorage::requestBuffers(UserId user, QDateTime since) { query.exec(); while(query.next()) { - bufferlist << BufferId(query.value(0).toUInt(), getNetworkId(user, query.value(1).toString()), 0, query.value(1).toString(), query.value(2).toString()); + bufferlist << BufferInfo(query.value(0).toUInt(), getNetworkId(user, query.value(1).toString()), 0, query.value(1).toString(), query.value(2).toString()); } return bufferlist; } @@ -389,7 +389,7 @@ MsgId SqliteStorage::logMessage(Message msg) { } } -QList SqliteStorage::requestMsgs(BufferId buffer, int lastmsgs, int offset) { +QList SqliteStorage::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) { QList messagelist; // we have to determine the real offset first requestMsgsOffsetQuery->bindValue(":bufferid", buffer.uid()); @@ -418,7 +418,7 @@ QList SqliteStorage::requestMsgs(BufferId buffer, int lastmsgs, int off } -QList SqliteStorage::requestMsgs(BufferId buffer, QDateTime since, int offset) { +QList SqliteStorage::requestMsgs(BufferInfo buffer, QDateTime since, int offset) { QList messagelist; // we have to determine the real offset first requestMsgsSinceOffsetQuery->bindValue(":bufferid", buffer.uid()); @@ -449,7 +449,7 @@ QList SqliteStorage::requestMsgs(BufferId buffer, QDateTime since, int } -QList SqliteStorage::requestMsgRange(BufferId buffer, int first, int last) { +QList SqliteStorage::requestMsgRange(BufferInfo buffer, int first, int last) { QList messagelist; requestMsgRangeQuery->bindValue(":bufferid", buffer.uid()); requestMsgRangeQuery->bindValue(":bufferid2", buffer.uid()); diff --git a/src/core/sqlitestorage.h b/src/core/sqlitestorage.h index a4f5fec0..c8265d13 100644 --- a/src/core/sqlitestorage.h +++ b/src/core/sqlitestorage.h @@ -23,7 +23,6 @@ #include -#include "global.h" #include "storage.h" class QSqlQuery; @@ -56,15 +55,15 @@ class SqliteStorage : public Storage { virtual uint getNetworkId(UserId user, const QString &network); /* Buffer handling */ - virtual BufferId getBufferId(UserId user, const QString &network, const QString &buffer = ""); - virtual QList requestBuffers(UserId user, QDateTime since = QDateTime()); + virtual BufferInfo getBufferInfo(UserId user, const QString &network, const QString &buffer = ""); + virtual QList requestBuffers(UserId user, QDateTime since = QDateTime()); /* Message handling */ virtual MsgId logMessage(Message msg); - virtual QList requestMsgs(BufferId buffer, int lastmsgs = -1, int offset = -1); - virtual QList requestMsgs(BufferId buffer, QDateTime since, int offset = -1); - virtual QList requestMsgRange(BufferId buffer, int first, int last); + virtual QList requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1); + virtual QList requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1); + virtual QList requestMsgRange(BufferInfo buffer, int first, int last); public slots: //! This is just for importing the old file-based backlog */ @@ -75,7 +74,7 @@ class SqliteStorage : public Storage { void importOldBacklog(); signals: - void bufferIdUpdated(BufferId); + void bufferInfoUpdated(BufferInfo); protected: @@ -92,7 +91,7 @@ class SqliteStorage : public Storage { QSqlQuery *requestMsgRangeQuery; QSqlQuery *createNetworkQuery; QSqlQuery *createBufferQuery; - QSqlQuery *getBufferIdQuery; + QSqlQuery *getBufferInfoQuery; }; diff --git a/src/core/storage.cpp b/src/core/storage.cpp index 3c16dd3f..e7dcea54 100644 --- a/src/core/storage.cpp +++ b/src/core/storage.cpp @@ -31,7 +31,7 @@ void Storage::importOldBacklog() { logDb.exec(QString("DELETE FROM 'Backlog$%1$' WHERE SenderId != '$VERSION$'").arg(user)); logDb.exec(QString("DELETE FROM 'Senders$%1$'").arg(user)); logDb.exec(QString("DELETE FROM 'Buffers$%1$'").arg(user)); - nextMsgId = 1; nextBufferId = 1; nextSenderId = 1; + nextMsgId = 1; nextBufferInfo = 1; nextSenderId = 1; qDebug() << "Importing old backlog files..."; initBackLogOld(); if(!backLogEnabledOld) return; @@ -98,11 +98,11 @@ void Storage::initBackLogOld(UserId uid) { QString target = QString::fromUtf8(targ); QString sender = QString::fromUtf8(s); QString text = QString::fromUtf8(m); - BufferId id; + BufferInfo id; if((f & Message::PrivMsg) && !(f & Message::Self)) { - id = getBufferId(uid, net, sender); + id = getBufferInfo(uid, net, sender); } else { - id = getBufferId(uid, net, target); + id = getBufferInfo(uid, net, target); } Message msg(QDateTime::fromTime_t(ts), id, (Message::Type)t, text, sender, f); //backLog[net].append(m); diff --git a/src/core/storage.h b/src/core/storage.h index a0e05e53..f493721c 100644 --- a/src/core/storage.h +++ b/src/core/storage.h @@ -96,19 +96,19 @@ class Storage : public QObject { //! Get the unique NetworkId of the network for a user. /** \param user The core user who owns this buffername * \param network The network name - * \return The BufferId corresponding to the given network and buffer name, or 0 if not found + * \return The BufferInfo corresponding to the given network and buffer name, or 0 if not found */ virtual uint getNetworkId(UserId user, const QString &network) = 0; /* Buffer handling */ - //! Get the unique BufferId for the given combination of network and buffername for a user. + //! Get the unique BufferInfo for the given combination of network and buffername for a user. /** \param user The core user who owns this buffername * \param network The network name * \param buffer The buffer name (if empty, the net's status buffer is returned) - * \return The BufferId corresponding to the given network and buffer name, or 0 if not found + * \return The BufferInfo corresponding to the given network and buffer name, or 0 if not found */ - virtual BufferId getBufferId(UserId user, const QString &network, const QString &buffer = "") = 0; + virtual BufferInfo getBufferInfo(UserId user, const QString &network, const QString &buffer = "") = 0; //! Request a list of all buffers known to a user since a certain point in time. /** This method is used to get a list of all buffers we have stored a backlog from. @@ -116,9 +116,9 @@ class Storage : public QObject { * since that point in time. * \param user The user whose buffers we request * \param since If this is defined, older buffers will be ignored - * \return A list of the BufferIds for all buffers as requested + * \return A list of the BufferInfos for all buffers as requested */ - virtual QList requestBuffers(UserId user, QDateTime since = QDateTime()) = 0; + virtual QList requestBuffers(UserId user, QDateTime since = QDateTime()) = 0; /* Message handling */ @@ -134,7 +134,7 @@ class Storage : public QObject { * \param offset Do not return (but DO count) messages with MsgId >= offset, if offset >= 0 * \return The requested list of messages */ - virtual QList requestMsgs(BufferId buffer, int lastmsgs = -1, int offset = -1) = 0; + virtual QList requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1) = 0; //! Request messages stored in a given buffer since a certain point in time. /** \param buffer The buffer we request messages from @@ -142,7 +142,7 @@ class Storage : public QObject { * \param offset Do not return messages with MsgId >= offset, if offset >= 0 * \return The requested list of messages */ - virtual QList requestMsgs(BufferId buffer, QDateTime since, int offset = -1) = 0; + virtual QList requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1) = 0; //! Request a range of messages stored in a given buffer. /** \param buffer The buffer we request messages from @@ -150,7 +150,7 @@ class Storage : public QObject { * \param last Return messages with first <= MsgId <= last * \return The requested list of messages */ - virtual QList requestMsgRange(BufferId buffer, int first, int last) = 0; + virtual QList requestMsgRange(BufferInfo buffer, int first, int last) = 0; public slots: //! This is just for importing the old file-based backlog */ @@ -161,8 +161,8 @@ class Storage : public QObject { virtual void importOldBacklog() = 0; signals: - //! Sent when a new BufferId is created, or an existing one changed somehow. - void bufferIdUpdated(BufferId); + //! Sent when a new BufferInfo is created, or an existing one changed somehow. + void bufferInfoUpdated(BufferInfo); //! Sent when a new user has been added void userAdded(UserId, const QString &username); //! Sent when a user has been renamed diff --git a/src/core/userinputhandler.cpp b/src/core/userinputhandler.cpp new file mode 100644 index 00000000..5d4705e0 --- /dev/null +++ b/src/core/userinputhandler.cpp @@ -0,0 +1,183 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "userinputhandler.h" + +#include "util.h" + +#include "server.h" +#include "networkinfo.h" +#include "ctcphandler.h" + +#include + +UserInputHandler::UserInputHandler(Server *parent) + : BasicHandler(parent) { +} + +void UserInputHandler::handleUserInput(QString bufname, QString msg) { + try { + if(msg.isEmpty()) + return; + QString cmd; + if(!msg.startsWith('/')) { + cmd = QString("SAY"); + } else { + cmd = msg.section(' ', 0, 0).remove(0, 1).toUpper(); + msg = msg.section(' ', 1); + } + handle(cmd, Q_ARG(QString, bufname), Q_ARG(QString, msg)); + } catch(Exception e) { + emit displayMsg(Message::Error, "", e.msg()); + } +} + +// ==================== +// Public Slots +// ==================== + +void UserInputHandler::handleAway(QString bufname, QString msg) { + emit putCmd("AWAY", QStringList(msg)); +} + +void UserInputHandler::handleDeop(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o'; + QStringList params; + params << bufname << m << nicks; + emit putCmd("MODE", params); +} + +void UserInputHandler::handleDevoice(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'v'; + QStringList params; + params << bufname << m << nicks; + emit putCmd("MODE", params); +} + +void UserInputHandler::handleInvite(QString bufname, QString msg) { + QStringList params; + params << msg << bufname; + emit putCmd("INVITE", params); +} + +void UserInputHandler::handleJoin(QString bufname, QString msg) { + emit putCmd("JOIN", QStringList(msg)); +} + +void UserInputHandler::handleKick(QString bufname, QString msg) { + QStringList params; + params << bufname << msg.split(' ', QString::SkipEmptyParts); + emit putCmd("KICK", params); +} + +void UserInputHandler::handleList(QString bufname, QString msg) { + emit putCmd("LIST", msg.split(' ', QString::SkipEmptyParts)); +} + +void UserInputHandler::handleMode(QString bufname, QString msg) { + emit putCmd("MODE", msg.split(' ', QString::SkipEmptyParts)); +} + +// TODO: show privmsgs +void UserInputHandler::handleMsg(QString bufname, QString msg) { + QString nick = msg.section(" ", 0, 0); + msg = msg.section(" ", 1); + if(nick.isEmpty() || msg.isEmpty()) return; + QStringList params; + params << nick << msg; + emit putCmd("PRIVMSG", params); +} + +void UserInputHandler::handleNick(QString bufname, QString msg) { + QString nick = msg.section(' ', 0, 0); + emit putCmd("NICK", QStringList(nick)); +} + +void UserInputHandler::handleOp(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'o'; + QStringList params; + params << bufname << m << nicks; + emit putCmd("MODE", params); +} + +void UserInputHandler::handlePart(QString bufname, QString msg) { + QStringList params; + params << bufname << msg; + emit putCmd("PART", params); +} + +// TODO: implement queries +void UserInputHandler::handleQuery(QString bufname, QString msg) { + QString nick = msg.section(' ', 0, 0); + // TODO: usenetworkids +// if(!nick.isEmpty()) +// emit queryRequested(network, nick); +} + +void UserInputHandler::handleQuit(QString bufname, QString msg) { + emit putCmd("QUIT", QStringList(msg)); +} + +void UserInputHandler::handleQuote(QString bufname, QString msg) { + emit putRawLine(msg); +} + +void UserInputHandler::handleSay(QString bufname, QString msg) { + if(bufname.isEmpty()) return; // server buffer + QStringList params; + params << bufname << msg; + emit putCmd("PRIVMSG", params); + if(isChannelName(bufname)) { + emit displayMsg(Message::Plain, params[0], msg, networkInfo()->myNick(), Message::Self); + } else { + emit displayMsg(Message::Plain, params[0], msg, networkInfo()->myNick(), Message::Self|Message::PrivMsg); + } +} + +void UserInputHandler::handleMe(QString bufname, QString msg) { + if(bufname.isEmpty()) return; // server buffer + server->ctcpHandler()->query(bufname, "ACTION", msg); + emit displayMsg(Message::Action, bufname, msg, networkInfo()->myNick()); +} + +void UserInputHandler::handleTopic(QString bufname, QString msg) { + if(bufname.isEmpty()) return; + QStringList params; + params << bufname << msg; + emit putCmd("TOPIC", params); +} + +void UserInputHandler::handleVoice(QString bufname, QString msg) { + QStringList nicks = msg.split(' ', QString::SkipEmptyParts); + QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'v'; + QStringList params; + params << bufname << m << nicks; + emit putCmd("MODE", params); +} + + +void UserInputHandler::defaultHandler(QString cmd, QString bufname, QString msg) { + emit displayMsg(Message::Error, "", QString("Error: %1 %2").arg(cmd).arg(msg)); + +} + + diff --git a/src/core/userinputhandler.h b/src/core/userinputhandler.h new file mode 100644 index 00000000..014a7c53 --- /dev/null +++ b/src/core/userinputhandler.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _USERINPUTHANDLER_H_ +#define _USERINPUTHANDLER_H_ + +#include "basichandler.h" + +class Server; + +class UserInputHandler : public BasicHandler { + Q_OBJECT + +public: + UserInputHandler(Server *parent = 0); + + void handleUserInput(QString buffer, QString msg); + +public slots: + void handleAway(QString, QString); + void handleDeop(QString, QString); + void handleDevoice(QString, QString); + void handleInvite(QString, QString); + void handleJoin(QString, QString); + void handleKick(QString, QString); + void handleList(QString, QString); + void handleMode(QString, QString); + void handleMsg(QString, QString); + void handleNick(QString, QString); + void handleOp(QString, QString); + void handlePart(QString, QString); + void handleQuery(QString, QString); + void handleQuit(QString, QString); + void handleQuote(QString, QString); + void handleSay(QString, QString); + void handleTopic(QString, QString); + void handleVoice(QString, QString); + void handleMe(QString, QString); + + void defaultHandler(QString cmd, QString buf, QString msg); + +}; + + +#endif diff --git a/src/qtgui/bufferviewfilter.cpp b/src/qtgui/bufferviewfilter.cpp index 8c563902..8dca8fa2 100644 --- a/src/qtgui/bufferviewfilter.cpp +++ b/src/qtgui/bufferviewfilter.cpp @@ -65,11 +65,11 @@ void BufferViewFilter::dropEvent(QDropEvent *event) { if(!(data->hasFormat("application/Quassel/BufferItem/row") && data->hasFormat("application/Quassel/BufferItem/network") - && data->hasFormat("application/Quassel/BufferItem/bufferId"))) + && data->hasFormat("application/Quassel/BufferItem/bufferInfo"))) return; // whatever the drop is... it's not a buffer... event->accept(); - uint bufferuid = data->data("application/Quassel/BufferItem/bufferId").toUInt(); + uint bufferuid = data->data("application/Quassel/BufferItem/bufferInfo").toUInt(); QString networkname = QString::fromUtf8("application/Quassel/BufferItem/network"); for(int rowid = 0; rowid < rowCount(); rowid++) { @@ -99,7 +99,7 @@ void BufferViewFilter::removeBuffer(const QModelIndex &index) { if(index.parent() == QModelIndex()) return; // only child elements can be deleted - uint bufferuid = index.data(BufferTreeModel::BufferIdRole).toUInt(); + uint bufferuid = index.data(BufferTreeModel::BufferInfoRole).toUInt(); if(customBuffers.contains(bufferuid)) { beginRemoveRows(index.parent(), index.row(), index.row()); customBuffers.removeAt(customBuffers.indexOf(bufferuid)); @@ -121,7 +121,7 @@ bool BufferViewFilter::filterAcceptBuffer(const QModelIndex &source_bufferIndex) if((mode & NoInactive) && !isActive) return false; if((mode & FullCustom)) { - uint bufferuid = source_bufferIndex.data(BufferTreeModel::BufferIdRole).toUInt(); + uint bufferuid = source_bufferIndex.data(BufferTreeModel::BufferInfoRole).toUInt(); if(!customBuffers.contains(bufferuid)) return false; } @@ -138,7 +138,7 @@ bool BufferViewFilter::filterAcceptNetwork(const QModelIndex &source_index) cons int childcount = sourceModel()->rowCount(source_index); for(int rowid = 0; rowid < childcount; rowid++) { QModelIndex child = sourceModel()->index(rowid, 0, source_index); - uint bufferuid = child.data(BufferTreeModel::BufferIdRole).toUInt(); + uint bufferuid = child.data(BufferTreeModel::BufferInfoRole).toUInt(); if(customBuffers.contains(bufferuid)) return true; } diff --git a/src/qtgui/chatline.cpp b/src/qtgui/chatline.cpp index 4c031529..335e15b7 100644 --- a/src/qtgui/chatline.cpp +++ b/src/qtgui/chatline.cpp @@ -122,7 +122,7 @@ uint ChatLine::msgId() const { return msg.buffer().uid(); } -BufferId ChatLine::bufferId() const { +BufferInfo ChatLine::bufferInfo() const { return msg.buffer(); } diff --git a/src/qtgui/chatline.h b/src/qtgui/chatline.h index ac803634..2707a171 100644 --- a/src/qtgui/chatline.h +++ b/src/qtgui/chatline.h @@ -59,7 +59,7 @@ class ChatLine : public QObject, public AbstractUiMsg { QString sender() const; QString text() const; MsgId msgId() const; - BufferId bufferId() const; + BufferInfo bufferInfo() const; bool isUrl(int pos) const; QUrl getUrl(int pos) const; diff --git a/src/qtgui/mainwin.cpp b/src/qtgui/mainwin.cpp index 36b36759..fc4f8ed8 100644 --- a/src/qtgui/mainwin.cpp +++ b/src/qtgui/mainwin.cpp @@ -29,6 +29,8 @@ //#include "settingspage.h" #include "signalproxy.h" +#include "topicwidget.h" + MainWin::MainWin(QtGui *_gui, QWidget *parent) : QMainWindow(parent), gui(_gui) { ui.setupUi(this); setWindowTitle("Quassel IRC"); @@ -41,7 +43,7 @@ MainWin::MainWin(QtGui *_gui, QWidget *parent) : QMainWindow(parent), gui(_gui) } void MainWin::init() { - Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferId, QVariant, QVariant))); + Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant))); ui.bufferWidget->init(); show(); @@ -56,9 +58,6 @@ void MainWin::init() { systray->setIcon(QIcon(":/qirc-icon.png")); systray->show(); - serverListDlg = new ServerListDlg(this); - serverListDlg->setVisible(serverListDlg->showOnStartup()); - //setupSettingsDlg(); setupMenus(); @@ -79,6 +78,29 @@ void MainWin::init() { disconnectedFromCore(); // Disable menus and stuff showCoreConnectionDlg(true); // autoconnect if appropriate //ui.actionConnectCore->activate(QAction::Trigger); + + serverListDlg = new ServerListDlg(this); + if(serverListDlg->showOnStartup()) { + showServerList(); + } + + // TESTING +// setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); +// setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + +// setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); +// setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); + +// QDockWidget *dock = new QDockWidget("Topic Dock", this); +// dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + +// TopicWidget *topicwidget = new TopicWidget(dock); +// dock->setWidget(topicwidget); + +// addDockWidget(Qt::TopDockWidgetArea, dock); + +// ui.menuViews->addAction(dock->toggleViewAction()); + } MainWin::~MainWin() { @@ -143,7 +165,7 @@ void MainWin::addBufferView(const QString &viewname, QAbstractItemModel *model, } void MainWin::connectedToCore() { - foreach(BufferId id, Client::allBufferIds()) { + foreach(BufferInfo id, Client::allBufferInfos()) { emit requestBacklog(id, 100, -1); } @@ -217,12 +239,12 @@ void MainWin::closeEvent(QCloseEvent *event) //} } -void MainWin::showBuffer(BufferId id) { +void MainWin::showBuffer(BufferInfo id) { showBuffer(Client::buffer(id)); } void MainWin::showBuffer(Buffer *b) { - currentBuffer = b->bufferId().groupId(); + currentBuffer = b->bufferInfo().groupId(); //emit bufferSelected(b); //qApp->processEvents(); diff --git a/src/qtgui/mainwin.h b/src/qtgui/mainwin.h index f5224492..c99b42fe 100644 --- a/src/qtgui/mainwin.h +++ b/src/qtgui/mainwin.h @@ -60,7 +60,7 @@ class MainWin : public QMainWindow { void showCoreConnectionDlg(bool autoConnect = false); void coreConnectionDlgFinished(int result); - void showBuffer(BufferId); + void showBuffer(BufferInfo); void showBuffer(Buffer *); void importBacklog(); @@ -68,7 +68,7 @@ class MainWin : public QMainWindow { signals: void connectToCore(const QVariantMap &connInfo); void disconnectFromCore(); - void requestBacklog(BufferId, QVariant, QVariant); + void requestBacklog(BufferInfo, QVariant, QVariant); void importOldBacklog(); private: diff --git a/src/qtgui/qtgui.pri b/src/qtgui/qtgui.pri index c8dd0f8c..914b80f9 100644 --- a/src/qtgui/qtgui.pri +++ b/src/qtgui/qtgui.pri @@ -3,15 +3,15 @@ QT_MOD = core gui network SRCS += bufferview.cpp bufferviewfilter.cpp bufferwidget.cpp channelwidgetinput.cpp chatline.cpp \ chatwidget.cpp coreconnectdlg.cpp \ - guisettings.cpp identities.cpp mainwin.cpp qtgui.cpp serverlist.cpp settingsdlg.cpp style.cpp tabcompleter.cpp + guisettings.cpp identities.cpp mainwin.cpp qtgui.cpp serverlist.cpp settingsdlg.cpp style.cpp tabcompleter.cpp topicwidget.cpp HDRS += bufferview.h bufferviewfilter.h bufferwidget.h channelwidgetinput.h chatline.h chatwidget.h coreconnectdlg.h \ - guisettings.h identities.h mainwin.h qtgui.h serverlist.h settingsdlg.h settingspage.h style.h tabcompleter.h + guisettings.h identities.h mainwin.h qtgui.h serverlist.h settingsdlg.h settingspage.h style.h tabcompleter.h topicwidget.h FORMNAMES = identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui nickeditdlg.ui serverlistdlg.ui \ servereditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui settingsdlg.ui \ - buffermgmtpage.ui connectionpage.ui usermgmtpage.ui + buffermgmtpage.ui connectionpage.ui usermgmtpage.ui topicwidget.ui for(ui, FORMNAMES) { FRMS += ui/$${ui} diff --git a/src/qtgui/topicwidget.cpp b/src/qtgui/topicwidget.cpp new file mode 100644 index 00000000..a16807f0 --- /dev/null +++ b/src/qtgui/topicwidget.cpp @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "topicwidget.h" + +#include + +TopicWidget::TopicWidget(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); + ui.topicLineEdit->setText("+++ DUMMY TOPIC +++ DUMMY TOPIC +++"); +} + +TopicWidget::~TopicWidget() { +} diff --git a/src/qtgui/topicwidget.h b/src/qtgui/topicwidget.h new file mode 100644 index 00000000..d6c1ab9c --- /dev/null +++ b/src/qtgui/topicwidget.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2005/06 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _TOPICWIDGET_H_ +#define _TOPICWIDGET_H_ + +#include + +#include "ui_topicwidget.h" + +class TopicWidget : public QWidget { + Q_OBJECT + +public: + TopicWidget(QWidget *parent = 0); + virtual ~TopicWidget(); + + +private: + Ui::TopicWidget ui; +}; + + +#endif diff --git a/src/qtgui/ui/topicwidget.ui b/src/qtgui/ui/topicwidget.ui new file mode 100644 index 00000000..9d3edb1d --- /dev/null +++ b/src/qtgui/ui/topicwidget.ui @@ -0,0 +1,60 @@ + + TopicWidget + + + + 0 + 0 + 568 + 25 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + ... + + + + + + + + diff --git a/src/qtopia/chatline.cpp b/src/qtopia/chatline.cpp index 28ce89d8..c1e9956f 100644 --- a/src/qtopia/chatline.cpp +++ b/src/qtopia/chatline.cpp @@ -39,8 +39,8 @@ MsgId ChatLine::msgId() const { return _msgId; } -BufferId ChatLine::bufferId() const { - return _bufferId; +BufferInfo ChatLine::bufferInfo() const { + return _bufferInfo; } QDateTime ChatLine::timeStamp() const { diff --git a/src/qtopia/chatline.h b/src/qtopia/chatline.h index 13d30678..c6daddd6 100644 --- a/src/qtopia/chatline.h +++ b/src/qtopia/chatline.h @@ -30,13 +30,13 @@ class ChatLine : public AbstractUiMsg { virtual QString sender() const; virtual QString text() const; virtual MsgId msgId() const; - virtual BufferId bufferId() const; + virtual BufferInfo bufferInfo() const; virtual QDateTime timeStamp() const; private: QString _sender, _text; MsgId _msgId; - BufferId _bufferId; + BufferInfo _bufferInfo; QDateTime _timeStamp; }; diff --git a/src/qtopia/qtopiamainwin.cpp b/src/qtopia/qtopiamainwin.cpp index bbeb4569..1991da9f 100644 --- a/src/qtopia/qtopiamainwin.cpp +++ b/src/qtopia/qtopiamainwin.cpp @@ -34,10 +34,10 @@ QtopiaMainWin::QtopiaMainWin(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { qRegisterMetaType("QVariant"); qRegisterMetaType("Message"); - qRegisterMetaType("BufferId"); + qRegisterMetaType("BufferInfo"); qRegisterMetaTypeStreamOperators("QVariant"); qRegisterMetaTypeStreamOperators("Message"); - qRegisterMetaTypeStreamOperators("BufferId"); + qRegisterMetaTypeStreamOperators("BufferInfo"); Global::runMode = Global::ClientOnly; @@ -68,7 +68,7 @@ QtopiaMainWin::QtopiaMainWin(QWidget *parent, Qt::WFlags flags) : QMainWindow(pa // at this point, client is fully initialized void QtopiaMainWin::init() { - Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferId, QVariant, QVariant))); + Client::signalProxy()->attachSignal(this, SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant))); connect(Client::bufferModel(), SIGNAL(bufferSelected(Buffer *)), this, SLOT(showBuffer(Buffer *))); CoreConnectDlg *dlg = new CoreConnectDlg(this); @@ -83,12 +83,12 @@ QtopiaMainWin::~QtopiaMainWin() { } void QtopiaMainWin::connectedToCore() { - foreach(BufferId id, Client::allBufferIds()) { + foreach(BufferInfo id, Client::allBufferInfos()) { emit requestBacklog(id, 100, -1); } // FIXME just for testing: select first available buffer - if(Client::allBufferIds().count()) { - Buffer *b = Client::buffer(Client::allBufferIds()[0]); + if(Client::allBufferInfos().count()) { + Buffer *b = Client::buffer(Client::allBufferInfos()[0]); Client::bufferModel()->selectBuffer(b); } } diff --git a/src/qtopia/qtopiamainwin.h b/src/qtopia/qtopiamainwin.h index 5d3ab9eb..70ab8913 100644 --- a/src/qtopia/qtopiamainwin.h +++ b/src/qtopia/qtopiamainwin.h @@ -44,7 +44,7 @@ class QtopiaMainWin : public QMainWindow { signals: void connectToCore(const QVariantMap &connInfo); void disconnectFromCore(); - void requestBacklog(BufferId, QVariant, QVariant); + void requestBacklog(BufferInfo, QVariant, QVariant); private slots: void showBuffer(Buffer *); -- 2.20.1