From: Manuel Nickschas Date: Thu, 17 Jan 2008 22:36:12 +0000 (+0000) Subject: This is the long-awaited monster commit, bringing you a redesigned core arch and... X-Git-Tag: 0.2.0-alpha1~226 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=d1b6499b0b848d4287efae89107576548533502c This is the long-awaited monster commit, bringing you a redesigned core arch and new auth method... NOT STABLE! DO NOT USE! WORK IN PROGRESS! NOT CLEANED UP! NOT TESTED! YOU HAVE BEEN WARNED! Known regressions: * Networks always use the Default Identity from the _new_ dialog (accessible via the new SettingsDlg) * No core config wizard. Will be back soon. * No session save/restore, Will be back soon. * Some more things, that you'll notice anyway. --- diff --git a/Quassel.kdevelop.filelist b/Quassel.kdevelop.filelist index a43f8889..fe1d9fa1 100644 --- a/Quassel.kdevelop.filelist +++ b/Quassel.kdevelop.filelist @@ -36,6 +36,8 @@ src/client/client.h src/client/client.pri src/client/clientsettings.cpp src/client/clientsettings.h +src/client/clientsyncer.cpp +src/client/clientsyncer.h src/client/mappedselectionmodel.cpp src/client/mappedselectionmodel.h src/client/modelpropertymapper.cpp @@ -68,8 +70,6 @@ src/common/message.cpp src/common/message.h src/common/network.cpp src/common/network.h -src/common/networkinfo.cpp -src/common/networkinfo.h src/common/settings.cpp src/common/settings.h src/common/signalproxy.cpp @@ -99,8 +99,8 @@ src/core/ircserverhandler.cpp src/core/ircserverhandler.h src/core/networkconnection.cpp src/core/networkconnection.h -src/core/server.cpp -src/core/server.h +src/core/sessionthread.cpp +src/core/sessionthread.h src/core/sqlitestorage.cpp src/core/sqlitestorage.h src/core/storage.cpp @@ -188,7 +188,6 @@ src/qtui/settingspages/identitiessettingspage.cpp src/qtui/settingspages/identitiessettingspage.h src/qtui/settingspages/identitiessettingspage.ui src/qtui/settingspages/networkssettingspage.ui -src/qtui/settingspages/nickeditdlg.ui src/qtui/settingspages/nickeditdlgnew.ui src/qtui/settingspages/saveidentitiesdlg.ui src/qtui/settingspages/servereditdlg.ui diff --git a/build/targets/target.pri b/build/targets/target.pri index 1441f63c..1f023b2f 100644 --- a/build/targets/target.pri +++ b/build/targets/target.pri @@ -15,6 +15,7 @@ for(mod, MODULES) { LIBS *= -L../modules/$$dirname(mod) -l$$basename(mod) PRE_TARGETDEPS *= ../modules/$$mod } +PRE_TARGETDEPS *= ../../version.inc #CONTRIB += libqxt # not needed #include(../contrib/contrib.pri) diff --git a/src/client/client.cpp b/src/client/client.cpp index 1bf07596..34c903ea 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -45,7 +45,8 @@ Client *Client::instance() { } void Client::destroy() { - delete instanceptr; + //delete instanceptr; + instanceptr->deleteLater(); } void Client::init(AbstractUi *ui) { @@ -61,15 +62,16 @@ Client::Client(QObject *parent) _networkModel(0), _bufferModel(0), _nickModel(0), - connectedToCore(false) + _connectedToCore(false), + _syncedToCore(false) { } Client::~Client() { + disconnectFromCore(); } void Client::init() { - blockSize = 0; _networkModel = new NetworkModel(this); connect(this, SIGNAL(bufferUpdated(BufferInfo)), @@ -77,18 +79,16 @@ void Client::init() { _bufferModel = new BufferModel(_networkModel); _nickModel = new NickModel(_networkModel); - + 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(networkConnected(uint)), - this, SLOT(networkConnected(uint))); - p->attachSlot(SIGNAL(networkDisconnected(uint)), - this, SLOT(networkDisconnected(uint))); + //p->attachSlot(SIGNAL(networkConnected(uint)), + //FIXME this, SLOT(networkConnected(uint))); + //p->attachSlot(SIGNAL(networkDisconnected(uint)), + //FIXME this, SLOT(networkDisconnected(uint))); p->attachSlot(SIGNAL(displayMsg(const Message &)), this, SLOT(recvMessage(const Message &))); p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)), @@ -106,7 +106,9 @@ void Client::init() { p->attachSlot(SIGNAL(identityCreated(const Identity &)), this, SLOT(coreIdentityCreated(const Identity &))); p->attachSlot(SIGNAL(identityRemoved(IdentityId)), this, SLOT(coreIdentityRemoved(IdentityId))); - connect(mainUi, SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &))); + connect(p, SIGNAL(disconnected()), this, SLOT(disconnectFromCore())); + + //connect(mainUi, SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &))); connect(mainUi, SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore())); connect(this, SIGNAL(connected()), mainUi, SLOT(connectedToCore())); connect(this, SIGNAL(disconnected()), mainUi, SLOT(disconnectedFromCore())); @@ -122,12 +124,12 @@ void Client::init() { QList Client::networks() { - return instance()->_network.values(); + return instance()->_networks.values(); } Network *Client::network(uint networkid) { - if(instance()->_network.contains(networkid)) - return instance()->_network[networkid]; + if(instance()->_networks.contains(networkid)) + return instance()->_networks[networkid]; else return 0; } @@ -144,13 +146,16 @@ QList Client::buffers() { return instance()->_buffers.values(); } -Buffer *Client::buffer(uint bufferUid) { + +// FIXME remove +Buffer *Client::buffer(BufferId bufferUid) { if(instance()->_buffers.contains(bufferUid)) return instance()->_buffers[bufferUid]; else return 0; } +// FIXME remove Buffer *Client::buffer(BufferInfo id) { Buffer *buff = buffer(id.uid()); @@ -169,6 +174,7 @@ Buffer *Client::buffer(BufferInfo id) { return buff; } + NetworkModel *Client::networkModel() { return instance()->_networkModel; } @@ -186,6 +192,13 @@ SignalProxy *Client::signalProxy() { return instance()->_signalProxy; } +bool Client::isConnected() { + return instance()->_connectedToCore; +} + +bool Client::isSynced() { + return instance()->_syncedToCore; +} /*** Identity handling ***/ @@ -198,7 +211,6 @@ const Identity * Client::identity(IdentityId id) { else return 0; } - void Client::createIdentity(const Identity &id) { emit instance()->requestCreateIdentity(id); } @@ -233,11 +245,6 @@ void Client::coreIdentityRemoved(IdentityId id) { /*** ***/ - -bool Client::isConnected() { - return instance()->connectedToCore; -} - void Client::fakeInput(uint bufferUid, QString message) { Buffer *buff = buffer(bufferUid); if(!buff) @@ -250,65 +257,31 @@ void Client::fakeInput(BufferInfo bufferInfo, QString message) { fakeInput(bufferInfo, message); } -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(conn["Host"].toString().isEmpty()) { - clientMode = LocalCore; - socket = new QBuffer(this); - connect(socket, SIGNAL(readyRead()), this, SLOT(coreHasData())); - socket->open(QIODevice::ReadWrite); - //QVariant state = connectToLocalCore(coreConnectionInfo["User"].toString(), coreConnectionInfo["Password"].toString()); - //syncToCore(state); - coreSocketConnected(); - } else { - clientMode = RemoteCore; - emit coreConnectionMsg(tr("Connecting...")); - Q_ASSERT(!socket); - QTcpSocket *sock = new QTcpSocket(this); - socket = sock; - connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData())); - connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected())); - connect(signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); - connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError))); - sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt()); - } -} - -void Client::disconnectFromCore() { - socket->close(); -} +/*** core connection stuff ***/ -void Client::setCoreConfiguration(const QVariantMap &settings) { - SignalProxy::writeDataToDevice(socket, settings); +void Client::setConnectedToCore(QIODevice *sock) { + socket = sock; + signalProxy()->addPeer(socket); + _connectedToCore = true; } -void Client::coreSocketConnected() { - connect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint))); - emit coreConnectionMsg(tr("Synchronizing to core...")); - QVariantMap clientInit; - clientInit["GuiProtocol"] = GUI_PROTOCOL; - clientInit["User"] = coreConnectionInfo["User"].toString(); - clientInit["Password"] = coreConnectionInfo["Password"].toString(); - SignalProxy::writeDataToDevice(socket, clientInit); +void Client::setSyncedToCore() { + _syncedToCore = true; + emit connected(); + emit coreConnectionStateChanged(true); } -void Client::coreSocketDisconnected() { - instance()->connectedToCore = false; +void Client::disconnectFromCore() { + if(socket) { + socket->close(); + socket->deleteLater(); + } + _connectedToCore = false; + _syncedToCore = false; emit disconnected(); emit coreConnectionStateChanged(false); - socket->deleteLater(); - blockSize = 0; - /* Clear internal data. Hopefully nothing relies on it at this point. */ + // Clear internal data. Hopefully nothing relies on it at this point. _networkModel->clear(); QHash::iterator bufferIter = _buffers.begin(); @@ -321,14 +294,14 @@ void Client::coreSocketDisconnected() { Q_ASSERT(_buffers.isEmpty()); - QHash::iterator netIter = _network.begin(); - while(netIter != _network.end()) { + QHash::iterator netIter = _networks.begin(); + while(netIter != _networks.end()) { Network *net = netIter.value(); disconnect(net, SIGNAL(destroyed()), this, 0); - netIter = _network.erase(netIter); + netIter = _networks.erase(netIter); net->deleteLater(); } - Q_ASSERT(_network.isEmpty()); + Q_ASSERT(_networks.isEmpty()); QHash::iterator idIter = _identities.begin(); while(idIter != _identities.end()) { @@ -339,116 +312,16 @@ void Client::coreSocketDisconnected() { } Q_ASSERT(_identities.isEmpty()); - coreConnectionInfo.clear(); sessionData.clear(); layoutQueue.clear(); layoutTimer->stop(); } -void Client::recvCoreState(const QVariant &state) { - disconnect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint))); - disconnect(socket, 0, this, 0); // rest of communication happens through SignalProxy - signalProxy()->addPeer(socket); - syncToCore(state); -} - -// TODO: auth errors -void Client::syncToCore(const QVariant &coreState) { - if(!coreState.toMap().contains("SessionState")) { - emit coreConnectionError(tr("Invalid data received from core!")); - disconnectFromCore(); - return; - } - - QVariantMap sessionState = coreState.toMap()["SessionState"].toMap(); - - // store sessionData - QVariantMap sessData = sessionState["SessionData"].toMap(); - foreach(QString key, sessData.keys()) - recvSessionData(key, sessData[key]); - - // create identities - foreach(QVariant vid, sessionState["Identities"].toList()) { - coreIdentityCreated(vid.value()); - } - - // store Buffer details - QVariantList coreBuffers = sessionState["Buffers"].toList(); - /* make lookups by id faster */ - foreach(QVariant vid, coreBuffers) { - buffer(vid.value()); // create all buffers, so we see them in the network views - } - - // create network objects - QVariantList networkids = sessionState["Networks"].toList(); - foreach(QVariant networkid, networkids) { - networkConnected(networkid.toUInt()); - } - - instance()->connectedToCore = true; - updateCoreConnectionProgress(); - +void Client::setCoreConfiguration(const QVariantMap &settings) { + SignalProxy::writeDataToDevice(socket, settings); } -void Client::updateCoreConnectionProgress() { - // we'll do this in three steps: - // 1.) networks - // 2.) channels - // 3.) ircusers - - int numNets = networks().count(); - int numNetsWaiting = 0; - - int numIrcUsers = 0; - int numIrcUsersWaiting = 0; - - int numChannels = 0; - int numChannelsWaiting = 0; - - foreach(Network *net, networks()) { - if(! net->initialized()) - numNetsWaiting++; - - numIrcUsers += net->ircUsers().count(); - foreach(IrcUser *user, net->ircUsers()) { - if(! user->initialized()) - numIrcUsersWaiting++; - } - - numChannels += net->ircChannels().count(); - foreach(IrcChannel *channel, net->ircChannels()) { - if(! channel->initialized()) - numChannelsWaiting++; - } - } - - if(numNetsWaiting > 0) { - emit coreConnectionMsg(tr("Requesting network states...")); - emit coreConnectionProgress(numNets - numNetsWaiting, numNets); - return; - } - - 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(); - emit coreConnectionStateChanged(true); - foreach(Network *net, networks()) { - disconnect(net, 0, this, SLOT(updateCoreConnectionProgress())); - } - - // signalProxy()->dumpProxyStats(); -} +/*** Session data ***/ void Client::recvSessionData(const QString &key, const QVariant &data) { sessionData[key] = data; @@ -472,31 +345,9 @@ QStringList Client::sessionDataKeys() { return instance()->sessionData.keys(); } -void Client::coreSocketError(QAbstractSocket::SocketError) { - emit coreConnectionError(socket->errorString()); - socket->deleteLater(); -} - -void Client::coreHasData() { - QVariant item; - if(SignalProxy::readDataFromDevice(socket, blockSize, item)) { - emit recvPartialItem(1,1); - QVariantMap msg = item.toMap(); - if (!msg["StartWizard"].toBool()) { - recvCoreState(msg["Reply"]); - } else { - qWarning("Core not configured!"); - qDebug() << "Available storage providers: " << msg["StorageProviders"].toStringList(); - emit showConfigWizard(msg); - } - blockSize = 0; - return; - } - if(blockSize > 0) { - emit recvPartialItem(socket->bytesAvailable(), blockSize); - } -} +/*** ***/ +/* void Client::networkConnected(uint netid) { // TODO: create statusBuffer / switch to networkids //BufferInfo id = statusBufferInfo(net); @@ -506,29 +357,40 @@ void Client::networkConnected(uint netid) { Network *netinfo = new Network(netid, this); netinfo->setProxy(signalProxy()); networkModel()->attachNetwork(netinfo); - - if(!isConnected()) { - connect(netinfo, SIGNAL(initDone()), this, SLOT(updateCoreConnectionProgress())); - connect(netinfo, SIGNAL(ircUserInitDone()), this, SLOT(updateCoreConnectionProgress())); - connect(netinfo, SIGNAL(ircChannelInitDone()), this, SLOT(updateCoreConnectionProgress())); - } connect(netinfo, SIGNAL(destroyed()), this, SLOT(networkDestroyed())); - _network[netid] = netinfo; + _networks[netid] = netinfo; } -void Client::networkDisconnected(uint networkid) { - if(!_network.contains(networkid)) { +void Client::networkDisconnected(NetworkId networkid) { + if(!_networks.contains(networkid)) { qWarning() << "Client::networkDisconnected(uint): unknown Network" << networkid; return; } - Network *net = _network.take(networkid); - if(!net->initialized()) { + Network *net = _networks.take(networkid); + if(!net->isInitialized()) { qDebug() << "Network" << networkid << "disconnected while not yet initialized!"; updateCoreConnectionProgress(); } net->deleteLater(); } +*/ + +void Client::addNetwork(NetworkId netid) { + Network *net = new Network(netid, instance()); + addNetwork(net); +} + +void Client::addNetwork(Network *net) { + net->setProxy(signalProxy()); + signalProxy()->synchronize(net); + networkModel()->attachNetwork(net); + connect(net, SIGNAL(destroyed()), instance(), SLOT(networkDestroyed())); + instance()->_networks[net->networkId()] = net; + //if(net->networkId() == 1) net->requestConnect(); // FIXME +} + +/*** ***/ void Client::updateBufferInfo(BufferInfo id) { emit bufferUpdated(id); @@ -548,9 +410,9 @@ void Client::bufferDestroyed() { void Client::networkDestroyed() { Network *netinfo = static_cast(sender()); - uint networkId = netinfo->networkId(); - if(_network.contains(networkId)) - _network.remove(networkId); + NetworkId networkId = netinfo->networkId(); + if(_networks.contains(networkId)) + _networks.remove(networkId); } void Client::recvMessage(const Message &msg) { diff --git a/src/client/client.h b/src/client/client.h index d99534bc..26e67cc5 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -38,6 +38,8 @@ class AbstractUi; class AbstractUiMsg; class NetworkModel; class BufferModel; +class IrcUser; +class IrcChannel; class NickModel; class SignalProxy; @@ -53,11 +55,11 @@ public: static void init(AbstractUi *); static QList networks(); - static Network *network(uint networkid); + static Network *network(NetworkId networkid); static QList allBufferInfos(); static QList buffers(); - static Buffer *buffer(uint bufferUid); + static Buffer *buffer(BufferId bufferUid); static Buffer *buffer(BufferInfo); static QList identityIds(); @@ -81,6 +83,10 @@ public: */ static void removeIdentity(IdentityId id); + static void addNetwork(NetworkId id); + static void addNetwork(Network *); + + static NetworkModel *networkModel(); static BufferModel *bufferModel(); static NickModel *nickModel(); @@ -89,8 +95,9 @@ public: static AbstractUiMsg *layoutMsg(const Message &); static bool isConnected(); + static bool isSynced(); - static void fakeInput(uint bufferUid, QString message); + static void fakeInput(BufferId bufferUid, QString message); static void fakeInput(BufferInfo bufferInfo, QString message); static void storeSessionData(const QString &key, const QVariant &data); @@ -107,11 +114,6 @@ signals: 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 showConfigWizard(const QVariantMap &coredata); void connected(); @@ -144,27 +146,24 @@ signals: public slots: //void selectBuffer(Buffer *); - //void connectToLocalCore(); - void connectToCore(const QVariantMap &); + + void setConnectedToCore(QIODevice *socket); + void setSyncedToCore(); void disconnectFromCore(); void setCoreConfiguration(const QVariantMap &settings); + 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 coreSocketError(QAbstractSocket::SocketError); void userInput(BufferInfo, QString); - void networkConnected(uint); - void networkDisconnected(uint); + //void networkConnected(NetworkId); + //void networkDisconnected(NetworkId); - void updateCoreConnectionProgress(); void recvMessage(const Message &message); void recvStatusMsg(QString network, QString message); void recvBacklogData(BufferInfo, QVariantList, bool); @@ -182,7 +181,7 @@ private: virtual ~Client(); void init(); - void syncToCore(const QVariant &coreState); + void syncToCore(const QVariantMap &sessionState); static QPointer instanceptr; @@ -195,12 +194,10 @@ private: ClientMode clientMode; - quint32 blockSize; - bool connectedToCore; + bool _connectedToCore, _syncedToCore; - QVariantMap coreConnectionInfo; QHash _buffers; - QHash _network; + QHash _networks; QHash _identities; QTimer *layoutTimer; @@ -208,7 +205,7 @@ private: QVariantMap sessionData; - + friend class ClientSyncer; }; #endif diff --git a/src/client/client.pri b/src/client/client.pri index 89088da1..a35211c1 100644 --- a/src/client/client.pri +++ b/src/client/client.pri @@ -1,6 +1,6 @@ DEPMOD = common -QT_MOD = core network gui # gui is needed just for QColor... FIXME! -SRCS += buffer.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp mappedselectionmodel.cpp modelpropertymapper.cpp \ - nickmodel.cpp selectionmodelsynchronizer.cpp -HDRS += buffer.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h quasselui.h mappedselectionmodel.h modelpropertymapper.h \ - nickmodel.h selectionmodelsynchronizer.h +QT_MOD = core network gui +SRCS += buffer.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp clientsyncer.cpp \ + mappedselectionmodel.cpp modelpropertymapper.cpp nickmodel.cpp selectionmodelsynchronizer.cpp +HDRS += buffer.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h clientsyncer.h quasselui.h \ + mappedselectionmodel.h modelpropertymapper.h nickmodel.h selectionmodelsynchronizer.h diff --git a/src/client/clientsettings.cpp b/src/client/clientsettings.cpp index 9cb45812..84103509 100644 --- a/src/client/clientsettings.cpp +++ b/src/client/clientsettings.cpp @@ -48,41 +48,56 @@ QVariant ClientSettings::sessionValue(const QString &key, const QVariant &def) { /***********************************************************************************************/ -AccountSettings::AccountSettings() : ClientSettings("Accounts") { +CoreAccountSettings::CoreAccountSettings() : ClientSettings("CoreAccounts") { } -QStringList AccountSettings::knownAccounts() { - return localChildGroups(); +QStringList CoreAccountSettings::knownAccounts() { + return localChildKeys("Accounts"); } -QString AccountSettings::lastAccount() { +QString CoreAccountSettings::lastAccount() { return localValue("LastAccount", "").toString(); } -void AccountSettings::setLastAccount(const QString &account) { +void CoreAccountSettings::setLastAccount(const QString &account) { setLocalValue("LastAccount", account); } -QString AccountSettings::autoConnectAccount() { +QString CoreAccountSettings::autoConnectAccount() { return localValue("AutoConnectAccount", "").toString(); } -void AccountSettings::setAutoConnectAccount(const QString &account) { +void CoreAccountSettings::setAutoConnectAccount(const QString &account) { setLocalValue("AutoConnectAccount", account); } -void AccountSettings::setValue(const QString &account, const QString &key, const QVariant &data) { - setLocalValue(QString("%1/%2").arg(account).arg(key), data); +void CoreAccountSettings::storeAccount(const QString name, const QVariantMap &data) { + setLocalValue(QString("Accounts/%2").arg(name), data); } -QVariant AccountSettings::value(const QString &account, const QString &key, const QVariant &def) { - return localValue(QString("%1/%2").arg(account).arg(key), def); +QVariantMap CoreAccountSettings::retrieveAccount(const QString &name) { + return localValue(QString("Accounts/%2").arg(name), QVariant()).toMap(); } -void AccountSettings::removeAccount(const QString &account) { - removeLocalKey(account); +void CoreAccountSettings::storeAllAccounts(const QHash accounts) { + removeLocalKey(QString("Accounts")); + foreach(QString name, accounts.keys()) { + storeAccount(name, accounts[name]); + } +} + +QHash CoreAccountSettings::retrieveAllAccounts() { + QHash accounts; + foreach(QString name, knownAccounts()) { + accounts[name] = retrieveAccount(name); + } + return accounts; +} + +void CoreAccountSettings::removeAccount(const QString &account) { + removeLocalKey(QString("Accounts/%1").arg(account)); } diff --git a/src/client/clientsettings.h b/src/client/clientsettings.h index 1c86dac2..c874b780 100644 --- a/src/client/clientsettings.h +++ b/src/client/clientsettings.h @@ -39,10 +39,10 @@ class ClientSettings : public Settings { }; -class AccountSettings : public ClientSettings { +class CoreAccountSettings : public ClientSettings { public: - AccountSettings(); + CoreAccountSettings(); QStringList knownAccounts(); QString lastAccount(); @@ -50,8 +50,10 @@ class AccountSettings : public ClientSettings { QString autoConnectAccount(); void setAutoConnectAccount(const QString &account); - void setValue(const QString &account, const QString &key, const QVariant &data); - QVariant value(const QString &account, const QString &key, const QVariant &def = QVariant()); + void storeAccount(const QString name, const QVariantMap &data); + QVariantMap retrieveAccount(const QString &name); + void storeAllAccounts(const QHash accounts); + QHash retrieveAllAccounts(); void removeAccount(const QString &account); }; diff --git a/src/client/clientsyncer.cpp b/src/client/clientsyncer.cpp new file mode 100644 index 00000000..afc1e162 --- /dev/null +++ b/src/client/clientsyncer.cpp @@ -0,0 +1,328 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. * + * * + * 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 "clientsyncer.h" + +#include "client.h" +#include "global.h" +#include "identity.h" +#include "ircuser.h" +#include "ircchannel.h" +#include "network.h" +#include "signalproxy.h" + + +ClientSyncer::ClientSyncer(QObject *parent) : QObject(parent) { + socket = 0; + blockSize = 0; + + connect(Client::signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); + +} + +ClientSyncer::~ClientSyncer() { + + +} + + +void ClientSyncer::coreHasData() { + QVariant item; + while(SignalProxy::readDataFromDevice(socket, blockSize, item)) { + emit recvPartialItem(1,1); + QVariantMap msg = item.toMap(); + if(!msg.contains("MsgType")) { + // This core is way too old and does not even speak our init protocol... + emit connectionError(tr("The Quassel Core you try to connect to is too old! Please consider upgrading.")); + disconnectFromCore(); + return; + } + if(msg["MsgType"] == "ClientInitAck") { + clientInitAck(msg); + } else if(msg["MsgType"] == "ClientInitReject") { + emit connectionError(msg["Error"].toString()); + disconnectFromCore(); + return; + } else if(msg["MsgType"] == "ClientLoginReject") { + emit loginFailed(msg["Error"].toString()); + } else if(msg["MsgType"] == "ClientLoginAck") { + // prevent multiple signal connections + disconnect(this, SIGNAL(recvPartialItem(quint32, quint32)), this, SIGNAL(sessionProgress(quint32, quint32))); + connect(this, SIGNAL(recvPartialItem(quint32, quint32)), this, SIGNAL(sessionProgress(quint32, quint32))); + emit loginSuccess(); + } else if(msg["MsgType"] == "SessionInit") { + sessionStateReceived(msg["SessionState"].toMap()); + } else { + emit connectionError(tr("Invalid data received from core!
Disconnecting.")); + disconnectFromCore(); + return; + } + /* + if (!msg["StartWizard"].toBool()) { + recvCoreState(msg["Reply"]); + } else { + qWarning("Core not configured!"); + qDebug() << "Available storage providers: " << msg["StorageProviders"].toStringList(); + emit showConfigWizard(msg); + } + blockSize = 0; + return; + } + */ + } + if(blockSize > 0) { + emit recvPartialItem(socket->bytesAvailable(), blockSize); + } +} + +void ClientSyncer::coreSocketError(QAbstractSocket::SocketError) { + emit connectionError(socket->errorString()); + socket->deleteLater(); +} + +void ClientSyncer::disconnectFromCore() { + if(socket) socket->close(); +} + +void ClientSyncer::connectToCore(const QVariantMap &conn) { + // TODO implement SSL + coreConnectionInfo = conn; + //if(isConnected()) { + // emit coreConnectionError(tr("Already connected to Core!")); + // return; + // } + + if(socket != 0) { + socket->deleteLater(); + socket = 0; + } + if(conn["Host"].toString().isEmpty()) { + emit connectionError(tr("Internal connections not yet supported.")); + return; // FIXME implement internal connections + //clientMode = LocalCore; + socket = new QBuffer(this); + connect(socket, SIGNAL(readyRead()), this, SLOT(coreHasData())); + socket->open(QIODevice::ReadWrite); + //QVariant state = connectToLocalCore(coreConnectionInfo["User"].toString(), coreConnectionInfo["Password"].toString()); + //syncToCore(state); + coreSocketConnected(); + } else { + //clientMode = RemoteCore; + //emit coreConnectionMsg(tr("Connecting...")); + Q_ASSERT(!socket); + QTcpSocket *sock = new QTcpSocket(Client::instance()); + socket = sock; + connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData())); + connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected())); + connect(sock, SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); + connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError))); + connect(sock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SIGNAL(socketStateChanged(QAbstractSocket::SocketState))); + sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt()); + } +} + +void ClientSyncer::coreSocketConnected() { + //connect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint))); + // Phase One: Send client info and wait for core info + + //emit coreConnectionMsg(tr("Synchronizing to core...")); + QVariantMap clientInit; + clientInit["MsgType"] = "ClientInit"; + clientInit["ClientVersion"] = Global::quasselVersion; + clientInit["ClientDate"] = Global::quasselDate; + clientInit["ClientBuild"] = Global::quasselBuild; // this is a minimum, since we probably won't update for every commit + clientInit["UseSsl"] = false; // FIXME implement SSL + SignalProxy::writeDataToDevice(socket, clientInit); +} + +void ClientSyncer::coreSocketDisconnected() { + emit socketDisconnected(); + Client::instance()->disconnectFromCore(); + + // FIXME handle disconnects gracefully in here as well! + + coreConnectionInfo.clear(); + netsToSync.clear(); + channelsToSync.clear(); + usersToSync.clear(); + blockSize = 0; + //restartPhaseNull(); +} + +void ClientSyncer::clientInitAck(const QVariantMap &msg) { + // Core has accepted our version info and sent its own. Let's see if we accept it as well... + if(msg["CoreBuild"].toUInt() < Global::coreBuildNeeded) { + emit connectionError(tr("The Quassel Core you are trying to connect to is too old!
" + "Need at least a Core Version %1 (Build >= %2) to connect.").arg(Global::quasselVersion).arg(Global::quasselBuild)); + disconnectFromCore(); + return; + } + emit connectionMsg(msg["CoreInfo"].toString()); + if(msg["LoginEnabled"].toBool()) { + emit startLogin(); + } +} + +void ClientSyncer::loginToCore(const QString &user, const QString &passwd) { + emit connectionMsg(tr("Logging in...")); + QVariantMap clientLogin; + clientLogin["MsgType"] = "ClientLogin"; + clientLogin["User"] = user; + clientLogin["Password"] = passwd; + SignalProxy::writeDataToDevice(socket, clientLogin); +} + +void ClientSyncer::sessionStateReceived(const QVariantMap &state) { + emit sessionProgress(1, 1); + disconnect(this, SIGNAL(recvPartialItem(quint32, quint32)), this, SIGNAL(sessionProgress(quint32, quint32))); + disconnect(socket, 0, this, 0); // rest of communication happens through SignalProxy + //Client::signalProxy()->addPeer(socket); + Client::instance()->setConnectedToCore(socket); + syncToCore(state); +} + +void ClientSyncer::syncToCore(const QVariantMap &sessionState) { + + // store sessionData + QVariantMap sessData = sessionState["SessionData"].toMap(); + foreach(QString key, sessData.keys()) Client::instance()->recvSessionData(key, sessData[key]); + + // create identities + foreach(QVariant vid, sessionState["Identities"].toList()) { + Client::instance()->coreIdentityCreated(vid.value()); + } + + // create buffers + // FIXME: get rid of this crap + QVariantList bufferinfos = sessionState["BufferInfos"].toList(); + foreach(QVariant vinfo, bufferinfos) Client::buffer(vinfo.value()); // create Buffers and BufferItems + + QVariantList networkids = sessionState["NetworkIds"].toList(); + + // prepare sync progress thingys... FIXME: Care about removal of networks + numNetsToSync = networkids.count(); + numChannelsToSync = 0; //sessionState["IrcChannelCount"].toUInt(); + numUsersToSync = 0; // sessionState["IrcUserCount"].toUInt(); qDebug() << numUsersToSync; + emit networksProgress(0, numNetsToSync); + emit channelsProgress(0, numChannelsToSync); + emit ircUsersProgress(0, numUsersToSync); + + // create network objects + foreach(QVariant networkid, networkids) { + NetworkId netid = networkid.value(); + Network *net = new Network(netid, Client::instance()); + netsToSync.insert(net); + connect(net, SIGNAL(initDone()), this, SLOT(networkInitDone())); + connect(net, SIGNAL(ircUserInitDone(IrcUser *)), this, SLOT(ircUserInitDone(IrcUser *))); + connect(net, SIGNAL(ircUserAdded(IrcUser *)), this, SLOT(ircUserAdded(IrcUser *))); + connect(net, SIGNAL(ircUserRemoved(QObject *)), this, SLOT(ircUserRemoved(QObject *))); + connect(net, SIGNAL(ircChannelInitDone(IrcChannel *)), this, SLOT(ircChannelInitDone(IrcChannel *))); + connect(net, SIGNAL(ircChannelAdded(IrcChannel *)), this, SLOT(ircChannelAdded(IrcChannel *))); + connect(net, SIGNAL(ircChannelRemoved(QObject *)), this, SLOT(ircChannelRemoved(QObject *))); + Client::addNetwork(net); + } +} + +void ClientSyncer::networkInitDone() { + netsToSync.remove(sender()); + emit networksProgress(numNetsToSync - netsToSync.count(), numNetsToSync); + checkSyncState(); +} + +void ClientSyncer::ircChannelInitDone(IrcChannel *chan) { + channelsToSync.remove(chan); + emit channelsProgress(numChannelsToSync - channelsToSync.count(), numChannelsToSync); + checkSyncState(); +} + +void ClientSyncer::ircChannelAdded(IrcChannel *chan) { + if(!chan->isInitialized()) { + channelsToSync.insert(chan); + numChannelsToSync++; + emit channelsProgress(numChannelsToSync - channelsToSync.count(), numChannelsToSync); + checkSyncState(); + } +} + +void ClientSyncer::ircChannelRemoved(QObject *chan) { + if(channelsToSync.contains(chan)) { + numChannelsToSync--; + channelsToSync.remove(chan); + emit channelsProgress(numChannelsToSync - channelsToSync.count(), numChannelsToSync); + checkSyncState(); + } +} + +void ClientSyncer::ircUserInitDone(IrcUser *user) { + usersToSync.remove(user); + emit ircUsersProgress(numUsersToSync - usersToSync.count(), numUsersToSync); + checkSyncState(); +} + +void ClientSyncer::ircUserAdded(IrcUser *user) { + if(!user->isInitialized()) { + usersToSync.insert(user); + numUsersToSync++; + emit ircUsersProgress(numUsersToSync - usersToSync.count(), numUsersToSync); + checkSyncState(); + } +} + +void ClientSyncer::ircUserRemoved(QObject *user) { + if(usersToSync.contains(user)) { + numUsersToSync--; + usersToSync.remove(user); + emit ircUsersProgress(numUsersToSync - usersToSync.count(), numUsersToSync); + checkSyncState(); + } +} + +void ClientSyncer::checkSyncState() { + if(usersToSync.count() + channelsToSync.count() + netsToSync.count() == 0) { + // done syncing! + /* + qDebug() << "done"; + foreach(Network *net, _networks.values()) { + //disconnect(net, 0, this, SLOT(networkInitDone())); + //disconnect(net, 0, this, SLOT(ircUserInitDone(IrcUser *))); + //disconnect(net, 0, this, SLOT(ircUserAdded(IrcUser *))); + //disconnect(net, 0, this, SLOT(ircUserRemoved(QObject *))); + //disconnect(net, 0, this, SLOT(ircChannelInitDone(IrcChannel *))); + //disconnect(net, 0, this, SLOT(ircChannelAdded(IrcChannel *))); + //disconnect(net, 0, this, SLOT(ircChannelRemoved(QObject *))); + qDebug() << "disconnecting"; + disconnect(net, SIGNAL(initDone()), this, SLOT(networkInitDone())); + disconnect(net, SIGNAL(ircUserInitDone(IrcUser *)), this, SLOT(ircUserInitDone(IrcUser *))); + disconnect(net, SIGNAL(ircUserAdded(IrcUser *)), this, SLOT(ircUserAdded(IrcUser *))); + disconnect(net, SIGNAL(ircUserRemoved(QObject *)), this, SLOT(ircUserRemoved(QObject *))); + disconnect(net, SIGNAL(ircChannelInitDone(IrcChannel *)), this, SLOT(ircChannelInitDone(IrcChannel *))); + disconnect(net, SIGNAL(ircChannelAdded(IrcChannel *)), this, SLOT(ircChannelAdded(IrcChannel *))); + disconnect(net, SIGNAL(ircChannelRemoved(QObject *)), this, SLOT(ircChannelRemoved(QObject *))); + } + */ + + Client::instance()->setSyncedToCore(); + emit syncFinished(); + //emit connected(); + //emit connectionStateChanged(true); + + } +} + diff --git a/src/client/clientsyncer.h b/src/client/clientsyncer.h new file mode 100644 index 00000000..9501d8de --- /dev/null +++ b/src/client/clientsyncer.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. * + * * + * 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 _CLIENTSYNCER_H_ +#define _CLIENTSYNCER_H_ + +#include +#include +#include +#include + +class IrcUser; +class IrcChannel; + +class ClientSyncer : public QObject { + Q_OBJECT + + public: + ClientSyncer(QObject *parent = 0); + ~ClientSyncer(); + + signals: + void recvPartialItem(quint32 avail, quint32 size); + void connectionError(const QString &errorMsg); + void connectionMsg(const QString &msg); + void sessionProgress(quint32 part, quint32 total); + void networksProgress(quint32 part, quint32 total); + void channelsProgress(quint32 part, quint32 total); + void ircUsersProgress(quint32 part, quint32 total); + void socketStateChanged(QAbstractSocket::SocketState); + void socketDisconnected(); + + void startLogin(); + void loginFailed(const QString &error); + void loginSuccess(); + void syncFinished(); + + + public slots: + void connectToCore(const QVariantMap &); + void loginToCore(const QString &user, const QString &passwd); + void disconnectFromCore(); + + private slots: + void coreSocketError(QAbstractSocket::SocketError); + void coreHasData(); + void coreSocketConnected(); + void coreSocketDisconnected(); + + void clientInitAck(const QVariantMap &msg); + + // for sync progress + void networkInitDone(); + void ircUserAdded(IrcUser *); + void ircUserRemoved(QObject *); + void ircUserInitDone(IrcUser *); + void ircChannelAdded(IrcChannel *); + void ircChannelRemoved(QObject *); + void ircChannelInitDone(IrcChannel *); + void checkSyncState(); + + void syncToCore(const QVariantMap &sessionState); + void sessionStateReceived(const QVariantMap &state); + + private: + QPointer socket; + quint32 blockSize; + QVariantMap coreConnectionInfo; + + QSet netsToSync, channelsToSync, usersToSync; + int numNetsToSync, numChannelsToSync, numUsersToSync; + +}; + +#endif diff --git a/src/client/networkmodel.cpp b/src/client/networkmodel.cpp index 61ee7b98..59485da8 100644 --- a/src/client/networkmodel.cpp +++ b/src/client/networkmodel.cpp @@ -195,7 +195,7 @@ void BufferItem::removeUserFromCategory(IrcUser *ircUser) { IrcUserItem *userItem; for(int i = 0; i < childCount(); i++) { categoryItem = qobject_cast(child(i)); - if(userItem = qobject_cast(categoryItem->childById((quint64)ircUser))) { + if((userItem = qobject_cast(categoryItem->childById((quint64)ircUser)))) { userItem->deleteLater(); return; } @@ -210,10 +210,9 @@ void BufferItem::userModeChanged(IrcUser *ircUser) { /***************************************** * Network Items *****************************************/ -NetworkItem::NetworkItem(const uint &netid, const QString &network, AbstractTreeItem *parent) +NetworkItem::NetworkItem(const NetworkId &netid, AbstractTreeItem *parent) : PropertyMapItem(QList() << "networkName" << "currentServer" << "nickCount", parent), - _networkId(netid), - _networkName(network) + _networkId(netid) { setFlags(Qt::ItemIsEnabled); } @@ -243,7 +242,7 @@ QString NetworkItem::networkName() const { if(_network) return _network->networkName(); else - return _networkName; + return QString(); } QString NetworkItem::currentServer() const { @@ -404,31 +403,33 @@ bool NetworkModel::isBufferIndex(const QModelIndex &index) const { return index.data(NetworkModel::ItemTypeRole) == NetworkModel::BufferItemType; } +/* Buffer *NetworkModel::getBufferByIndex(const QModelIndex &index) const { BufferItem *item = static_cast(index.internalPointer()); return Client::instance()->buffer(item->id()); } +*/ // experimental stuff :) -QModelIndex NetworkModel::networkIndex(uint networkId) { +QModelIndex NetworkModel::networkIndex(NetworkId networkId) { return indexById(networkId); } -NetworkItem *NetworkModel::network(uint networkId) { +NetworkItem *NetworkModel::existsNetworkItem(NetworkId networkId) { return qobject_cast(rootItem->childById(networkId)); } -NetworkItem *NetworkModel::newNetwork(uint networkId, const QString &networkName) { - NetworkItem *networkItem = network(networkId); +NetworkItem *NetworkModel::networkItem(NetworkId networkId) { + NetworkItem *netItem = existsNetworkItem(networkId); - if(networkItem == 0) { - networkItem = new NetworkItem(networkId, networkName, rootItem); - appendChild(rootItem, networkItem); + if(netItem == 0) { + netItem = new NetworkItem(networkId, rootItem); + appendChild(rootItem, netItem); } - Q_ASSERT(networkItem); - return networkItem; + Q_ASSERT(netItem); + return netItem; } QModelIndex NetworkModel::bufferIndex(BufferId bufferId) { @@ -442,7 +443,7 @@ QModelIndex NetworkModel::bufferIndex(BufferId bufferId) { return QModelIndex(); } -BufferItem *NetworkModel::buffer(BufferInfo bufferInfo) { +BufferItem *NetworkModel::existsBufferItem(const BufferInfo &bufferInfo) { QModelIndex bufferIdx = bufferIndex(bufferInfo.uid()); if(bufferIdx.isValid()) return static_cast(bufferIdx.internalPointer()); @@ -450,16 +451,16 @@ BufferItem *NetworkModel::buffer(BufferInfo bufferInfo) { return 0; } -BufferItem *NetworkModel::newBuffer(BufferInfo bufferInfo) { - BufferItem *bufferItem = buffer(bufferInfo); - if(bufferItem == 0) { - NetworkItem *networkItem = newNetwork(bufferInfo.networkId(), bufferInfo.network()); - bufferItem = new BufferItem(bufferInfo, networkItem); - appendChild(networkItem, bufferItem); +BufferItem *NetworkModel::bufferItem(const BufferInfo &bufferInfo) { + BufferItem *bufItem = existsBufferItem(bufferInfo); + if(bufItem == 0) { + NetworkItem *netItem = networkItem(bufferInfo.networkId()); + bufItem = new BufferItem(bufferInfo, netItem); + appendChild(netItem, bufItem); } - Q_ASSERT(bufferItem); - return bufferItem; + Q_ASSERT(bufItem); + return bufItem; } QStringList NetworkModel::mimeTypes() const { @@ -475,19 +476,20 @@ bool NetworkModel::mimeContainsBufferList(const QMimeData *mimeData) { return mimeData->hasFormat("application/Quassel/BufferItemList"); } -QList< QPair > NetworkModel::mimeDataToBufferList(const QMimeData *mimeData) { - QList< QPair > bufferList; +QList< QPair > NetworkModel::mimeDataToBufferList(const QMimeData *mimeData) { + QList< QPair > bufferList; if(!mimeContainsBufferList(mimeData)) return bufferList; QStringList rawBufferList = QString::fromAscii(mimeData->data("application/Quassel/BufferItemList")).split(","); - uint networkId, bufferUid; + NetworkId networkId; + BufferId bufferUid; foreach(QString rawBuffer, rawBufferList) { if(!rawBuffer.contains(":")) continue; - networkId = rawBuffer.section(":", 0, 0).toUInt(); - bufferUid = rawBuffer.section(":", 1, 1).toUInt(); + networkId = rawBuffer.section(":", 0, 0).toInt(); + bufferUid = rawBuffer.section(":", 1, 1).toInt(); bufferList.append(qMakePair(networkId, bufferUid)); } return bufferList; @@ -500,8 +502,8 @@ QMimeData *NetworkModel::mimeData(const QModelIndexList &indexes) const { QStringList bufferlist; QString netid, uid, bufferid; foreach(QModelIndex index, indexes) { - netid = QString::number(index.data(NetworkIdRole).toUInt()); - uid = QString::number(index.data(BufferIdRole).toUInt()); + netid = QString::number(index.data(NetworkIdRole).value()); + uid = QString::number(index.data(BufferIdRole).value()); bufferid = QString("%1:%2").arg(netid).arg(uid); if(!bufferlist.contains(bufferid)) bufferlist << bufferid; @@ -535,7 +537,7 @@ bool NetworkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, in uint bufferId = bufferList.first().second; // no self merges (would kill us) - if(bufferId == parent.data(BufferIdRole).toUInt()) + if(bufferId == parent.data(BufferIdRole).value()) return false; Q_ASSERT(rootItem->childById(netId)); @@ -547,24 +549,20 @@ bool NetworkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, in return false; // TODO: warn user about buffermerge! - qDebug() << "merging" << bufferId << parent.data(BufferIdRole).toInt(); + qDebug() << "merging" << bufferId << parent.data(BufferIdRole).value(); removeRow(parent.row(), parent.parent()); return true; } void NetworkModel::attachNetwork(Network *net) { - NetworkItem *networkItem = network(net->networkId()); - if(!networkItem) { - qWarning() << "NetworkModel::attachNetwork(): network is unknown!"; - return; - } - networkItem->attachNetwork(net); + NetworkItem *netItem = networkItem(net->networkId()); + netItem->attachNetwork(net); } void NetworkModel::bufferUpdated(BufferInfo bufferInfo) { - BufferItem *bufferItem = newBuffer(bufferInfo); - QModelIndex itemindex = indexByItem(bufferItem); + BufferItem *bufItem = bufferItem(bufferInfo); + QModelIndex itemindex = indexByItem(bufItem); emit dataChanged(itemindex, itemindex); } diff --git a/src/client/networkmodel.h b/src/client/networkmodel.h index a9a108d2..b1cc15f0 100644 --- a/src/client/networkmodel.h +++ b/src/client/networkmodel.h @@ -114,7 +114,7 @@ class NetworkItem : public PropertyMapItem { Q_PROPERTY(int nickCount READ nickCount) public: - NetworkItem(const uint &netid, const QString &, AbstractTreeItem *parent = 0); + NetworkItem(const NetworkId &netid, AbstractTreeItem *parent = 0); virtual QVariant data(int column, int row) const; virtual quint64 id() const; @@ -133,8 +133,7 @@ public slots: void attachIrcChannel(const QString &channelName); private: - uint _networkId; - QString _networkName; + NetworkId _networkId; QPointer _network; }; @@ -221,7 +220,7 @@ public: static QList defaultHeader(); static bool mimeContainsBufferList(const QMimeData *mimeData); - static QList< QPair > mimeDataToBufferList(const QMimeData *mimeData); + static QList< QPair > mimeDataToBufferList(const QMimeData *mimeData); virtual QStringList mimeTypes() const; virtual QMimeData *mimeData(const QModelIndexList &) const; @@ -230,7 +229,7 @@ public: void attachNetwork(Network *network); bool isBufferIndex(const QModelIndex &) const; - Buffer *getBufferByIndex(const QModelIndex &) const; + //Buffer *getBufferByIndex(const QModelIndex &) const; QModelIndex bufferIndex(BufferId bufferId); public slots: @@ -238,12 +237,11 @@ public slots: void bufferActivity(BufferItem::ActivityLevel, BufferInfo bufferInfo); private: - QModelIndex networkIndex(uint networkId); - NetworkItem *network(uint networkId); - NetworkItem *newNetwork(uint networkId, const QString &networkName); - - BufferItem *buffer(BufferInfo bufferInfo); - BufferItem *newBuffer(BufferInfo bufferInfo); + QModelIndex networkIndex(NetworkId networkId); + NetworkItem *networkItem(NetworkId networkId); + NetworkItem *existsNetworkItem(NetworkId networkId); + BufferItem *bufferItem(const BufferInfo &bufferInfo); + BufferItem *existsBufferItem(const BufferInfo &bufferInfo); }; diff --git a/src/common/global.cpp b/src/common/global.cpp index 09aa5902..ce71aeb0 100644 --- a/src/common/global.cpp +++ b/src/common/global.cpp @@ -64,6 +64,7 @@ void Global::initIconMap() { //! Register our custom types with Qt's Meta Object System. /** This makes them available for QVariant and in signals/slots, among other things. + * */ void Global::registerMetaTypes() { // Complex types @@ -82,13 +83,24 @@ void Global::registerMetaTypes() { qRegisterMetaType("IdentityId"); qRegisterMetaType("BufferId"); qRegisterMetaType("NetworkId"); + qRegisterMetaType("UserId"); qRegisterMetaTypeStreamOperators("IdentityId"); qRegisterMetaTypeStreamOperators("BufferId"); qRegisterMetaTypeStreamOperators("NetworkId"); + qRegisterMetaTypeStreamOperators("UserId"); } +// Static variables + +QString Global::quasselVersion; +QString Global::quasselDate; +uint Global::quasselBuild; +uint Global::clientBuildNeeded; +QString Global::clientVersionNeeded; +uint Global::coreBuildNeeded; +QString Global::coreVersionNeeded; + Global::RunMode Global::runMode; uint Global::defaultPort; - diff --git a/src/common/global.h b/src/common/global.h index 1c72f05e..8b7cf83c 100644 --- a/src/common/global.h +++ b/src/common/global.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005 by the Quassel Project * + * Copyright (C) 2005-08 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -28,14 +28,22 @@ // Enable some shortcuts and stuff //#define DEVELMODE -/** The protocol version we use fo the communication between core and GUI */ -#define GUI_PROTOCOL 5 - -//#define DEFAULT_PORT 4242 - /* Some global stuff */ namespace Global { + + extern QString quasselVersion; + extern QString quasselDate; + extern uint quasselBuild; + + //! Minimum client build number the core needs + extern uint clientBuildNeeded; + extern QString clientVersionNeeded; + + //! Minimum core build number the client needs + extern uint coreBuildNeeded; + extern QString coreVersionNeeded; + // We need different config (QSettings) files for client and gui, since the core cannot work with GUI types // Set these here. They're used in ClientSettings and CoreSettings. const QString coreApplicationName = "Quassel Core"; diff --git a/src/common/identity.cpp b/src/common/identity.cpp index b69f8987..d7bcbdcf 100644 --- a/src/common/identity.cpp +++ b/src/common/identity.cpp @@ -55,7 +55,6 @@ Identity::Identity(const Identity &other, QObject *parent) : SyncableObject(pare } void Identity::init() { - _initialized = false; setObjectName(QString::number(id())); } @@ -87,14 +86,6 @@ bool Identity::isValid() const { return (id() > 0); } -bool Identity::initialized() const { - return _initialized; -} - -void Identity::setInitialized() { - _initialized = true; -} - IdentityId Identity::id() const { return _identityId; } diff --git a/src/common/identity.h b/src/common/identity.h index bffd2a36..9c961a9f 100644 --- a/src/common/identity.h +++ b/src/common/identity.h @@ -84,9 +84,6 @@ class Identity : public SyncableObject { QString partReason() const; QString quitReason() const; - bool initialized() const; - void setInitialized(); - public slots: void setId(IdentityId id); void setIdentityName(const QString &name); @@ -133,10 +130,7 @@ class Identity : public SyncableObject { void partReasonSet(const QString &); void quitReasonSet(const QString &); - void updatedRemotely(); - private: - bool _initialized; IdentityId _identityId; QString _identityName, _realName; QStringList _nicks; diff --git a/src/common/ircchannel.cpp b/src/common/ircchannel.cpp index 1e567b5c..5c12171a 100644 --- a/src/common/ircchannel.cpp +++ b/src/common/ircchannel.cpp @@ -73,10 +73,6 @@ bool IrcChannel::isValidChannelUserMode(const QString &mode) const { return isvalid; } -bool IrcChannel::initialized() const { - return _initialized; -} - QString IrcChannel::name() const { return _name; } @@ -169,7 +165,7 @@ void IrcChannel::part(IrcUser *ircuser) { // if you wonder why there is no counterpart to ircUserParted: // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience emit ircUserParted(ircuser); - if(network->isMyNick(ircuser)) + if(network->isMe(ircuser)) deleteLater(); } } @@ -258,8 +254,3 @@ void IrcChannel::ircUserNickSet(QString nick) { emit ircUserNickSet(ircUser, nick); } -void IrcChannel::setInitialized() { - _initialized = true; - emit initDone(); -} - diff --git a/src/common/ircchannel.h b/src/common/ircchannel.h index 2840b524..d9708145 100644 --- a/src/common/ircchannel.h +++ b/src/common/ircchannel.h @@ -45,8 +45,6 @@ public: bool isKnownUser(IrcUser *ircuser) const; bool isValidChannelUserMode(const QString &mode) const; - bool initialized() const; - QString name() const; QString topic() const; @@ -89,8 +87,6 @@ public slots: // init seters void initSetUserModes(const QVariantMap &usermodes); - void setInitialized(); - signals: void topicSet(QString topic); void userModesSet(QString nick, QString modes); @@ -107,8 +103,6 @@ signals: void ircUserModeRemoved(IrcUser *ircuser, QString mode); void ircUserModesSet(IrcUser *ircuser, QString modes); - void initDone(); - private slots: void ircUserDestroyed(); void ircUserNickSet(QString nick); diff --git a/src/common/ircuser.cpp b/src/common/ircuser.cpp index f6818b9a..08543e1c 100644 --- a/src/common/ircuser.cpp +++ b/src/common/ircuser.cpp @@ -48,9 +48,6 @@ IrcUser::~IrcUser() { // ==================== // PUBLIC: // ==================== -bool IrcUser::initialized() const { - return _initialized; -} QString IrcUser::user() const { return _user; @@ -232,8 +229,3 @@ void IrcUser::initSetChannels(const QStringList channels) { } } -void IrcUser::setInitialized() { - _initialized = true; - emit initDone(); -} - diff --git a/src/common/ircuser.h b/src/common/ircuser.h index 0ca81a17..45be4220 100644 --- a/src/common/ircuser.h +++ b/src/common/ircuser.h @@ -46,8 +46,6 @@ public: IrcUser(const QString &hostmask, Network *network); virtual ~IrcUser(); - bool initialized() const; - QString user() const; QString host() const; QString nick() const; @@ -88,8 +86,6 @@ public slots: // init seters void initSetChannels(const QStringList channels); - void setInitialized(); - signals: void userSet(QString user); void hostSet(QString host); @@ -109,8 +105,6 @@ signals: // void setUsermodes(const QSet &usermodes); // QSet usermodes() const; - void initDone(); - private slots: void updateObjectName(); void channelDestroyed(); diff --git a/src/common/main.cpp b/src/common/main.cpp index b5fe32cf..ecd0fa55 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -64,6 +64,8 @@ int main(int argc, char **argv) { Global::registerMetaTypes(); +#include "../../version.inc" + #if defined BUILD_CORE Global::runMode = Global::CoreOnly; QCoreApplication app(argc, argv); diff --git a/src/common/network.cpp b/src/common/network.cpp index 780a5d86..1388060a 100644 --- a/src/common/network.cpp +++ b/src/common/network.cpp @@ -31,12 +31,11 @@ // ==================== // Public: // ==================== -Network::Network(const uint &networkid, QObject *parent) - : SyncableObject(parent), +Network::Network(const NetworkId &networkid, QObject *parent) : SyncableObject(parent), _networkId(networkid), - _initialized(false), + _identity(0), _myNick(QString()), - _networkName(QString()), + _networkName(QString("")), _currentServer(QString()), _prefixes(QString()), _prefixModes(QString()), @@ -56,28 +55,24 @@ Network::Network(const uint &networkid, QObject *parent) // } //} -uint Network::networkId() const { +NetworkId Network::networkId() const { return _networkId; } -bool Network::initialized() const { - return _initialized; -} - SignalProxy *Network::proxy() const { return _proxy; } void Network::setProxy(SignalProxy *proxy) { _proxy = proxy; - proxy->synchronize(this); + //proxy->synchronize(this); // we should to this explicitly from the outside! } bool Network::isMyNick(const QString &nick) const { return (myNick().toLower() == nick.toLower()); } -bool Network::isMyNick(IrcUser *ircuser) const { +bool Network::isMe(IrcUser *ircuser) const { return (ircuser->nick().toLower() == myNick().toLower()); } @@ -125,6 +120,10 @@ QString Network::myNick() const { return _myNick; } +IdentityId Network::identity() const { + return _identity; +} + QStringList Network::nicks() const { // we don't use _ircUsers.keys() since the keys may be // not up to date after a nick change @@ -139,6 +138,10 @@ QStringList Network::channels() const { return _ircChannels.keys(); } +QList Network::serverList() const { + return _serverList; +} + QString Network::prefixes() { if(_prefixes.isNull()) determinePrefixes(); @@ -170,18 +173,19 @@ IrcUser *Network::newIrcUser(const QString &hostmask) { if(!_ircUsers.contains(nick)) { IrcUser *ircuser = new IrcUser(hostmask, this); // mark IrcUser as already initialized to keep the SignalProxy from requesting initData - if(initialized()) - ircuser->setInitialized(); + //if(isInitialized()) + // ircuser->setInitialized(); if(proxy()) proxy()->synchronize(ircuser); else qWarning() << "unable to synchronize new IrcUser" << hostmask << "forgot to call Network::setProxy(SignalProxy *)?"; connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString))); - connect(ircuser, SIGNAL(initDone()), this, SIGNAL(ircUserInitDone())); + connect(ircuser, SIGNAL(initDone()), this, SLOT(ircUserInitDone())); connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed())); _ircUsers[nick] = ircuser; emit ircUserAdded(hostmask); + emit ircUserAdded(ircuser); } return _ircUsers[nick]; } @@ -196,8 +200,9 @@ void Network::removeIrcUser(IrcUser *ircuser) { return; _ircUsers.remove(nick); - ircuser->deleteLater(); emit ircUserRemoved(nick); + emit ircUserRemoved(ircuser); + ircuser->deleteLater(); } void Network::removeIrcUser(QString nick) { @@ -222,22 +227,27 @@ QList Network::ircUsers() const { return _ircUsers.values(); } +quint32 Network::ircUserCount() const { + return _ircUsers.count(); +} + IrcChannel *Network::newIrcChannel(const QString &channelname) { if(!_ircChannels.contains(channelname.toLower())) { IrcChannel *channel = new IrcChannel(channelname, this); // mark IrcUser as already initialized to keep the SignalProxy from requesting initData - if(initialized()) - channel->setInitialized(); + //if(isInitialized()) + // channel->setInitialized(); if(proxy()) proxy()->synchronize(channel); else qWarning() << "unable to synchronize new IrcChannel" << channelname << "forgot to call Network::setProxy(SignalProxy *)?"; - connect(channel, SIGNAL(initDone()), this, SIGNAL(ircChannelInitDone())); + connect(channel, SIGNAL(initDone()), this, SLOT(ircChannelInitDone())); connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed())); _ircChannels[channelname.toLower()] = channel; emit ircChannelAdded(channelname); + emit ircChannelAdded(channel); } return _ircChannels[channelname.toLower()]; } @@ -263,24 +273,30 @@ QList Network::ircChannels() const { return _ircChannels.values(); } -QTextCodec *Network::codecForEncoding() const { - return _codecForEncoding; +quint32 Network::ircChannelCount() const { + return _ircChannels.count(); } -void Network::setCodecForEncoding(const QString &name) { - setCodecForEncoding(QTextCodec::codecForName(name.toAscii())); +QByteArray Network::codecForEncoding() const { + if(_codecForEncoding) return _codecForEncoding->name(); + return QByteArray(); +} + +void Network::setCodecForEncoding(const QByteArray &name) { + setCodecForEncoding(QTextCodec::codecForName(name)); } void Network::setCodecForEncoding(QTextCodec *codec) { _codecForEncoding = codec; } -QTextCodec *Network::codecForDecoding() const { - return _codecForDecoding; +QByteArray Network::codecForDecoding() const { + if(_codecForDecoding) return _codecForDecoding->name(); + else return QByteArray(); } -void Network::setCodecForDecoding(const QString &name) { - setCodecForDecoding(QTextCodec::codecForName(name.toAscii())); +void Network::setCodecForDecoding(const QByteArray &name) { + setCodecForDecoding(QTextCodec::codecForName(name)); } void Network::setCodecForDecoding(QTextCodec *codec) { @@ -316,6 +332,16 @@ void Network::setMyNick(const QString &nickname) { emit myNickSet(nickname); } +void Network::setIdentity(IdentityId id) { + _identity = id; + emit identitySet(id); +} + +void Network::setServerList(const QList &serverList) { + _serverList = serverList; + emit serverListSet(serverList); +} + void Network::addSupport(const QString ¶m, const QString &value) { if(!_supports.contains(param)) { _supports[param] = value; @@ -340,6 +366,12 @@ QVariantMap Network::initSupports() const { return supports; } +QVariantList Network::initServerList() const { + QList list; + foreach(QVariantMap serverdata, serverList()) list << QVariant(serverdata); + return list; +} + QStringList Network::initIrcUsers() const { QStringList hostmasks; foreach(IrcUser *ircuser, ircUsers()) { @@ -360,6 +392,12 @@ void Network::initSetSupports(const QVariantMap &supports) { } } +void Network::initSetServerList(const QVariantList & serverList) { + QList slist; + foreach(QVariant v, serverList) slist << v.toMap(); + setServerList(slist); +} + void Network::initSetIrcUsers(const QStringList &hostmasks) { if(!_ircUsers.empty()) return; @@ -395,11 +433,23 @@ void Network::ircUserNickChanged(QString newnick) { return; if(newnick.toLower() != oldnick) _ircUsers[newnick.toLower()] = _ircUsers.take(oldnick); - + if(myNick().toLower() == oldnick) setMyNick(newnick); } +void Network::ircUserInitDone() { + IrcUser *ircuser = static_cast(sender()); + Q_ASSERT(ircuser); + emit ircUserInitDone(ircuser); +} + +void Network::ircChannelInitDone() { + IrcChannel *ircchannel = static_cast(sender()); + Q_ASSERT(ircchannel); + emit ircChannelInitDone(ircchannel); +} + void Network::ircUserDestroyed() { IrcUser *ircuser = static_cast(sender()); Q_ASSERT(ircuser); @@ -409,12 +459,14 @@ void Network::ircUserDestroyed() { void Network::channelDestroyed() { IrcChannel *channel = static_cast(sender()); Q_ASSERT(channel); + emit ircChannelRemoved(sender()); _ircChannels.remove(_ircChannels.key(channel)); } -void Network::setInitialized() { - _initialized = true; - emit initDone(); +void Network::requestConnect() { + if(!proxy()) return; + if(proxy()->proxyMode() == SignalProxy::Client) emit connectRequested(); // on the client this triggers calling this slot on the core + else emit connectRequested(networkId()); // and this is for CoreSession :) } // ==================== diff --git a/src/common/network.h b/src/common/network.h index 93d9d515..6a58d841 100644 --- a/src/common/network.h +++ b/src/common/network.h @@ -21,12 +21,14 @@ #ifndef _NETWORK_H_ #define _NETWORK_H_ +#include #include #include #include #include #include #include +#include #include "types.h" #include "syncableobject.h" @@ -35,6 +37,7 @@ class SignalProxy; class IrcUser; class IrcChannel; +// TODO: ConnectionInfo to propagate and sync the current state of NetworkConnection, encodings etcpp class Network : public SyncableObject { Q_OBJECT @@ -42,19 +45,22 @@ class Network : public SyncableObject { 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) + Q_PROPERTY(QByteArray codecForEncoding READ codecForEncoding WRITE setCodecForEncoding STORED false) + Q_PROPERTY(QByteArray codecForDecoding READ codecForDecoding WRITE setCodecForDecoding STORED false) + Q_PROPERTY(IdentityId identityId READ identity WRITE setIdentity STORED false) + // Q_PROPERTY(bool isConnected READ isConnected STORED false) public: - Network(const uint &networkid, QObject *parent = 0); + Network(const NetworkId &networkid, QObject *parent = 0); //virtual ~Network(); NetworkId networkId() const; - bool initialized() const; SignalProxy *proxy() const; void setProxy(SignalProxy *proxy); bool isMyNick(const QString &nick) const; - bool isMyNick(IrcUser *ircuser) const; + bool isMe(IrcUser *ircuser) const; bool isChannelName(const QString &channelname) const; @@ -66,8 +72,10 @@ public: QString networkName() const; QString currentServer() const; QString myNick() const; + IdentityId identity() const; QStringList nicks() const; QStringList channels() const; + QList serverList() const; QString prefixes(); QString prefixModes(); @@ -80,19 +88,18 @@ public: IrcUser *ircUser(QString nickname) const; IrcUser *ircUser(const QByteArray &nickname) const; QList ircUsers() const; + quint32 ircUserCount() const; IrcChannel *newIrcChannel(const QString &channelname); IrcChannel *newIrcChannel(const QByteArray &channelname); IrcChannel *ircChannel(QString channelname); IrcChannel *ircChannel(const QByteArray &channelname); - QList ircChannels() const; + quint32 ircChannelCount() const; - QTextCodec *codecForEncoding() const; - QTextCodec *codecForDecoding() const; - void setCodecForEncoding(const QString &codecName); + QByteArray codecForEncoding() const; + QByteArray codecForDecoding() const; void setCodecForEncoding(QTextCodec *codec); - void setCodecForDecoding(const QString &codecName); void setCodecForDecoding(QTextCodec *codec); QString decodeString(const QByteArray &text) const; @@ -102,6 +109,12 @@ public slots: void setNetworkName(const QString &networkName); void setCurrentServer(const QString ¤tServer); void setMyNick(const QString &mynick); + void setIdentity(IdentityId); + + void setServerList(const QList &serverList); + + void setCodecForEncoding(const QByteArray &codecName); + void setCodecForDecoding(const QByteArray &codecName); void addSupport(const QString ¶m, const QString &value = QString()); void removeSupport(const QString ¶m); @@ -111,11 +124,13 @@ public slots: //init geters QVariantMap initSupports() const; + QVariantList initServerList() const; QStringList initIrcUsers() const; QStringList initIrcChannels() const; //init seters void initSetSupports(const QVariantMap &supports); + void initSetServerList(const QVariantList &serverList); void initSetIrcUsers(const QStringList &hostmasks); void initSetChannels(const QStringList &channels); @@ -124,34 +139,50 @@ public slots: // these slots are to keep the hashlists of all users and the // channel lists up to date void ircUserNickChanged(QString newnick); - void setInitialized(); + + void requestConnect(); private slots: void ircUserDestroyed(); void channelDestroyed(); void removeIrcUser(IrcUser *ircuser); - + void ircUserInitDone(); + void ircChannelInitDone(); + signals: void networkNameSet(const QString &networkName); void currentServerSet(const QString ¤tServer); void myNickSet(const QString &mynick); + void identitySet(IdentityId); + + void serverListSet(const QList &serverList); + + void codecForEncodingSet(const QString &codecName); + void codecForDecodingSet(const QString &codecName); void supportAdded(const QString ¶m, const QString &value); void supportRemoved(const QString ¶m); - - void ircUserAdded(QString hostmask); - void ircChannelAdded(QString channelname); - void ircUserRemoved(QString nick); - - void initDone(); - void ircUserInitDone(); - void ircChannelInitDone(); - + void ircUserAdded(const QString &hostmask); + void ircUserAdded(IrcUser *); + void ircChannelAdded(const QString &channelname); + void ircChannelAdded(IrcChannel *); + + void ircUserRemoved(const QString &nick); + + // needed for client sync progress + void ircUserRemoved(QObject *); + void ircChannelRemoved(QObject *); + + void ircUserInitDone(IrcUser *); + void ircChannelInitDone(IrcChannel *); + + void connectRequested(NetworkId = 0); + private: - uint _networkId; - bool _initialized; - + NetworkId _networkId; + IdentityId _identity; + QString _myNick; QString _networkName; QString _currentServer; @@ -163,6 +194,7 @@ private: QHash _ircChannels; // stores all known channels QHash _supports; // stores results from RPL_ISUPPORT + QList _serverList; //QVariantMap networkSettings; //QVariantMap identity; diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index e4964798..204c197e 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -91,11 +91,11 @@ int SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { // dispatch Sync Signal if necessary QByteArray signature(caller->metaObject()->method(_id).signature()); if(synchronize() && proxy->syncMap(qobject_cast(caller)).contains(signature)) { - // qDebug() << "__SYNC__ >>>" - // << caller->metaObject()->className() - // << caller->objectName() - // << proxy->methodName(caller, _id) - // << params; + //qDebug() << "__SYNC__ >>>" + // << caller->metaObject()->className() + // << caller->objectName() + // << signature + // << params; // params.prepend(QVariant(_id)); params.prepend(signature); params.prepend(caller->objectName()); @@ -131,10 +131,10 @@ bool SignalRelay::isSyncMethod(int i) { if(!proxy->syncMap(qobject_cast(caller)).contains(signature)) return false; - if(proxy->proxyMode() == SignalProxy::Server && !signature.startsWith("request")) + if(proxy->proxyMode() == SignalProxy::Server && !signature.contains("Requested")) return true; - if(proxy->proxyMode() == SignalProxy::Client && signature.startsWith("request")) + if(proxy->proxyMode() == SignalProxy::Client && signature.contains("Requested")) return true; return false; @@ -338,12 +338,6 @@ const QList &SignalProxy::argTypes(QObject *obj, int methodId) { return _classInfo[obj->metaObject()]->argTypes[methodId]; } -bool SignalProxy::hasUpdateSignal(QObject *obj) { - if(!_classInfo.contains(obj->metaObject())) - return false; - return _classInfo[obj->metaObject()]->hasUpdateSignal; -} - void SignalProxy::setMethodName(QObject *obj, int methodId) { const QMetaObject *meta = obj->metaObject(); QByteArray method(::methodName(meta->method(methodId))); @@ -406,7 +400,6 @@ void SignalProxy::createClassInfo(QObject *obj) { return; ClassInfo *classInfo = new ClassInfo(); - classInfo->hasUpdateSignal = (obj->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("updatedRemotely()")) != -1); _classInfo[obj->metaObject()] = classInfo; } @@ -478,18 +471,16 @@ void SignalProxy::synchronize(SyncableObject *obj) { } void SignalProxy::setInitialized(SyncableObject *obj) { - QMetaObject::invokeMethod(obj, "setInitialized"); + obj->setInitialized(); + emit objectInitialized(obj); } -bool SignalProxy::initialized(SyncableObject *obj) { - bool init; - if(!QMetaObject::invokeMethod(obj, "initialized", Q_RETURN_ARG(bool, init))) - init = false; - return init; +bool SignalProxy::isInitialized(SyncableObject *obj) const { + return obj->isInitialized(); } void SignalProxy::requestInit(SyncableObject *obj) { - if(proxyMode() == Server || initialized(obj)) + if(proxyMode() == Server || isInitialized(obj)) return; QVariantList params; @@ -634,8 +625,7 @@ void SignalProxy::handleSync(QVariantList params) { qWarning("SignalProxy::handleSync(): invokeMethod for \"%s\" failed ", methodName(receiver, slotId).constData()); return; } - if(hasUpdateSignal(receiver)) - QMetaObject::invokeMethod(receiver, "updatedRemotely"); + QMetaObject::invokeMethod(receiver, "updatedRemotely"); } void SignalProxy::handleInitRequest(QIODevice *sender, const QVariantList ¶ms) { @@ -798,7 +788,7 @@ QVariantMap SignalProxy::initData(SyncableObject *obj) const { } void SignalProxy::setInitData(SyncableObject *obj, const QVariantMap &properties) { - if(initialized(obj)) + if(isInitialized(obj)) return; obj->fromVariantMap(properties); setInitialized(obj); diff --git a/src/common/signalproxy.h b/src/common/signalproxy.h index 1a8dfac9..d9871a23 100644 --- a/src/common/signalproxy.h +++ b/src/common/signalproxy.h @@ -67,7 +67,7 @@ public: void synchronize(SyncableObject *obj); void setInitialized(SyncableObject *obj); - bool initialized(SyncableObject *obj); + bool isInitialized(SyncableObject *obj) const; void requestInit(SyncableObject *obj); void detachObject(QObject *obj); @@ -89,9 +89,8 @@ public: static bool readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVariant &item); static QString methodBaseName(const QMetaMethod &method); - + const QList &argTypes(QObject *obj, int methodId); - bool hasUpdateSignal(QObject *obj); const QByteArray &methodName(QObject *obj, int methodId); const QHash &syncMap(SyncableObject *obj); @@ -101,7 +100,6 @@ public: ArgHash argTypes; MethodNameHash methodNames; QHash syncMap; - bool hasUpdateSignal; }; void dumpProxyStats(); @@ -117,6 +115,7 @@ signals: void peerRemoved(QIODevice *obj); void connected(); void disconnected(); + void objectInitialized(SyncableObject *); private: void initServer(); @@ -147,7 +146,9 @@ private: void _detachSlots(QObject *receiver); void _stopSync(SyncableObject *obj); + public: void dumpSyncMap(SyncableObject *object); + private: // Hash of used QIODevices QHash _peerByteCount; diff --git a/src/common/syncableobject.cpp b/src/common/syncableobject.cpp index dc202e2c..668f61c6 100644 --- a/src/common/syncableobject.cpp +++ b/src/common/syncableobject.cpp @@ -26,12 +26,21 @@ #include "util.h" SyncableObject::SyncableObject(QObject *parent) : QObject(parent) { - + _initialized = false; } SyncableObject::SyncableObject(const SyncableObject &other, QObject *parent) : QObject(parent) { - Q_UNUSED(other); + _initialized = other._initialized; + +} + +bool SyncableObject::isInitialized() const { + return _initialized; +} +void SyncableObject::setInitialized() { + _initialized = true; + emit initDone(); } QVariantMap SyncableObject::toVariantMap() { diff --git a/src/common/syncableobject.h b/src/common/syncableobject.h index 4ce8c91d..04ba44ba 100644 --- a/src/common/syncableobject.h +++ b/src/common/syncableobject.h @@ -37,10 +37,11 @@ class SyncableObject : public QObject { /** The default implementation takes dynamic properties as well as getters that have * names starting with "init" and stores them in a QVariantMap. Override this method in * derived classes in order to store the object state in a custom form. - * \Note: This is used by SignalProxy to transmit the state of the object to clients + * \note This is used by SignalProxy to transmit the state of the object to clients * that request the initial object state. Later updates use a different mechanism * and assume that the state is completely covered by properties and init* getters. * DO NOT OVERRIDE THIS unless you know exactly what you do! + * * \return The object's state in a QVariantMap */ virtual QVariantMap toVariantMap(); @@ -50,9 +51,20 @@ class SyncableObject : public QObject { */ virtual void fromVariantMap(const QVariantMap &map); + virtual bool isInitialized() const; + + public slots: + virtual void setInitialized(); + + signals: + void initDone(); + void updatedRemotely(); + private: bool setInitValue(const QString &property, const QVariant &value); + bool _initialized; + }; #endif diff --git a/src/common/util.h b/src/common/util.h index 528f60d9..9354620a 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -38,7 +38,7 @@ bool isChannelName(QString str); /** This function takes a string and first checks if it is encoded in utf8, in which case it is * decoded appropriately. Otherwise, the specified text codec is used to transform the string. * \param input The input string containing encoded data - * \param encoding The text codec we use if the input is not utf8 + * \param codec The text codec we use if the input is not utf8 * \return The decoded string. */ QString decodeString(const QByteArray &input, QTextCodec *codec = 0); diff --git a/src/core/core.cpp b/src/core/core.cpp index 7da0aee5..32337988 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -18,18 +18,19 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include +#include +#include +#include + #include "core.h" #include "coresession.h" #include "coresettings.h" #include "signalproxy.h" #include "sqlitestorage.h" -#include -#include - -#include - Core *Core::instanceptr = 0; +QMutex Core::mutex; Core *Core::instance() { if(instanceptr) return instanceptr; @@ -46,71 +47,17 @@ void Core::destroy() { Core::Core() : storage(0) { + startTime = QDateTime::currentDateTime(); // for uptime :) } void Core::init() { - // TODO: Remove this again at some point - // Check if old core settings need to be migrated in order to make the switch to the - // new location less painful. - CoreSettings cs; - QVariant foo = cs.databaseSettings(); - - if(!foo.isValid()) { - // ok, no settings stored yet. check for old ones. -#ifdef Q_WS_MAC - QSettings os("quassel-irc.org", "Quassel IRC", this); -#else - QSettings os("Quassel IRC Development Team", "Quassel IRC"); -#endif - QVariant bar = os.value("Core/DatabaseSettings"); - if(bar.isValid()) { - // old settings available -- migrate! - qWarning() << "\n\nOld settings detected. Will migrate core settings to the new location...\nNOTE: GUI style settings won't be migrated!\n"; -#ifdef Q_WS_MAC - QSettings ncs("quassel-irc.org", "Quassel Core"); -#else - QSettings ncs("Quassel Project", "Quassel Core"); -#endif - ncs.setValue("Core/CoreState", os.value("Core/CoreState")); - ncs.setValue("Core/DatabaseSettings", os.value("Core/DatabaseSettings")); - os.beginGroup("SessionData"); - foreach(QString group, os.childGroups()) { - ncs.setValue(QString("CoreUser/%1/SessionData/Identities").arg(group), os.value(QString("%1/Identities").arg(group))); - ncs.setValue(QString("CoreUser/%1/SessionData/Networks").arg(group), os.value(QString("%1/Networks").arg(group))); - } - os.endGroup(); -#ifdef Q_WS_MAC - QSettings ngs("quassel-irc.org", "Quassel Client"); -#else - QSettings ngs("Quassel Project", "Quassel Client"); -#endif - os.beginGroup("Accounts"); - foreach(QString key, os.childKeys()) { - ngs.setValue(QString("Accounts/%1").arg(key), os.value(key)); - } - foreach(QString group, os.childGroups()) { - ngs.setValue(QString("Accounts/%1/AccountData").arg(group), os.value(QString("%1/AccountData").arg(group))); - } - os.endGroup(); - os.beginGroup("Geometry"); - foreach(QString key, os.childKeys()) { - ngs.setValue(QString("UI/%1").arg(key), os.value(key)); - } - os.endGroup(); - - ncs.sync(); - ngs.sync(); - qWarning() << "Migration successfully finished. You may now delete $HOME/.config/Quassel IRC Development Team/ (on Linux).\n\n"; - } - } - // END - configured = false; + CoreSettings cs; if(!(configured = initStorage(cs.databaseSettings().toMap()))) { qWarning("Core is currently not configured!"); } - + connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); startListening(cs.port()); guiUser = 0; @@ -129,6 +76,7 @@ bool Core::initStorage(QVariantMap dbSettings, bool setup) { // FIXME register new storageProviders here if(engine == "sqlite" && SqliteStorage::isAvailable()) { storage = new SqliteStorage(this); + connect(storage, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)), this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &))); } else { qWarning() << "Selected StorageBackend is not available:" << dbSettings["Type"].toString(); return configured = false; @@ -141,15 +89,14 @@ bool Core::initStorage(QVariantMap dbSettings, bool setup) { return configured = storage->init(dbSettings); } -bool Core::initStorage(QVariantMap dbSettings) { - return initStorage(dbSettings, false); -} - Core::~Core() { + // FIXME properly shutdown the sessions qDeleteAll(sessions); } void Core::restoreState() { + return; + /* Q_ASSERT(!instance()->sessions.count()); CoreSettings s; QList users = s.coreState().toList(); @@ -159,45 +106,67 @@ void Core::restoreState() { QVariantMap m = v.toMap(); if(m.contains("UserId")) { CoreSession *sess = createSession(m["UserId"].toUInt()); - sess->restoreState(m["State"]); + sess->restoreState(m["State"]); // FIXME multithreading } } qDebug() << "...done."; } + */ } void Core::saveState() { + /* CoreSettings s; QList users; foreach(CoreSession *sess, instance()->sessions.values()) { QVariantMap m; - m["UserId"] = sess->userId(); + m["UserId"] = sess->user(); // FIXME multithreading m["State"] = sess->state(); users << m; } s.setCoreState(users); + */ +} + +/*** Storage Access ***/ + +NetworkId Core::networkId(UserId user, const QString &network) { + QMutexLocker locker(&mutex); + return instance()->storage->getNetworkId(user, network); } -CoreSession *Core::session(UserId uid) { - Core *core = instance(); - if(core->sessions.contains(uid)) return core->sessions[uid]; - else return 0; +BufferInfo Core::bufferInfo(UserId user, const QString &network, const QString &buffer) { + //QMutexLocker locker(&mutex); + return instance()->storage->getBufferInfo(user, network, buffer); } -CoreSession *Core::localSession() { - Core *core = instance(); - if(core->guiUser && core->sessions.contains(core->guiUser)) return core->sessions[core->guiUser]; - else return 0; +MsgId Core::storeMessage(const Message &message) { + QMutexLocker locker(&mutex); + return instance()->storage->logMessage(message); } -CoreSession *Core::createSession(UserId uid) { - Core *core = instance(); - Q_ASSERT(!core->sessions.contains(uid)); - CoreSession *sess = new CoreSession(uid, core->storage); - core->sessions[uid] = sess; - return sess; +QList Core::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) { + QMutexLocker locker(&mutex); + return instance()->storage->requestMsgs(buffer, lastmsgs, offset); +} + +QList Core::requestMsgs(BufferInfo buffer, QDateTime since, int offset) { + QMutexLocker locker(&mutex); + return instance()->storage->requestMsgs(buffer, since, offset); +} + +QList Core::requestMsgRange(BufferInfo buffer, int first, int last) { + QMutexLocker locker(&mutex); + return instance()->storage->requestMsgRange(buffer, first, last); +} + +QList Core::requestBuffers(UserId user, QDateTime since) { + QMutexLocker locker(&mutex); + return instance()->storage->requestBuffers(user, since); } +/*** Network Management ***/ + bool Core::startListening(uint port) { if(!server.listen(QHostAddress::Any, port)) { qWarning(QString(QString("Could not open GUI client port %1: %2").arg(port).arg(server.errorString())).toAscii()); @@ -218,9 +187,10 @@ void Core::incomingConnection() { QTcpSocket *socket = server.nextPendingConnection(); connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData())); - blockSizes.insert(socket, (quint32)0); - qDebug() << "Client connected from " << socket->peerAddress().toString(); - + QVariantMap clientInfo; + blocksizes.insert(socket, (quint32)0); + qDebug() << "Client connected from" << qPrintable(socket->peerAddress().toString()); + if (!configured) { server.close(); qDebug() << "Closing server for basic setup."; @@ -230,10 +200,73 @@ void Core::incomingConnection() { void Core::clientHasData() { QTcpSocket *socket = dynamic_cast(sender()); - Q_ASSERT(socket && blockSizes.contains(socket)); - quint32 bsize = blockSizes.value(socket); + Q_ASSERT(socket && blocksizes.contains(socket)); QVariant item; - if(SignalProxy::readDataFromDevice(socket, bsize, item)) { + while(SignalProxy::readDataFromDevice(socket, blocksizes[socket], item)) { + QVariantMap msg = item.toMap(); + if(!msg.contains("MsgType")) { + // Client is way too old, does not even use the current init format + qWarning() << qPrintable(tr("Antique client trying to connect... refusing.")); + socket->close(); + return; + } + // OK, so we have at least an init message format we can understand + if(msg["MsgType"] == "ClientInit") { + QVariantMap reply; + reply["CoreVersion"] = Global::quasselVersion; + reply["CoreDate"] = Global::quasselDate; + reply["CoreBuild"] = Global::quasselBuild; + // TODO: Make the core info configurable + int uptime = startTime.secsTo(QDateTime::currentDateTime()); + int updays = uptime / 86400; uptime %= 86400; + int uphours = uptime / 3600; uptime %= 3600; + int upmins = uptime / 60; + reply["CoreInfo"] = tr("Quassel Core Version %1 (Build >= %2)
" + "Up %3d%4h%5m (since %6)").arg(Global::quasselVersion).arg(Global::quasselBuild) + .arg(updays).arg(uphours,2,10,QChar('0')).arg(upmins,2,10,QChar('0')).arg(startTime.toString(Qt::TextDate)); + + reply["SupportSsl"] = false; + reply["LoginEnabled"] = true; + // TODO: check if we are configured, start wizard otherwise + + // Just version information -- check it! + if(msg["ClientBuild"].toUInt() < Global::clientBuildNeeded) { + reply["MsgType"] = "ClientInitReject"; + reply["Error"] = tr("Your Quassel Client is too old!
" + "This core needs at least client version %1 (Build >= %2).
" + "Please consider upgrading your client.").arg(Global::quasselVersion).arg(Global::quasselBuild); + SignalProxy::writeDataToDevice(socket, reply); + qWarning() << qPrintable(tr("Client %1 too old, rejecting.").arg(socket->peerAddress().toString())); + socket->close(); return; + } + clientInfo[socket] = msg; // store for future reference + reply["MsgType"] = "ClientInitAck"; + SignalProxy::writeDataToDevice(socket, reply); + } else if(msg["MsgType"] == "ClientLogin") { + QVariantMap reply; + if(!clientInfo.contains(socket)) { + reply["MsgType"] = "ClientLoginReject"; + reply["Error"] = tr("Client not initialized!
You need to send an init message before trying to login."); + SignalProxy::writeDataToDevice(socket, reply); + qWarning() << qPrintable(tr("Client %1 did not send an init message before trying to login, rejecting.").arg(socket->peerAddress().toString())); + socket->close(); return; + } + mutex.lock(); + UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); + mutex.unlock(); + if(!uid) { + reply["MsgType"] = "ClientLoginReject"; + reply["Error"] = tr("Invalid username or password!
The username/password combination you supplied could not be found in the database."); + SignalProxy::writeDataToDevice(socket, reply); + continue; + } + reply["MsgType"] = "ClientLoginAck"; + SignalProxy::writeDataToDevice(socket, reply); + qDebug() << qPrintable(tr("Client %1 initialized and authentificated successfully as \"%2\".").arg(socket->peerAddress().toString(), msg["User"].toString())); + setupClientSession(socket, uid); + } + //socket->close(); return; + /* // we need to auth the client try { QVariantMap msg = item.toMap(); @@ -253,50 +286,36 @@ void Core::clientHasData() { qWarning() << "Client init error:" << e.msg(); socket->close(); return; - } + } */ } - blockSizes[socket] = bsize = 0; // FIXME blockSizes aufr�um0rn! } -// FIXME: no longer called, since connection handling is now in SignalProxy -// No, it is called as long as core is not configured. (kaffeedoktor) +// Potentially called during the initialization phase (before handing the connection off to the session) void Core::clientDisconnected() { QTcpSocket *socket = dynamic_cast(sender()); - blockSizes.remove(socket); - qDebug() << "Client disconnected."; - - // make server listen again if still not configured + blocksizes.remove(socket); + clientInfo.remove(socket); + qDebug() << qPrintable(tr("Client %1 disconnected.").arg(socket->peerAddress().toString())); + socket->deleteLater(); + socket = 0; + + // make server listen again if still not configured FIXME if (!configured) { startListening(); } - - // TODO remove unneeded sessions - if necessary/possible... -} - -QVariant Core::connectLocalClient(QString user, QString passwd) { - UserId uid = instance()->storage->validateUser(user, passwd); - QVariant reply = instance()->initSession(uid); - instance()->guiUser = uid; - qDebug() << "Local client connected."; - return reply; -} -void Core::disconnectLocalClient() { - qDebug() << "Local client disconnected."; - instance()->guiUser = 0; + // TODO remove unneeded sessions - if necessary/possible... + // Suggestion: kill sessions if they are not connected to any network and client. } -void Core::processClientInit(QTcpSocket *socket, const QVariantMap &msg) { - // Auth - QVariantMap reply; - UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); // throws exception if this failed - reply["StartWizard"] = false; - reply["Reply"] = initSession(uid); - disconnect(socket, 0, this, 0); - sessions[uid]->addClient(socket); + + //disconnect(socket, 0, this, 0); + /* + sessions[uid]->addClient(socket); // FIXME multithreading qDebug() << "Client initialized successfully."; SignalProxy::writeDataToDevice(socket, reply); -} + */ + void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) { if(msg["HasSettings"].toBool()) { @@ -322,7 +341,7 @@ void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) { storage->addUser(auth["User"].toString(), auth["Password"].toString()); startListening(); // continue the normal procedure - processClientInit(socket, auth); + //processClientInit(socket, auth); } } else { // notify client to start wizard @@ -333,16 +352,29 @@ void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) { } } -QVariant Core::initSession(UserId uid) { +void Core::setupClientSession(QTcpSocket *socket, UserId uid) { // Find or create session for validated user - CoreSession *sess; - if(sessions.contains(uid)) - sess = sessions[uid]; - else - sess = createSession(uid); - QVariantMap reply; - reply["SessionState"] = sess->sessionState(); - return reply; + SessionThread *sess; + if(sessions.contains(uid)) sess = sessions[uid]; + else sess = createSession(uid); + // Hand over socket, session then sends state itself + disconnect(socket, 0, this, 0); + if(!sess) { + qWarning() << qPrintable(tr("Could not initialize session for client %1!").arg(socket->peerAddress().toString())); + socket->close(); + } + sess->addClient(socket); +} + +SessionThread *Core::createSession(UserId uid) { + if(sessions.contains(uid)) { + qWarning() << "Calling createSession() when a session for the user already exists!"; + return 0; + } + SessionThread *sess = new SessionThread(uid, this); + sessions[uid] = sess; + sess->start(); + return sess; } QStringList Core::availableStorageProviders() { diff --git a/src/core/core.h b/src/core/core.h index ae39dc18..76693176 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -21,15 +21,21 @@ #ifndef _CORE_H_ #define _CORE_H_ +#include +#include #include #include #include #include +#include "bufferinfo.h" +#include "message.h" #include "global.h" +#include "sessionthread.h" #include "types.h" class CoreSession; +class SessionThread; class Storage; class Core : public QObject { @@ -39,16 +45,85 @@ class Core : public QObject { static Core * instance(); static void destroy(); - static CoreSession * session(UserId); - static CoreSession * localSession(); - static CoreSession * createSession(UserId); - - static QVariant connectLocalClient(QString user, QString passwd); - static void disconnectLocalClient(); - static void saveState(); static void restoreState(); + /*** Storage access ***/ + // These methods are threadsafe. + + //! Get the NetworkId for a network name. + /** \note This method is threadsafe. + * + * \param user The core user + * \param network The name of the network + * \return The NetworkId corresponding to the given network. + */ + static NetworkId networkId(UserId user, const QString &network); + + //! Get the unique BufferInfo for the given combination of network and buffername for a user. + /** \note This method is threadsafe. + * + * \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 BufferInfo corresponding to the given network and buffer name, or 0 if not found + */ + static BufferInfo bufferInfo(UserId user, const QString &network, const QString &buffer = ""); + + //! Store a Message in the backlog. + /** \note This method is threadsafe. + * + * \param msg The message object to be stored + * \return The globally unique id for the stored message + */ + static MsgId storeMessage(const Message &message); + + //! Request a certain number (or all) messages stored in a given buffer. + /** \note This method is threadsafe. + * + * \param buffer The buffer we request messages from + * \param lastmsgs The number of messages we would like to receive, or -1 if we'd like all messages from that buffername + * \param offset Do not return (but DO count) messages with MsgId >= offset, if offset >= 0 + * \return The requested list of messages + */ + static QList requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1); + + //! Request messages stored in a given buffer since a certain point in time. + /** \note This method is threadsafe. + * + * \param buffer The buffer we request messages from + * \param since Only return messages newer than this point in time + * \param offset Do not return messages with MsgId >= offset, if offset >= 0 + * \return The requested list of messages + */ + static QList requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1); + + //! Request a range of messages stored in a given buffer. + /** \note This method is threadsafe. + * + * \param buffer The buffer we request messages from + * \param first Return messages with first <= MsgId <= last + * \param last Return messages with first <= MsgId <= last + * \return The requested list of messages + */ + static QList requestMsgRange(BufferInfo buffer, int first, int last); + + //! 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. + * Optionally, a QDateTime can be given, so that only buffers are listed that were active + * since that point in time. + * \note This method is threadsafe. + * + * \param user The user whose buffers we request + * \param since If this is defined, older buffers will be ignored + * \return A list of the BufferInfos for all buffers as requested + */ + static QList requestBuffers(UserId user, QDateTime since = QDateTime()); + + signals: + //! Sent when a BufferInfo is updated in storage. + void bufferInfoUpdated(UserId user, const BufferInfo &info); + private slots: bool startListening(uint port = Global::defaultPort); void stopListening(); @@ -56,35 +131,33 @@ class Core : public QObject { void clientHasData(); void clientDisconnected(); - bool initStorage(QVariantMap dbSettings, bool setup); - bool initStorage(QVariantMap dbSettings); + bool initStorage(QVariantMap dbSettings, bool setup = false); private: Core(); ~Core(); void init(); static Core *instanceptr; - - //! Initiate a session for the user with the given credentials if one does not already exist. - /** This function is called during the init process for a new client. If there is no session for the - * given user, one is created. - * \param userId The user - * \return A QVariant containing the session data, e.g. global data and buffers - */ - QVariant initSession(UserId userId); - void processClientInit(QTcpSocket *socket, const QVariantMap &msg); + + SessionThread *createSession(UserId userId); + void setupClientSession(QTcpSocket *socket, UserId uid); void processCoreSetup(QTcpSocket *socket, QVariantMap &msg); - + QStringList availableStorageProviders(); UserId guiUser; - QHash sessions; + QHash sessions; Storage *storage; QTcpServer server; // TODO: implement SSL - QHash blockSizes; - + QHash blocksizes; + QHash clientInfo; + + QDateTime startTime; + bool configured; + + static QMutex mutex; }; #endif diff --git a/src/core/core.pri b/src/core/core.pri index 352858b0..8d71feb8 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -1,6 +1,6 @@ DEPMOD = common QT_MOD = core network sql script SRCS = core.cpp coresession.cpp coresettings.cpp networkconnection.cpp sqlitestorage.cpp abstractsqlstorage.cpp storage.cpp basichandler.cpp \ - ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp + ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp sessionthread.cpp HDRS = core.h coresession.h coresettings.h networkconnection.h sqlitestorage.h abstractsqlstorage.h storage.h basichandler.h \ - ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h + ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h sessionthread.h diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 2b484b39..2d2c67ea 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -18,6 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include "core.h" #include "coresession.h" #include "networkconnection.h" @@ -34,17 +35,15 @@ #include -CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) - : QObject(parent), - user(uid), +CoreSession::CoreSession(UserId uid, QObject *parent) : QObject(parent), + _user(uid), _signalProxy(new SignalProxy(SignalProxy::Server, 0, this)), - storage(_storage), scriptEngine(new QScriptEngine(this)) { SignalProxy *p = signalProxy(); - CoreUserSettings s(user); + CoreUserSettings s(user()); sessionData = s.sessionData(); foreach(IdentityId id, s.identityIds()) { @@ -69,15 +68,15 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) createIdentity(i); } - p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(networkStateRequested())); + //p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(networkStateRequested())); p->attachSlot(SIGNAL(requestConnect(QString)), this, SLOT(connectToNetwork(QString))); - p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromGui(BufferInfo, QString))); + p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString))); 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(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 &))); @@ -92,17 +91,56 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent) foreach(Identity *id, _identities.values()) { p->synchronize(id); } + + // Load and init networks. + // FIXME For now we use the old info from sessionData... + + QVariantMap networks = retrieveSessionData("Networks").toMap(); + foreach(QString netname, networks.keys()) { + QVariantMap network = networks[netname].toMap(); + NetworkId netid = Core::networkId(user(), netname); + Network *net = new Network(netid, this); + connect(net, SIGNAL(connectRequested(NetworkId)), this, SLOT(connectToNetwork(NetworkId))); + net->setNetworkName(netname); + net->setIdentity(1); // FIXME default identity for now + net->setCodecForEncoding("ISO-8859-15"); // FIXME + net->setCodecForDecoding("ISO-8859-15"); // FIXME + QList slist; + foreach(QVariant v, network["Servers"].toList()) slist << v.toMap(); + net->setServerList(slist); + net->setProxy(p); + _networks[netid] = net; + p->synchronize(net); + } + + emit initialized(); } CoreSession::~CoreSession() { } -UserId CoreSession::userId() const { - return user; +UserId CoreSession::user() const { + return _user; +} + +Network *CoreSession::network(NetworkId id) const { + if(_networks.contains(id)) return _networks[id]; + return 0; +} + +NetworkConnection *CoreSession::networkConnection(NetworkId id) const { + if(_connections.contains(id)) return _connections[id]; + return 0; +} + +Identity *CoreSession::identity(IdentityId id) const { + if(_identities.contains(id)) return _identities[id]; + return 0; } -QVariant CoreSession::state() const { +QVariant CoreSession::state() const { // FIXME QVariantMap res; + /* QList conn; foreach(NetworkConnection *net, connections.values()) { if(net->isConnected()) { @@ -113,11 +151,13 @@ QVariant CoreSession::state() const { } } res["ConnectedServers"] = conn; + */ return res; } -void CoreSession::restoreState(const QVariant &previousState) { +void CoreSession::restoreState(const QVariant &previousState) { // FIXME // Session restore + /* QVariantMap state = previousState.toMap(); if(state.contains("ConnectedServers")) { foreach(QVariant v, state["ConnectedServers"].toList()) { @@ -126,66 +166,90 @@ void CoreSession::restoreState(const QVariant &previousState) { if(!net.isEmpty()) connectToNetwork(net, m["State"]); } } + */ } void CoreSession::storeSessionData(const QString &key, const QVariant &data) { - CoreUserSettings s(user); - mutex.lock(); + CoreUserSettings s(user()); s.setSessionValue(key, data); sessionData[key] = data; - mutex.unlock(); emit sessionDataChanged(key, data); emit sessionDataChanged(key); } QVariant CoreSession::retrieveSessionData(const QString &key, const QVariant &def) { QVariant data; - mutex.lock(); if(!sessionData.contains(key)) data = def; else data = sessionData[key]; - mutex.unlock(); return data; } -// FIXME switch to NetworkIDs -void CoreSession::connectToNetwork(QString networkname, const QVariant &previousState) { - uint networkid = getNetworkId(networkname); - if(networkid == 0) { - qWarning() << "unable to connect to Network" << networkname << "(User:" << userId() << "): unable to determine NetworkId"; +void CoreSession::updateBufferInfo(UserId uid, const BufferInfo &bufinfo) { + if(uid == user()) emit bufferInfoUpdated(bufinfo); +} + +// FIXME remove +void CoreSession::connectToNetwork(QString netname, const QVariant &previousState) { + Network *net = 0; + foreach(Network *n, _networks.values()) { + if(n->networkName() == netname) { + net = n; break; + } + } + if(!net) { + qWarning() << "Connect to unknown network requested, ignoring!"; + return; + } + connectToNetwork(net->networkId(), previousState); +} + +void CoreSession::connectToNetwork(NetworkId id, const QVariant &previousState) { + Network *net = network(id); + if(!net) { + qWarning() << "Connect to unknown network requested! net:" << id << "user:" << user(); return; } - if(!connections.contains(networkid)) { - NetworkConnection *connection = new NetworkConnection(userId(), networkid, networkname, previousState); - connections[networkid] = connection; - attachNetworkConnection(connection); - connection->start(); + + NetworkConnection *conn = networkConnection(id); + if(!conn) { + conn = new NetworkConnection(net, this, previousState); + _connections[id] = conn; + attachNetworkConnection(conn); + conn->connectToIrc(); } - emit connectToIrc(networkname); } -void CoreSession::attachNetworkConnection(NetworkConnection *network) { - connect(this, SIGNAL(connectToIrc(QString)), network, SLOT(connectToIrc(QString))); - connect(this, SIGNAL(disconnectFromIrc(QString)), network, SLOT(disconnectFromIrc(QString))); - connect(this, SIGNAL(msgFromGui(uint, QString, QString)), network, SLOT(userInput(uint, QString, QString))); - - connect(network, SIGNAL(connected(uint)), this, SLOT(networkConnected(uint))); - connect(network, SIGNAL(disconnected(uint)), this, SLOT(networkDisconnected(uint))); - connect(network, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8))); - connect(network, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString))); - - // connect serversignals to proxy - signalProxy()->attachSignal(network, SIGNAL(networkState(QString, QVariantMap)), SIGNAL(networkState(QString, QVariantMap))); - signalProxy()->attachSignal(network, SIGNAL(connected(uint)), SIGNAL(networkConnected(uint))); - signalProxy()->attachSignal(network, SIGNAL(disconnected(uint)), SIGNAL(networkDisconnected(uint))); +void CoreSession::attachNetworkConnection(NetworkConnection *conn) { + //connect(this, SIGNAL(connectToIrc(QString)), network, SLOT(connectToIrc(QString))); + //connect(this, SIGNAL(disconnectFromIrc(QString)), network, SLOT(disconnectFromIrc(QString))); + //connect(this, SIGNAL(msgFromGui(uint, QString, QString)), network, SLOT(userInput(uint, QString, QString))); + + connect(conn, SIGNAL(connected(NetworkId)), this, SLOT(networkConnected(NetworkId))); + connect(conn, SIGNAL(disconnected(NetworkId)), this, SLOT(networkDisconnected(NetworkId))); + signalProxy()->attachSignal(conn, SIGNAL(connected(NetworkId)), SIGNAL(networkConnected(NetworkId))); + signalProxy()->attachSignal(conn, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId))); + + connect(conn, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8))); + connect(conn, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString))); + // TODO add error handling } void CoreSession::networkStateRequested() { } -void CoreSession::addClient(QIODevice *device) { - signalProxy()->addPeer(device); +void CoreSession::addClient(QObject *dev) { // this is QObject* so we can use it in signal connections + QIODevice *device = qobject_cast(dev); + if(!device) { + qWarning() << "Invoking CoreSession::addClient with a QObject that is not a QIODevice!"; + } else { + signalProxy()->addPeer(device); + QVariantMap reply; + reply["MsgType"] = "SessionInit"; + reply["SessionState"] = sessionState(); + SignalProxy::writeDataToDevice(device, reply); + } } SignalProxy *CoreSession::signalProxy() const { @@ -193,17 +257,25 @@ SignalProxy *CoreSession::signalProxy() const { } void CoreSession::networkConnected(uint networkid) { - storage->getBufferInfo(userId(), connections[networkid]->networkName()); // create status buffer + Core::bufferInfo(user(), networkConnection(networkid)->networkName()); // create status buffer } void CoreSession::networkDisconnected(uint networkid) { - Q_ASSERT(connections.contains(networkid)); - connections.take(networkid)->deleteLater(); - Q_ASSERT(!connections.contains(networkid)); + // FIXME + // connection should only go away on explicit /part, and handle reconnections etcpp internally otherwise + Q_ASSERT(_connections.contains(networkid)); + _connections.take(networkid)->deleteLater(); + Q_ASSERT(!_connections.contains(networkid)); } -void CoreSession::msgFromGui(BufferInfo bufid, QString msg) { - emit msgFromGui(bufid.networkId(), bufid.buffer(), msg); +// FIXME switch to BufferId +void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) { + NetworkConnection *conn = networkConnection(bufinfo.networkId()); + if(conn) { + conn->userInput(bufinfo.buffer(), msg); + } else { + qWarning() << "Trying to send to unconnected network!"; + } } // ALL messages coming pass through these functions before going to the GUI. @@ -213,12 +285,12 @@ void CoreSession::recvMessageFromServer(Message::Type type, QString target, QStr Q_ASSERT(s); BufferInfo buf; if((flags & Message::PrivMsg) && !(flags & Message::Self)) { - buf = storage->getBufferInfo(user, s->networkName(), nickFromMask(sender)); + buf = Core::bufferInfo(user(), s->networkName(), nickFromMask(sender)); } else { - buf = storage->getBufferInfo(user, s->networkName(), target); + buf = Core::bufferInfo(user(), s->networkName(), target); } Message msg(buf, type, text, sender, flags); - msg.setMsgId(storage->logMessage(msg)); + msg.setMsgId(Core::storeMessage(msg)); Q_ASSERT(msg.msgId()); emit displayMsg(msg); } @@ -229,13 +301,8 @@ void CoreSession::recvStatusMsgFromServer(QString msg) { emit displayStatusMsg(s->networkName(), msg); } - -uint CoreSession::getNetworkId(const QString &net) const { - return storage->getNetworkId(user, net); -} - QList CoreSession::buffers() const { - return storage->requestBuffers(user); + return Core::requestBuffers(user()); } @@ -243,24 +310,29 @@ QVariant CoreSession::sessionState() { QVariantMap v; QVariantList bufs; - foreach(BufferInfo id, storage->requestBuffers(user)) - bufs.append(QVariant::fromValue(id)); - v["Buffers"] = bufs; - - mutex.lock(); - v["SessionData"] = sessionData; - mutex.unlock(); - - QVariantList networks; - foreach(NetworkId networkid, connections.keys()) - networks.append(QVariant(networkid)); - v["Networks"] = QVariant(networks); + foreach(BufferInfo id, buffers()) bufs << QVariant::fromValue(id); + v["BufferInfos"] = bufs; + QVariantList networkids; + foreach(NetworkId id, _networks.keys()) networkids << QVariant::fromValue(id); + v["NetworkIds"] = networkids; + + quint32 ircusercount = 0; + quint32 ircchannelcount = 0; + foreach(Network *net, _networks.values()) { + ircusercount += net->ircUserCount(); + ircchannelcount += net->ircChannelCount(); + } + v["IrcUserCount"] = ircusercount; + v["IrcChannelCount"] = ircchannelcount; + qDebug() << "nets:" << _networks.count() << " chans:" << ircchannelcount << " users:" << ircusercount; QList idlist; foreach(Identity *i, _identities.values()) idlist << QVariant::fromValue(*i); v["Identities"] = idlist; - // v["Payload"] = QByteArray(100000000, 'a'); // for testing purposes + v["SessionData"] = sessionData; + + //v["Payload"] = QByteArray(100000000, 'a'); // for testing purposes return v; } @@ -271,7 +343,7 @@ void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) { } else { - msglist = storage->requestMsgs(id, v1.toInt(), v2.toInt()); + msglist = Core::requestMsgs(id, v1.toInt(), v2.toInt()); } // Send messages out in smaller packages - we don't want to make the signal data too large! @@ -289,9 +361,10 @@ void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) { void CoreSession::initScriptEngine() { signalProxy()->attachSlot(SIGNAL(scriptRequest(QString)), this, SLOT(scriptRequest(QString))); signalProxy()->attachSignal(this, SIGNAL(scriptResult(QString))); - - QScriptValue storage_ = scriptEngine->newQObject(storage); - scriptEngine->globalObject().setProperty("storage", storage_); + + // FIXME + //QScriptValue storage_ = scriptEngine->newQObject(storage); + //scriptEngine->globalObject().setProperty("storage", storage_); } void CoreSession::scriptRequest(QString script) { @@ -309,7 +382,7 @@ void CoreSession::createIdentity(const Identity &id) { newId->setId(i); _identities[i] = newId; signalProxy()->synchronize(newId); - CoreUserSettings s(user); + CoreUserSettings s(user()); s.storeIdentity(*newId); emit identityCreated(*newId); } @@ -321,7 +394,7 @@ void CoreSession::updateIdentity(const Identity &id) { } _identities[id.id()]->update(id); - CoreUserSettings s(user); + CoreUserSettings s(user()); s.storeIdentity(id); } @@ -329,7 +402,7 @@ void CoreSession::removeIdentity(IdentityId id) { Identity *i = _identities.take(id); if(i) { emit identityRemoved(id); - CoreUserSettings s(user); + CoreUserSettings s(user()); s.removeIdentity(id); i->deleteLater(); } diff --git a/src/core/coresession.h b/src/core/coresession.h index 27417e5e..1c8924ab 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -21,16 +21,15 @@ #ifndef _CORESESSION_H_ #define _CORESESSION_H_ -#include #include #include #include "message.h" class Identity; -class NetworkConnection; +class NetworkConnection; // FIXME get rid of +class Network; class SignalProxy; -class Storage; class QScriptEngine; @@ -38,12 +37,15 @@ class CoreSession : public QObject { Q_OBJECT public: - CoreSession(UserId, Storage *, QObject *parent = 0); - virtual ~CoreSession(); + CoreSession(UserId, QObject *parent = 0); + ~CoreSession(); - NetworkId getNetworkId(const QString &network) const; QList buffers() const; - UserId userId() const; + UserId user() const; + Network *network(NetworkId) const; + NetworkConnection *networkConnection(NetworkId) const; + Identity *identity(IdentityId) const; + QVariant sessionState(); //! Retrieve a piece of session-wide data. @@ -63,14 +65,14 @@ public slots: void networkStateRequested(); - void addClient(QIODevice *connection); + void addClient(QObject *socket); void connectToNetwork(QString, const QVariant &previousState = QVariant()); - //void connectToNetwork(NetworkId); + void connectToNetwork(NetworkId, const QVariant &previousState = QVariant()); //void processSignal(ClientSignal, QVariant, QVariant, QVariant); void sendBacklog(BufferInfo, QVariant, QVariant); - void msgFromGui(BufferInfo, QString message); + void msgFromClient(BufferInfo, QString message); //! Create an identity and propagate the changes to the clients. /** \param identity The identity to be created. @@ -88,12 +90,14 @@ public slots: void removeIdentity(IdentityId identity); signals: - void msgFromGui(uint netid, QString buf, QString message); + void initialized(); + + //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 connectToIrc(QString net); + //void disconnectFromIrc(QString net); void backlogData(BufferInfo, QVariantList, bool done); @@ -121,23 +125,29 @@ private slots: void networkConnected(uint networkid); void networkDisconnected(uint networkid); + //! Called when storage updated a BufferInfo. + /** This emits bufferInfoUpdated() via SignalProxy, iff it's one of our buffers. + * \param user The buffer's owner (not necessarily us) + * \param bufferInfo The updated BufferInfo + */ + void updateBufferInfo(UserId user, const BufferInfo &bufferInfo); + void scriptRequest(QString script); - + private: void initScriptEngine(); - - UserId user; - + + UserId _user; + SignalProxy *_signalProxy; - Storage *storage; - QHash connections; - + QHash _connections; + QHash _networks; + QHash _identities; + QVariantMap sessionData; - QMutex mutex; QScriptEngine *scriptEngine; - QHash _identities; }; #endif diff --git a/src/core/ircserverhandler.h b/src/core/ircserverhandler.h index a821a351..591c86fb 100644 --- a/src/core/ircserverhandler.h +++ b/src/core/ircserverhandler.h @@ -27,7 +27,7 @@ class IrcServerHandler : public BasicHandler { Q_OBJECT public: - IrcServerHandler(NetworkConnection *parent = 0); + IrcServerHandler(NetworkConnection *parent); ~IrcServerHandler(); void handleServerMsg(QByteArray rawMsg); diff --git a/src/core/networkconnection.cpp b/src/core/networkconnection.cpp index ae8ac139..21e7f630 100644 --- a/src/core/networkconnection.cpp +++ b/src/core/networkconnection.cpp @@ -29,25 +29,28 @@ #include "ircuser.h" #include "network.h" +#include "identity.h" #include "ircserverhandler.h" #include "userinputhandler.h" #include "ctcphandler.h" -NetworkConnection::NetworkConnection(UserId uid, NetworkId networkId, QString net, const QVariant &state) - : _userId(uid), - _networkId(networkId), +NetworkConnection::NetworkConnection(Network *network, CoreSession *session, const QVariant &state) : QObject(network), + _network(network), + _coreSession(session), _ircServerHandler(new IrcServerHandler(this)), _userInputHandler(new UserInputHandler(this)), _ctcpHandler(new CtcpHandler(this)), - _network(new Network(networkId, this)), _previousState(state) { - connect(network(), SIGNAL(currentServerSet(const QString &)), this, SLOT(sendPerform())); - network()->setCodecForEncoding("ISO-8859-15"); // FIXME - network()->setCodecForDecoding("ISO-8859-15"); // FIXME - network()->setNetworkName(net); - network()->setProxy(coreSession()->signalProxy()); + connect(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(sendPerform())); + + connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected())); + connect(&socket, SIGNAL(disconnected()), this, SLOT(quit())); + connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); + connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState))); + connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData())); + } NetworkConnection::~NetworkConnection() { @@ -56,15 +59,36 @@ NetworkConnection::~NetworkConnection() { delete _ctcpHandler; } -void NetworkConnection::run() { - connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected())); - connect(&socket, SIGNAL(disconnected()), this, SLOT(quit())); - connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); - connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState))); - connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData())); - connect(this, SIGNAL(finished()), this, SLOT(threadFinished())); +bool NetworkConnection::isConnected() const { + return socket.state() == QAbstractSocket::ConnectedState; +} + +uint NetworkConnection::networkId() const { + return network()->networkId(); +} + +QString NetworkConnection::networkName() const { + return network()->networkName(); +} + +Network *NetworkConnection::network() const { + return _network; +} - exec(); +CoreSession *NetworkConnection::coreSession() const { + return _coreSession; +} + +IrcServerHandler *NetworkConnection::ircServerHandler() const { + return _ircServerHandler; +} + +UserInputHandler *NetworkConnection::userInputHandler() const { + return _userInputHandler; +} + +CtcpHandler *NetworkConnection::ctcpHandler() const { + return _ctcpHandler; } QString NetworkConnection::serverDecode(const QByteArray &string) const { @@ -100,18 +124,21 @@ QByteArray NetworkConnection::userEncode(const QString &userNick, const QString } -void NetworkConnection::connectToIrc(QString net) { - if(net != networkName()) - return; // not me! - - CoreSession *sess = coreSession(); - networkSettings = sess->retrieveSessionData("Networks").toMap()[net].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(); +void NetworkConnection::connectToIrc() { + QList serverList = network()->serverList(); + Identity *identity = coreSession()->identity(network()->identity()); + if(!serverList.count()) { + qWarning() << "Server list empty, ignoring connect request!"; + return; + } + if(!identity) { + qWarning() << "Invalid identity configures, ignoring connect request!"; + return; + } + + // TODO implement cycling / random servers + QString host = serverList[0]["Address"].toString(); + quint16 port = serverList[0]["Port"].toUInt(); displayStatusMsg(QString("Connecting to %1:%2...").arg(host).arg(port)); socket.connectToHost(host, port); } @@ -138,15 +165,13 @@ void NetworkConnection::sendPerform() { _previousState = QVariant(); } -QVariant NetworkConnection::state() { +QVariant NetworkConnection::state() const { IrcUser *me = network()->ircUser(network()->myNick()); if(!me) return QVariant(); // this shouldn't really happen, I guess return me->channels(); } -void NetworkConnection::disconnectFromIrc(QString net) { - if(net != networkName()) - return; // not me! +void NetworkConnection::disconnectFromIrc() { socket.disconnectFromHost(); } @@ -158,29 +183,27 @@ void NetworkConnection::socketHasData() { } void NetworkConnection::socketError( QAbstractSocket::SocketError err ) { - //qDebug() << "Socket Error!"; + qDebug() << "Socket Error!"; } void NetworkConnection::socketConnected() { 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 NetworkConnection::threadFinished() { - // the Socket::disconnected() is connect to this::quit() - // so after the event loop is finished we're beeing called - // and propagate the disconnect - emit disconnected(networkId()); + Identity *identity = coreSession()->identity(network()->identity()); + if(!identity) { + qWarning() << "Identity invalid!"; + disconnectFromIrc(); + return; + } + putRawLine(QString("NICK :%1").arg(identity->nicks()[0])); // FIXME: try more nicks if error occurs + putRawLine(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName())); } void NetworkConnection::socketStateChanged(QAbstractSocket::SocketState state) { //qDebug() << "Socket state changed: " << state; } -void NetworkConnection::userInput(uint netid, QString buf, QString msg) { - if(netid != networkId()) - return; // not me! +// FIXME switch to BufferId +void NetworkConnection::userInput(QString buf, QString msg) { userInputHandler()->handleUserInput(buf, msg); } @@ -204,19 +227,6 @@ void NetworkConnection::putCmd(QString cmd, QStringList params, QString prefix) putRawLine(msg); } - -uint NetworkConnection::networkId() const { - return _networkId; -} - -QString NetworkConnection::networkName() const { - return network()->networkName(); -} - -CoreSession *NetworkConnection::coreSession() const { - return Core::session(userId()); -} - /* Exception classes for message handling */ NetworkConnection::ParseError::ParseError(QString cmd, QString prefix, QStringList params) { Q_UNUSED(prefix); diff --git a/src/core/networkconnection.h b/src/core/networkconnection.h index a7d6eba6..1e1247b5 100644 --- a/src/core/networkconnection.h +++ b/src/core/networkconnection.h @@ -25,46 +25,38 @@ #include #include #include -#include #include #include "message.h" #include "signalproxy.h" +class CoreSession; class Network; 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. - * We have this running in its own thread mainly to not block other server objects or the core if something goes wrong, - * e.g. if some scripts starts running wild... - */ - -class NetworkConnection : public QThread { +class NetworkConnection : public QObject { Q_OBJECT public: - NetworkConnection(UserId uid, NetworkId networkId, QString network, const QVariant &previousState = QVariant()); + NetworkConnection(Network *network, CoreSession *session, const QVariant &previousState = QVariant()); ~NetworkConnection(); - UserId userId() const { return _userId; } - - // networkState state(); - bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; } - NetworkId networkId() const; - QString networkName() const; // hasbeen getNetwork() + QString networkName() const; + Network *network() const; + CoreSession *coreSession() const; + + bool isConnected() const; - Network *network() const { return _network; } - IrcServerHandler *ircServerHandler() const { return _ircServerHandler; } - UserInputHandler *userInputHandler() const { return _userInputHandler; } - CtcpHandler *ctcpHandler() const { return _ctcpHandler; } + IrcServerHandler *ircServerHandler() const; + UserInputHandler *userInputHandler() const; + CtcpHandler *ctcpHandler() const; - QVariant state(); ///< Return data necessary to restore the server's state upon core restart + //! Return data necessary to restore the connection state upon core restart + QVariant state() const; //! Decode a string using the server (network) decoding. QString serverDecode(const QByteArray &string) const; @@ -86,60 +78,52 @@ public: public slots: // void setServerOptions(); - void connectToIrc(QString net); - void disconnectFromIrc(QString net); - void userInput(uint netid, QString buffer, QString msg); + void connectToIrc(); + void disconnectFromIrc(); + void userInput(QString buffer, QString msg); void putRawLine(QString input); void putCmd(QString cmd, QStringList params, QString prefix = 0); private slots: - void threadFinished(); void sendPerform(); signals: - void networkState(QString net, QVariantMap data); + // #void networkState(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); + void connected(NetworkId networkId); + void disconnected(NetworkId networkId); void connectionInitialized(); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server - void synchronizeClients(); - - void queryRequested(QString network, QString nick); + //void queryRequested(QString network, QString nick); private slots: - void run(); void socketHasData(); void socketError(QAbstractSocket::SocketError); void socketConnected(); void socketStateChanged(QAbstractSocket::SocketState); private: - UserId _userId; - NetworkId _networkId; - QTcpSocket socket; + Network *_network; + CoreSession *_coreSession; + IrcServerHandler *_ircServerHandler; UserInputHandler *_userInputHandler; CtcpHandler *_ctcpHandler; - Network *_network; - QVariantMap networkSettings; QVariantMap identity; QVariant _previousState; - CoreSession *coreSession() const; - class ParseError : public Exception { public: ParseError(QString cmd, QString prefix, QStringList params); diff --git a/src/core/sessionthread.cpp b/src/core/sessionthread.cpp new file mode 100644 index 00000000..d5070955 --- /dev/null +++ b/src/core/sessionthread.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. * + * * + * 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 "sessionthread.h" + +#include "coresession.h" + +SessionThread::SessionThread(UserId uid, QObject *parent) : QThread(parent) { + _user = uid; + _session = 0; + _sessionInitialized = false; + connect(this, SIGNAL(initialized()), this, SLOT(setSessionInitialized())); +} + +SessionThread::~SessionThread() { + // FIXME + quit(); + wait(); + if(session()) _session->deleteLater(); +} + +CoreSession *SessionThread::session() { + return _session; +} + +UserId SessionThread::user() { + return _user; +} + +bool SessionThread::isSessionInitialized() { + return _sessionInitialized; +} + +void SessionThread::setSessionInitialized() { + _sessionInitialized = true; + foreach(QIODevice *socket, clientQueue) { + addClientToSession(socket); + } + clientQueue.clear(); +} + +void SessionThread::addClient(QIODevice *socket) { + if(isSessionInitialized()) { + addClientToSession(socket); + } else { + clientQueue.append(socket); + } +} + +void SessionThread::addClientToSession(QIODevice *socket) { + socket->setParent(0); + socket->moveToThread(session()->thread()); + if(!QMetaObject::invokeMethod(session(), "addClient", Q_ARG(QObject *, socket))) { + qWarning() << qPrintable(tr("Could not initialize session!")); + socket->close(); + } +} + +void SessionThread::run() { + _session = new CoreSession(user()); + emit initialized(); + exec(); +} + diff --git a/src/core/sessionthread.h b/src/core/sessionthread.h new file mode 100644 index 00000000..ee29d2e3 --- /dev/null +++ b/src/core/sessionthread.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. * + * * + * 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 _SESSIONTHREAD_H_ +#define _SESSIONTHREAD_H_ + +#include +#include + +#include "types.h" + +class CoreSession; +class QIODevice; + +class SessionThread : public QThread { + Q_OBJECT + + public: + SessionThread(UserId user, QObject *parent = 0); + ~SessionThread(); + + void run(); + + CoreSession *session(); + UserId user(); + + public slots: + void addClient(QIODevice *socket); + + private slots: + void setSessionInitialized(); + + signals: + void initialized(); + + private: + CoreSession *_session; + UserId _user; + QList clientQueue; + bool _sessionInitialized; + + bool isSessionInitialized(); + void addClientToSession(QIODevice *socket); +}; + +#endif diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index 90a111e0..81108bd0 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -113,7 +113,6 @@ UserId SqliteStorage::validateUser(const QString &user, const QString &password) if(query.first()) { return query.value(0).toUInt(); } else { - throw AuthError(); return 0; } } @@ -203,7 +202,7 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const QString &network, con getBufferInfoQuery->exec(); if(getBufferInfoQuery->first()) { bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer); - emit bufferInfoUpdated(bufferid); + emit bufferInfoUpdated(user, bufferid); } } else { bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer); diff --git a/src/core/sqlitestorage.h b/src/core/sqlitestorage.h index 3b27205d..992fc8f5 100644 --- a/src/core/sqlitestorage.h +++ b/src/core/sqlitestorage.h @@ -69,9 +69,6 @@ protected: inline virtual QString databaseName() { return backlogFile(); } virtual int installedSchemaVersion(); -signals: - void bufferInfoUpdated(BufferInfo); - private: static QString backlogFile(); void createBuffer(UserId user, const QString &network, const QString &buffer); diff --git a/src/core/storage.h b/src/core/storage.h index 69a229e4..db68417c 100644 --- a/src/core/storage.h +++ b/src/core/storage.h @@ -157,7 +157,7 @@ class Storage : public QObject { signals: //! Sent when a new BufferInfo is created, or an existing one changed somehow. - void bufferInfoUpdated(BufferInfo); + void bufferInfoUpdated(UserId user, const BufferInfo &); //! Sent when a new user has been added void userAdded(UserId, const QString &username); //! Sent when a user has been renamed @@ -166,8 +166,7 @@ class Storage : public QObject { void userRemoved(UserId); public: - /* Exceptions */ - struct AuthError : public Exception {}; + }; diff --git a/src/icons/icons.qrc b/src/icons/icons.qrc index fe36a6d7..5630df6a 100644 --- a/src/icons/icons.qrc +++ b/src/icons/icons.qrc @@ -484,8 +484,8 @@ oxygen/22x22/actions/media-seek-forward.png oxygen/22x22/actions/media-skip-backward.png oxygen/22x22/actions/media-skip-forward.png - oxygen/22x22/actions/network-connect.png - oxygen/22x22/actions/network-disconnect.png + oxygen/22x22/actions/network-connect.png + oxygen/22x22/actions/network-disconnect.png oxygen/22x22/actions/news-subscribe.png oxygen/22x22/actions/news-unsubscribe.png oxygen/22x22/actions/object-rotate-left.png @@ -584,6 +584,16 @@ oxygen/22x22/actions/zoom-original.png oxygen/22x22/actions/zoom-out.png + + oxygen/22x22/status/dialog-error.png + oxygen/22x22/status/dialog-information.png + oxygen/22x22/status/dialog-password.png + oxygen/22x22/status/dialog-warning.png + oxygen/22x22/status/script-error.png + oxygen/22x22/status/security-high.png + oxygen/22x22/status/security-low.png + oxygen/22x22/status/security-medium.png + quassel-icon.png diff --git a/src/qtui/chatline-old.cpp b/src/qtui/chatline-old.cpp index 4146db97..017a4792 100644 --- a/src/qtui/chatline-old.cpp +++ b/src/qtui/chatline-old.cpp @@ -21,11 +21,9 @@ #include "chatline-old.h" #include "qtui.h" -//!\brief Construct a ChatLine object from a message. +//! Construct a ChatLine object from a message. /** * \param m The message to be layouted and rendered - * \param net The network name - * \param buf The buffer name */ ChatLine::ChatLine(Message m) { hght = 0; diff --git a/src/qtui/coreconnectdlg.cpp b/src/qtui/coreconnectdlg.cpp index 643b0fff..3b4a21a6 100644 --- a/src/qtui/coreconnectdlg.cpp +++ b/src/qtui/coreconnectdlg.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-08 by the Quassel IRC Team * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -18,319 +18,385 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include +#include +#include + #include "coreconnectdlg.h" -#include "client.h" + #include "clientsettings.h" -#include "configwizard.h" -#include "global.h" +#include "clientsyncer.h" + +CoreConnectDlg::CoreConnectDlg(QWidget *parent, bool autoconnect) : QDialog(parent) { + ui.setupUi(this); -CoreConnectDlg::CoreConnectDlg(QWidget *parent, bool /*doAutoConnect*/) : QDialog(parent) { - ui.setupUi(this); //qDebug() << "new dlg"; + clientSyncer = new ClientSyncer(this); setAttribute(Qt::WA_DeleteOnClose); - coreState = 0; - /* We show ui.internalCore in any case, because we might want to run as monolithic client anyway at another time - if(Global::runMode == Global::Monolithic) { - connect(ui.internalCore, SIGNAL(toggled(bool)), ui.hostEdit, SLOT(setDisabled(bool))); - connect(ui.internalCore, SIGNAL(toggled(bool)), ui.port, SLOT(setDisabled(bool))); - ui.internalCore->setChecked(true); - } else { - //ui.internalCore->hide(); - } - */ - connect(ui.newAccount, SIGNAL(clicked()), this, SLOT(createAccount())); - connect(ui.delAccount, SIGNAL(clicked()), this, SLOT(removeAccount())); - connect(ui.buttonBox1, SIGNAL(accepted()), this, SLOT(doConnect())); - connect(ui.hostEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkInputValid())); - connect(ui.userEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkInputValid())); - connect(ui.internalCore, SIGNAL(toggled(bool)), this, SLOT(checkInputValid())); - connect(ui.internalCore, SIGNAL(toggled(bool)), ui.hostEdit, SLOT(setDisabled(bool))); - connect(ui.internalCore, SIGNAL(toggled(bool)), ui.port, SLOT(setDisabled(bool))); - connect(ui.accountList, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(accountChanged(const QString &))); - connect(ui.autoConnect, SIGNAL(clicked(bool)), this, SLOT(autoConnectToggled(bool))); - - connect(Client::instance(), SIGNAL(coreConnectionMsg(const QString &)), ui.connectionStatus, SLOT(setText(const QString &))); - connect(Client::instance(), SIGNAL(coreConnectionProgress(uint, uint)), this, SLOT(updateProgressBar(uint, uint))); - connect(Client::instance(), SIGNAL(coreConnectionError(QString)), this, SLOT(coreConnectionError(QString))); - connect(Client::instance(), SIGNAL(connected()), this, SLOT(coreConnected())); - - connect(Client::instance(), SIGNAL(showConfigWizard(const QVariantMap &)), this, SLOT(showConfigWizard(const QVariantMap &))); - - AccountSettings s; + doingAutoConnect = false; + + ui.stackedWidget->setCurrentWidget(ui.accountPage); + ui.accountButtonBox->setFocus(); + + CoreAccountSettings s; QString lastacc = s.lastAccount(); - ui.accountList->addItems(s.knownAccounts()); - if(!ui.accountList->count()) { - //if(doAutoConnect) reject(); - - setAccountEditEnabled(false); - QString newacc = QInputDialog::getText(this, tr("Create Account"), tr( - "In order to connect to a Quassel Core, you need to create an account.
" - "Please enter a name for this account now:"), QLineEdit::Normal, tr("Default")); - if(!newacc.isEmpty()) { - ui.accountList->addItem(newacc); - ui.hostEdit->setText("localhost"); - ui.port->setValue(Global::defaultPort); - ui.internalCore->setChecked(false); - setAccountEditEnabled(true); - } - /* - // FIXME We create a default account here that just connects to the internal core - curacc = "Default"; - ui.accountList->addItem("Default"); - ui.internalCore->setChecked(true); - ui.userEdit->setText("Default"); - ui.passwdEdit->setText("password"); - ui.rememberPasswd->setChecked(true); - accountChanged(curacc); - ui.passwdEdit->setText("password"); - ui.accountList->setCurrentIndex(0); - ui.autoConnect->setChecked(true); - autoConnectToggled(true); - */ - } else { - if(!lastacc.isEmpty()) { - //if(doAutoConnect) { qDebug() << "auto"; - // AccountSettings s; - // int idx = ui.accountList->findText(s.autoConnectAccount()); - // if(idx < 0) reject(); - // else { - // ui.accountList->setCurrentIndex(idx); - // doConnect(); - // } - //} else { - int idx = ui.accountList->findText(lastacc); - ui.accountList->setCurrentIndex(idx); - //} - } + autoConnectAccount = s.autoConnectAccount(); + accounts = s.retrieveAllAccounts(); + ui.accountList->addItems(accounts.keys()); + QList l = ui.accountList->findItems(lastacc, Qt::MatchExactly); + if(l.count()) ui.accountList->setCurrentItem(l[0]); + else ui.accountList->setCurrentRow(0); + + setAccountWidgetStates(); + + connect(clientSyncer, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)),this, SLOT(initPhaseSocketState(QAbstractSocket::SocketState))); + connect(clientSyncer, SIGNAL(connectionError(const QString &)), this, SLOT(initPhaseError(const QString &))); + connect(clientSyncer, SIGNAL(connectionMsg(const QString &)), this, SLOT(initPhaseMsg(const QString &))); + connect(clientSyncer, SIGNAL(startLogin()), this, SLOT(startLogin())); + connect(clientSyncer, SIGNAL(loginFailed(const QString &)), this, SLOT(loginFailed(const QString &))); + connect(clientSyncer, SIGNAL(loginSuccess()), this, SLOT(startSync())); + connect(clientSyncer, SIGNAL(sessionProgress(quint32, quint32)), this, SLOT(coreSessionProgress(quint32, quint32))); + connect(clientSyncer, SIGNAL(networksProgress(quint32, quint32)), this, SLOT(coreNetworksProgress(quint32, quint32))); + connect(clientSyncer, SIGNAL(channelsProgress(quint32, quint32)), this, SLOT(coreChannelsProgress(quint32, quint32))); + connect(clientSyncer, SIGNAL(ircUsersProgress(quint32, quint32)), this, SLOT(coreIrcUsersProgress(quint32, quint32))); + connect(clientSyncer, SIGNAL(syncFinished()), this, SLOT(accept())); + + connect(ui.user, SIGNAL(textChanged(const QString &)), this, SLOT(setLoginWidgetStates())); + connect(ui.password, SIGNAL(textChanged(const QString &)), this, SLOT(setLoginWidgetStates())); + + connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull())); + connect(ui.syncButtonBox->button(QDialogButtonBox::Abort), SIGNAL(clicked()), this, SLOT(restartPhaseNull())); + + if(autoconnect && ui.accountList->count() && !autoConnectAccount.isEmpty() && autoConnectAccount == ui.accountList->currentItem()->text()) { + doingAutoConnect = true; + on_accountButtonBox_accepted(); } } CoreConnectDlg::~CoreConnectDlg() { - //qDebug() << "destroy"; + if(ui.accountList->selectedItems().count()) { + CoreAccountSettings s; + s.setLastAccount(ui.accountList->selectedItems()[0]->text()); + } } -void CoreConnectDlg::setAccountEditEnabled(bool en) { - ui.accountList->setEnabled(en); - ui.hostEdit->setEnabled(en && !ui.internalCore->isChecked()); - ui.userEdit->setEnabled(en); - ui.passwdEdit->setEnabled(en); - ui.port->setEnabled(en && !ui.internalCore->isChecked()); - ui.editAccount->setEnabled(en); - ui.delAccount->setEnabled(en); - ui.internalCore->setEnabled(en); - ui.rememberPasswd->setEnabled(en); - ui.autoConnect->setEnabled(en); - ui.buttonBox1->button(QDialogButtonBox::Ok)->setEnabled(en && checkInputValid()); + +/**************************************************** + * Account Management + ***************************************************/ + +void CoreConnectDlg::on_accountList_itemSelectionChanged() { + setAccountWidgetStates(); } -void CoreConnectDlg::accountChanged(const QString &text) { - AccountSettings s; - if(!curacc.isEmpty()) { - QVariantMap oldAcc; - oldAcc["User"] = ui.userEdit->text(); - oldAcc["Host"] = ui.hostEdit->text(); - oldAcc["Port"] = ui.port->value(); - oldAcc["InternalCore"] = ui.internalCore->isChecked(); - if(ui.rememberPasswd->isChecked()) oldAcc["Password"] = ui.passwdEdit->text(); - s.setValue(curacc, "AccountData", oldAcc); - } - ui.autoConnect->setChecked(false); - if(!text.isEmpty()) { // empty text: just save stuff - curacc = text; - s.setLastAccount(curacc); - QVariantMap newAcc = s.value(curacc, "AccountData").toMap(); - ui.userEdit->setText(newAcc["User"].toString()); - ui.hostEdit->setText(newAcc["Host"].toString()); - ui.port->setValue(newAcc["Port"].toInt()); - ui.internalCore->setChecked(newAcc["InternalCore"].toBool()); - if(newAcc.contains("Password")) { - ui.passwdEdit->setText(newAcc["Password"].toString()); - ui.rememberPasswd->setChecked(true); - } else ui.rememberPasswd->setChecked(false); - if(s.autoConnectAccount() == curacc) ui.autoConnect->setChecked(true); +void CoreConnectDlg::setAccountWidgetStates() { + QList selectedItems = ui.accountList->selectedItems(); + ui.editAccount->setEnabled(selectedItems.count()); + ui.deleteAccount->setEnabled(selectedItems.count()); + ui.autoConnect->setEnabled(selectedItems.count()); + if(selectedItems.count()) { + ui.autoConnect->setChecked(selectedItems[0]->text() == autoConnectAccount); } } -void CoreConnectDlg::autoConnectToggled(bool autoConnect) { - AccountSettings s; - if(autoConnect) s.setAutoConnectAccount(curacc); - else s.setAutoConnectAccount(""); +void CoreConnectDlg::on_autoConnect_clicked(bool state) { + if(!state) { + autoConnectAccount = QString(); + } else { + if(ui.accountList->selectedItems().count()) { + autoConnectAccount = ui.accountList->selectedItems()[0]->text(); + } else { + qWarning() << "Checked auto connect without an enabled item!"; // should never happen! + autoConnectAccount = QString(); + } + } + setAccountWidgetStates(); } -bool CoreConnectDlg::checkInputValid() { - bool res = (ui.internalCore->isChecked() || ui.hostEdit->text().count()) && ui.userEdit->text().count(); - ui.buttonBox1->button(QDialogButtonBox::Ok)->setEnabled(res); - return res; +void CoreConnectDlg::on_addAccount_clicked() { + QStringList existing; + for(int i = 0; i < ui.accountList->count(); i++) existing << ui.accountList->item(i)->text(); + CoreAccountEditDlg dlg(QString(), QVariantMap(), existing, this); + if(dlg.exec() == QDialog::Accepted) { + accounts[dlg.accountName()] = dlg.accountData(); + ui.accountList->addItem(dlg.accountName()); + ui.accountList->setCurrentItem(ui.accountList->findItems(dlg.accountName(), Qt::MatchExactly)[0]); + } } -void CoreConnectDlg::createAccount() { - QString accname = QInputDialog::getText(this, tr("Create Account"), tr("Please enter a name for the new account:")); - if(accname.isEmpty()) return; - if(ui.accountList->findText(accname) >= 0) { - QMessageBox::warning(this, tr("Account name already exists!"), tr("An account named '%1' already exists, and account names must be unique!").arg(accname)); - return; +void CoreConnectDlg::on_editAccount_clicked() { + QStringList existing; + for(int i = 0; i < ui.accountList->count(); i++) existing << ui.accountList->item(i)->text(); + QString current = ui.accountList->currentItem()->text(); + QVariantMap acct = accounts[current]; + CoreAccountEditDlg dlg(current, acct, existing, this); + if(dlg.exec() == QDialog::Accepted) { + if(current != dlg.accountName()) { + if(autoConnectAccount == current) autoConnectAccount = dlg.accountName(); + accounts.remove(current); + current = dlg.accountName(); + ui.accountList->currentItem()->setText(current); + } + accounts[current] = dlg.accountData(); } - QVariantMap defdata; - ui.accountList->addItem(accname); - ui.accountList->setCurrentIndex(ui.accountList->findText(accname)); - setAccountEditEnabled(true); + //ui.accountList->setCurrent } -void CoreConnectDlg::removeAccount() { - QString acc = ui.accountList->currentText(); - int res = QMessageBox::warning(this, tr("Delete account?"), tr("Do you really want to delete the data for the account '%1'?
" - "Note that this only affects your local account settings and will not remove " - "any data from the core.").arg(acc), - QMessageBox::Yes|QMessageBox::No, QMessageBox::No); - if(res == QMessageBox::Yes) { - AccountSettings s; - s.removeAccount(acc); - curacc = ""; - ui.accountList->removeItem(ui.accountList->findText(acc)); - if(!ui.accountList->count()) setAccountEditEnabled(false); +void CoreConnectDlg::on_deleteAccount_clicked() { + QString current = ui.accountList->currentItem()->text(); + int ret = QMessageBox::question(this, tr("Remove Account Settings"), + tr("Do you really want to remove your local settings for this Quassel Core account?
" + "Note: This will not remove or change any data on the Core itself!"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::No); + if(ret == QMessageBox::Yes) { + int idx = ui.accountList->currentRow(); + delete ui.accountList->item(idx); + ui.accountList->setCurrentRow(qMin(idx, ui.accountList->count())); + accounts.remove(current); } } -bool CoreConnectDlg::willDoInternalAutoConnect() { - AccountSettings s; - if(Global::runMode != Global::Monolithic) return false; - if(ui.autoConnect->isChecked() && s.autoConnectAccount() == curacc && ui.internalCore->isChecked()) { - return true; - } - return false; +void CoreConnectDlg::on_accountList_itemDoubleClicked(QListWidgetItem *item) { + Q_UNUSED(item); + on_accountButtonBox_accepted(); +} + +void CoreConnectDlg::on_accountButtonBox_accepted() { + // save accounts + CoreAccountSettings s; + s.storeAllAccounts(accounts); + s.setAutoConnectAccount(autoConnectAccount); + + ui.stackedWidget->setCurrentWidget(ui.loginPage); + accountName = ui.accountList->currentItem()->text(); + account = s.retrieveAccount(accountName); + s.setLastAccount(accountName); + connectToCore(); +} + +/***************************************************** + * Connecting to the Core + ****************************************************/ + +/*** Phase One: initializing the core connection ***/ + +void CoreConnectDlg::connectToCore() { + ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/actions/network-disconnect"))); + ui.connectLabel->setText(tr("Connect to %1").arg(account["Host"].toString())); + ui.coreInfoLabel->setText(""); + ui.loginStack->setCurrentWidget(ui.loginEmptyPage); + ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + ui.loginButtonBox->button(QDialogButtonBox::Ok)->setDisabled(true); + disconnect(ui.loginButtonBox, 0, this, 0); + connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull())); + + + //connect(Client::instance(), SIGNAL(coreConnectionPhaseOne(const QVariantMap &)), this, SLOT(phaseOneFinished + clientSyncer->connectToCore(account); +} + +void CoreConnectDlg::initPhaseError(const QString &error) { + doingAutoConnect = false; + ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/status/dialog-error"))); + //ui.connectLabel->setBrush(QBrush("red")); + ui.connectLabel->setText(tr("
Connection to %1 failed!
").arg(account["Host"].toString())); + ui.coreInfoLabel->setText(error); + ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Retry|QDialogButtonBox::Cancel); + disconnect(ui.loginButtonBox, 0, this, 0); + connect(ui.loginButtonBox, SIGNAL(accepted()), this, SLOT(restartPhaseNull())); + connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(reject())); +} + +void CoreConnectDlg::initPhaseMsg(const QString &msg) { + ui.coreInfoLabel->setText(msg); } -void CoreConnectDlg::doAutoConnect() { - AccountSettings s; - if(s.autoConnectAccount() == curacc) { - doConnect(); +void CoreConnectDlg::initPhaseSocketState(QAbstractSocket::SocketState state) { + QString s; + QString host = account["Host"].toString(); + switch(state) { + case QAbstractSocket::UnconnectedState: s = tr("Not connected to %1.").arg(host); break; + case QAbstractSocket::HostLookupState: s = tr("Looking up %1...").arg(host); break; + case QAbstractSocket::ConnectingState: s = tr("Connecting to %1...").arg(host); break; + case QAbstractSocket::ConnectedState: s = tr("Connected to %1").arg(host); break; + default: s = tr("Unknown connection state to %1"); break; } + ui.connectLabel->setText(s); } -void CoreConnectDlg::doConnect() { - accountChanged(); // save current account info - QVariantMap conninfo; - ui.stackedWidget->setCurrentIndex(1); - if(ui.internalCore->isChecked()) { - // FIXME - coreConnectionError(tr("Can't connect to internal core at the moment [serious breakage due to switch to dynamic signals]. Please check back later.")); - return; - if(Global::runMode != Global::Monolithic) { - coreConnectionError(tr("Can't connect to internal core, since we are running as a standalone GUI!")); - return; +void CoreConnectDlg::restartPhaseNull() { + doingAutoConnect = false; + ui.stackedWidget->setCurrentWidget(ui.accountPage); + clientSyncer->disconnectFromCore(); +} + +/********************************************************* + * Phase Two: Login + *********************************************************/ + +void CoreConnectDlg::startLogin() { + ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/actions/network-connect"))); + ui.loginStack->setCurrentWidget(ui.loginCredentialsPage); + ui.loginStack->setMinimumSize(ui.loginStack->sizeHint()); ui.loginStack->updateGeometry(); + ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); + if(!account["User"].toString().isEmpty()) { + ui.user->setText(account["User"].toString()); + if(account["RememberPasswd"].toBool()) { + ui.password->setText(account["Password"].toString()); + ui.rememberPasswd->setChecked(true); + } else { + ui.rememberPasswd->setChecked(false); + ui.password->setFocus(); } - ui.connectionGroupBox->setTitle(tr("Connecting to internal core")); - ui.connectionProgress->hide(); + } else ui.user->setFocus(); + disconnect(ui.loginButtonBox, 0, this, 0); + connect(ui.loginButtonBox, SIGNAL(accepted()), this, SLOT(doLogin())); + connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull())); + if(doingAutoConnect) doLogin(); +} + +void CoreConnectDlg::doLogin() { + ui.loginGroup->setTitle(tr("Logging in...")); + ui.user->setDisabled(true); + ui.password->setDisabled(true); + ui.rememberPasswd->setDisabled(true); + ui.loginButtonBox->button(QDialogButtonBox::Ok)->setDisabled(true); + account["User"] = ui.user->text(); + account["RememberPasswd"] = ui.rememberPasswd->isChecked(); + if(ui.rememberPasswd->isChecked()) account["Password"] = ui.password->text(); + else account.remove("Password"); + CoreAccountSettings s; + s.storeAccount(accountName, account); + clientSyncer->loginToCore(account["User"].toString(), account["Password"].toString()); +} + +void CoreConnectDlg::setLoginWidgetStates() { + ui.loginButtonBox->button(QDialogButtonBox::Ok)->setDisabled(ui.user->text().isEmpty() || ui.password->text().isEmpty()); +} + +void CoreConnectDlg::loginFailed(const QString &error) { + ui.loginGroup->setTitle(tr("Login")); + ui.user->setEnabled(true); + ui.password->setEnabled(true); + ui.rememberPasswd->setEnabled(true); + ui.coreInfoLabel->setText(error); + ui.loginButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + ui.password->setFocus(); + doingAutoConnect = false; +} + +/************************************************************ + * Phase Three: Syncing + ************************************************************/ + +void CoreConnectDlg::startSync() { + ui.sessionProgress->setRange(0, 1); + ui.sessionProgress->setValue(0); + ui.networksProgress->setRange(0, 1); + ui.networksProgress->setValue(0); + ui.channelsProgress->setRange(0, 1); + ui.channelsProgress->setValue(0); + ui.ircUsersProgress->setRange(0, 1); + ui.ircUsersProgress->setValue(0); + + ui.stackedWidget->setCurrentWidget(ui.syncPage); + // clean up old page + ui.loginGroup->setTitle(tr("Login")); + ui.user->setEnabled(true); + ui.password->setEnabled(true); + ui.rememberPasswd->setEnabled(true); + ui.loginButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true); +} + + +void CoreConnectDlg::coreSessionProgress(quint32 val, quint32 max) { + ui.sessionProgress->setRange(0, max); + ui.sessionProgress->setValue(val); + +} + +void CoreConnectDlg::coreNetworksProgress(quint32 val, quint32 max) { + if(max == 0) { + ui.networksProgress->setFormat("0/0"); + ui.networksProgress->setRange(0, 1); + ui.networksProgress->setValue(1); } else { - ui.connectionGroupBox->setTitle(tr("Connecting to %1").arg(ui.hostEdit->text())); - conninfo["Host"] = ui.hostEdit->text(); - conninfo["Port"] = ui.port->value(); - } - conninfo["User"] = ui.userEdit->text(); - conninfo["Password"] = ui.passwdEdit->text(); - ui.profileLabel->hide(); ui.guiProfile->hide(); - ui.newGuiProfile->hide(); ui.alwaysUseProfile->hide(); - ui.connectionProgress->show(); - try { - Client::instance()->connectToCore(conninfo); - } catch(Exception e) { - QString msg; - //if(!e.msg().isEmpty()) msg = tr("
%1").arg(e.msg()); // FIXME throw more detailed (vulgo: any) error msg - coreConnectionError(tr("Invalid user or password. Pleasy try again.%1").arg(msg)); - //QMessageBox::warning(this, tr("Unknown account"), tr("Invalid user or password. Pleasy try again.%1").arg(msg)); - //cancelConnect(); - return; + ui.networksProgress->setFormat("%v/%m"); + ui.networksProgress->setRange(0, max); + ui.networksProgress->setValue(val); } } -void CoreConnectDlg::cancelConnect() { - ui.stackedWidget->setCurrentIndex(0); +void CoreConnectDlg::coreChannelsProgress(quint32 val, quint32 max) { + if(max == 0) { + ui.channelsProgress->setFormat("0/0"); + ui.channelsProgress->setRange(0, 1); + ui.channelsProgress->setValue(1); + } else { + ui.channelsProgress->setFormat("%v/%m"); + ui.channelsProgress->setRange(0, max); + ui.channelsProgress->setValue(val); + } } -void CoreConnectDlg::setStartState() { /* - ui.hostName->show(); ui.hostPort->show(); ui.hostLabel->show(); ui.portLabel->show(); - ui.statusText->setText(tr("Connect to Quassel Core running on:")); - ui.buttonBox->button(QDialogButtonBox::Ok)->show(); - ui.hostName->setEnabled(true); ui.hostPort->setEnabled(true); - ui.hostName->setSelection(0, ui.hostName->text().length()); */ - ui.stackedWidget->setCurrentIndex(0); +void CoreConnectDlg::coreIrcUsersProgress(quint32 val, quint32 max) { + if(max == 0) { + ui.ircUsersProgress->setFormat("0/0"); + ui.ircUsersProgress->setRange(0, 1); + ui.ircUsersProgress->setValue(1); + } else { + ui.ircUsersProgress->setFormat("%v/%m"); + ui.ircUsersProgress->setRange(0, max); + ui.ircUsersProgress->setValue(val); + } } -void CoreConnectDlg::hostEditChanged(QString /*txt*/) { - //ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(txt.length()); -} +/***************************************************************************************** + * CoreAccountEditDlg + *****************************************************************************************/ -void CoreConnectDlg::hostSelected() { /* - ui.hostName->hide(); ui.hostPort->hide(); ui.hostLabel->hide(); ui.portLabel->hide(); - ui.statusText->setText(tr("Connecting to %1:%2" ).arg(ui.hostName->text()).arg(ui.hostPort->value())); - ui.buttonBox->button(QDialogButtonBox::Ok)->hide(); - connect(ClientProxy::instance(), SIGNAL(coreConnected()), this, SLOT(coreConnected())); - connect(ClientProxy::instance(), SIGNAL(coreConnectionError(QString)), this, SLOT(coreConnectionError(QString))); - Client::instance()->connectToCore(ui.hostName->text(), ui.hostPort->value()); -*/ +CoreAccountEditDlg::CoreAccountEditDlg(const QString &name, const QVariantMap &acct, const QStringList &_existing, QWidget *parent) : QDialog(parent) { + ui.setupUi(this); + existing = _existing; + account = acct; + if(!name.isEmpty()) { + existing.removeAll(name); + ui.host->setText(acct["Host"].toString()); + ui.port->setValue(acct["Port"].toUInt()); + ui.useInternal->setChecked(acct["UseInternal"].toBool()); + ui.accountName->setText(name); + } else { + setWindowTitle(tr("Add Core Account")); + } } -void CoreConnectDlg::coreConnected() { /* - ui.hostLabel->hide(); ui.hostName->hide(); ui.portLabel->hide(); ui.hostPort->hide(); - ui.statusText->setText(tr("Synchronizing...")); - QSettings s; - s.setValue("GUI/CoreHost", ui.hostName->text()); - s.setValue("GUI/CorePort", ui.hostPort->value()); - s.setValue("GUI/CoreAutoConnect", ui.autoConnect->isChecked()); - connect(ClientProxy::instance(), SIGNAL(recvPartialItem(quint32, quint32)), this, SLOT(updateProgressBar(quint32, quint32))); - connect(ClientProxy::instance(), SIGNAL(csCoreState(QVariant)), this, SLOT(recvCoreState(QVariant))); - ui.progressBar->show(); - QVariantMap initmsg; - initmsg["GUIProtocol"] = GUI_PROTOCOL; - // FIXME guiProxy->send(GS_CLIENT_INIT, QVariant(initmsg)); */ - ui.connectionStatus->setText(tr("Connected to core.")); - accept(); +QString CoreAccountEditDlg::accountName() const { + return ui.accountName->text(); } -void CoreConnectDlg::coreConnectionError(QString err) { - ui.stackedWidget->setCurrentIndex(0); - show(); // just in case we started hidden - QMessageBox::warning(this, tr("Connection Error"), tr("Could not connect to Quassel Core!
\n") + err, QMessageBox::Retry); - //disconnect(ClientProxy::instance(), 0, this, 0); FIXME? - //ui.autoConnect->setChecked(false); - setStartState(); +QVariantMap CoreAccountEditDlg::accountData() { + account["Host"] = ui.host->text(); + account["Port"] = ui.port->value(); + account["UseInternal"] = ui.useInternal->isChecked(); + return account; } -void CoreConnectDlg::updateProgressBar(uint partial, uint total) { - ui.connectionProgress->setMaximum(total); - ui.connectionProgress->setValue(partial); - //qDebug() << "progress:" << partial << total; +void CoreAccountEditDlg::setWidgetStates() { + bool ok = !accountName().isEmpty() && !existing.contains(accountName()) && (ui.useInternal->isChecked() || !ui.host->text().isEmpty()); + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok); } -void CoreConnectDlg::recvCoreState(QVariant state) { - //ui.progressBar->hide(); - coreState = state; - accept(); +void CoreAccountEditDlg::on_host_textChanged(const QString &text) { + Q_UNUSED(text); + setWidgetStates(); } -QVariant CoreConnectDlg::getCoreState() { - return coreState; +void CoreAccountEditDlg::on_accountName_textChanged(const QString &text) { + Q_UNUSED(text); + setWidgetStates(); } -void CoreConnectDlg::showConfigWizard(const QVariantMap &coredata) { - QStringList storageProviders = coredata["StorageProviders"].toStringList(); - ConfigWizard *wizard = new ConfigWizard(storageProviders, this); - wizard->exec(); - QVariantMap reply; - reply["GuiProtocol"] = GUI_PROTOCOL; - reply["HasSettings"] = true; - reply["User"] = wizard->field("adminuser.name").toString(); - reply["Password"] = wizard->field("adminuser.password").toString(); - QString sp = storageProviders.value(wizard->field("storage.provider").toInt()); - reply["Type"] = sp; - if (sp.compare("Sqlite", Qt::CaseInsensitive)) { - reply["Host"] = wizard->field("storage.host").toString(); - reply["Port"] = wizard->field("storage.port").toString(); - reply["Database"] = wizard->field("storage.database").toString(); - reply["User"] = wizard->field("storage.user").toString(); - reply["Password"] = wizard->field("storage.password").toString(); - } - Client::instance()->setCoreConfiguration(reply); +void CoreAccountEditDlg::on_useRemote_toggled(bool state) { + Q_UNUSED(state); + setWidgetStates(); } diff --git a/src/qtui/coreconnectdlg.h b/src/qtui/coreconnectdlg.h index 3b6f5847..4714a012 100644 --- a/src/qtui/coreconnectdlg.h +++ b/src/qtui/coreconnectdlg.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-08 by the Quassel IRC Team * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -18,52 +18,96 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#ifndef _CORECONNECTDLG_H -#define _CORECONNECTDLG_H +#ifndef _CORECONNECTDLG_H_ +#define _CORECONNECTDLG_H_ + +#include #include "ui_coreconnectdlg.h" +#include "ui_coreaccounteditdlg.h" + +class ClientSyncer; -class CoreConnectDlg: public QDialog { +class CoreConnectDlg : public QDialog { Q_OBJECT public: - CoreConnectDlg(QWidget *parent, bool doAutoConnect = false); + CoreConnectDlg(QWidget *parent = 0, bool = false); ~CoreConnectDlg(); - QVariant getCoreState(); - - bool willDoInternalAutoConnect(); - - public slots: - void doAutoConnect(); private slots: - void createAccount(); - void removeAccount(); - void accountChanged(const QString & = ""); - void setAccountEditEnabled(bool); - void autoConnectToggled(bool); - bool checkInputValid(); - void hostEditChanged(QString); - void hostSelected(); - void doConnect(); - - void coreConnected(); - void coreConnectionError(QString); - //void coreConnectionMsg(const QString &); - //void coreConnectionProgress(uint partial, uint total); - void updateProgressBar(uint partial, uint total); - void recvCoreState(QVariant); - - void showConfigWizard(const QVariantMap &coredata); + + /*** Phase Null: Accounts ***/ + void restartPhaseNull(); + + void on_accountList_itemSelectionChanged(); + void on_autoConnect_clicked(bool); + + void on_addAccount_clicked(); + void on_editAccount_clicked(); + void on_deleteAccount_clicked(); + + void on_accountList_itemDoubleClicked(QListWidgetItem *item); + void on_accountButtonBox_accepted(); + + void setAccountWidgetStates(); + + /*** Phase One: Connection ***/ + void connectToCore(); + + void initPhaseError(const QString &error); + void initPhaseMsg(const QString &msg); + void initPhaseSocketState(QAbstractSocket::SocketState); + + /*** Phase Two: Login ***/ + void startLogin(); + void doLogin(); + void loginFailed(const QString &); + + void setLoginWidgetStates(); + + /*** Phase Three: Sync ***/ + void startSync(); + + void coreSessionProgress(quint32, quint32); + void coreNetworksProgress(quint32, quint32); + void coreChannelsProgress(quint32, quint32); + void coreIrcUsersProgress(quint32, quint32); private: Ui::CoreConnectDlg ui; - QVariant coreState; - void cancelConnect(); - void setStartState(); - QVariantMap accountData; - QString curacc; + QString autoConnectAccount; + QHash accounts; + QVariantMap account; + QString accountName; + + bool doingAutoConnect; + + ClientSyncer *clientSyncer; +}; + +class CoreAccountEditDlg : public QDialog { + Q_OBJECT + + public: + CoreAccountEditDlg(const QString &name, const QVariantMap &data, const QStringList &existing = QStringList(), QWidget *parent = 0); + + QString accountName() const; + QVariantMap accountData(); + + private slots: + void on_host_textChanged(const QString &); + void on_accountName_textChanged(const QString &); + void on_useRemote_toggled(bool); + + void setWidgetStates(); + + private: + Ui::CoreAccountEditDlg ui; + + QStringList existing; + QVariantMap account; }; #endif diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index 6c63404f..8aa0bb2e 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -129,7 +129,7 @@ void MainWin::init() { // attach the BufferWidget to the PropertyMapper Client::bufferModel()->mapProperty(0, NetworkModel::BufferIdRole, ui.bufferWidget, "currentBuffer"); connect(Client::networkModel(), SIGNAL(bufferAboutToBeRemoved(BufferId)), - ui.bufferWidget, SLOT(removeBuffer(BufferId))); + ui.bufferWidget, SLOT(removeBuffer(BufferId))); // attach the NickList to the PropertyMapper Client::bufferModel()->mapProperty(0, NetworkModel::BufferIdRole, nickListWidget, "currentBuffer"); @@ -237,14 +237,14 @@ void MainWin::showCoreConnectionDlg(bool autoConnect) { coreConnectDlg = new CoreConnectDlg(this, autoConnect); connect(coreConnectDlg, SIGNAL(finished(int)), this, SLOT(coreConnectionDlgFinished(int))); coreConnectDlg->setModal(true); - if(!autoConnect || !coreConnectDlg->willDoInternalAutoConnect()) + //if(!autoConnect || !coreConnectDlg->willDoInternalAutoConnect()) coreConnectDlg->show(); // avoid flicker and show dlg only if we do remote connect, which needs a progress bar - if(autoConnect) coreConnectDlg->doAutoConnect(); + //if(autoConnect) coreConnectDlg->doAutoConnect(); } void MainWin::coreConnectionDlgFinished(int /*code*/) { - coreConnectDlg->close(); + //exit(1); } diff --git a/src/qtui/qtui.pri b/src/qtui/qtui.pri index 1f91e79a..5570020b 100644 --- a/src/qtui/qtui.pri +++ b/src/qtui/qtui.pri @@ -11,7 +11,7 @@ HDRS += bufferwidget.h chatline-old.h chatwidget.h configwizard.h \ topicwidget.h debugconsole.h FORMNAMES = identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui nickeditdlg.ui serverlistdlg.ui \ - servereditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui nicklistwidget.ui settingsdlg.ui \ + servereditdlg.ui coreaccounteditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui nicklistwidget.ui settingsdlg.ui \ buffermgmtpage.ui connectionpage.ui usermgmtpage.ui topicwidget.ui debugconsole.ui for(ui, FORMNAMES) { diff --git a/src/qtui/ui/coreaccounteditdlg.ui b/src/qtui/ui/coreaccounteditdlg.ui new file mode 100644 index 00000000..4f056bc8 --- /dev/null +++ b/src/qtui/ui/coreaccounteditdlg.ui @@ -0,0 +1,239 @@ + + CoreAccountEditDlg + + + + 0 + 0 + 395 + 242 + + + + Edit Core Account + + + + + + + + Account Details + + + + + + + + Account Name: + + + + + + + + + + + + + + false + + + + + + + + + + false + + + Use built-in Quassel Core + + + useInternal + + + + + + + + + + true + + + + + + + Remote host: + + + useRemote + + + + + + + Port: + + + + + + + + + + 1 + + + 65535 + + + 4242 + + + + + + + false + + + Use secure connection (SSL) + + + :/16x16/actions/oxygen/16x16/actions/document-encrypt.png + + + false + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + + + + + buttonBox + accepted() + CoreAccountEditDlg + accept() + + + 263 + 230 + + + 157 + 207 + + + + + buttonBox + rejected() + CoreAccountEditDlg + reject() + + + 331 + 230 + + + 286 + 207 + + + + + useInternal + toggled(bool) + host + setDisabled(bool) + + + 30 + 79 + + + 92 + 143 + + + + + useInternal + toggled(bool) + port + setDisabled(bool) + + + 39 + 78 + + + 331 + 144 + + + + + useRemote + clicked(bool) + host + setFocus() + + + 26 + 113 + + + 184 + 146 + + + + + diff --git a/src/qtui/ui/coreconnectdlg.ui b/src/qtui/ui/coreconnectdlg.ui index a840031c..91ce6cad 100644 --- a/src/qtui/ui/coreconnectdlg.ui +++ b/src/qtui/ui/coreconnectdlg.ui @@ -5,419 +5,451 @@ 0 0 - 462 - 249 + 511 + 389 - - - 0 - 0 - - Connect to Quassel Core - - - - - false - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - + + 0 - - - - - - Account Settings - - - - - - Account: - - - - - - - false - - - QComboBox::InsertAlphabetically - - - - - - - ... - - - :/22x22/actions/oxygen/22x22/actions/configure.png - - - - 22 - 22 - - - - - - - - ... - - - :/22x22/actions/oxygen/22x22/actions/list-add.png - - - - 22 - 22 - - - - - - - - ... - - - :/22x22/actions/oxygen/22x22/actions/edit-delete.png - - - - 22 - 22 - - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - - - - - Host: - - - - - - - - - - false - - - Use internal - - - false - - - - - - - Port: - - - - - - - 1024 - - - 65535 - - - 4242 - - - - - - - Qt::Horizontal - - - - 211 - 20 - - - - - - - - User: - - - - - - - - - - Password: - - - - - - - QLineEdit::Password - - - - - - - Remember - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - + + + + 2 + + + - - - Always use this account - - - false + + + Connect to Quassel Core + + + + + true + + + + + + + + + Edit... + + + :/16x16/actions/oxygen/16x16/actions/configure.png + + + + + + + Add... + + + :/16x16/actions/oxygen/16x16/actions/list-add.png + + + + + + + Delete + + + :/16x16/actions/oxygen/16x16/actions/list-remove.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + - - - Qt::Horizontal - - - - 101 - 31 - - - + + + + + Always use this account + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + - - - Qt::Horizontal + + + Initializing your connection + + + + + + + + + + + + :/22x22/actions/network-disconnect + + + + + + + Connected to apollo.mindpool.net. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + Qt::Horizontal + + + + 358 + 21 + + + + + + + + Core Info + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 0 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Login + + + + 9 + + + + + User: + + + + + + + + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Remember + + + + + + + + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok - - - - - - - - - Connecting to... - - - - - - Connecting... - - - - - - - 0 - - - Qt::Horizontal - - - - - - - - - GUI Profile: - - - - - - - - 0 - 0 - - - - + + + + + + + Initializing your session... + + - - - - 0 - 0 - - - - New... - - + + + + + <b>Please be patient while your client synchronizes with the Quassel Core!</b> + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + + + + + Session state: + + + + + + + 1 + + + 0 + + + + + + + Network states: + + + + + + + 1 + + + 0 + + + 0/0 + + + + + + + Channel states: + + + + + + + 1 + + + 0 + + + 0/0 + + + + + + + User states: + + + + + + + 0 + + + 1 + + + 0 + + + 0/0 + + + + + + + + + Qt::Vertical + + + + 483 + 61 + + + + + - - - - - Always use this profile - - - - - - - - - - Qt::Vertical - - - - 20 - 31 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + - + - QDialogButtonBox::Abort|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + QDialogButtonBox::Abort + + + true - - - - + + + + + + accountButtonBox + accountList + editAccount + addAccount + deleteAccount + autoConnect + loginButtonBox + user + password + rememberPasswd + syncButtonBox + - - buttonBox1 + accountButtonBox rejected() CoreConnectDlg reject() - 507 - 273 + 279 + 434 - 297 - 151 + 286 + 237 diff --git a/src/qtui/ui/serverlistdlg.ui b/src/qtui/ui/serverlistdlg.ui index 8c892e80..dbc3b465 100644 --- a/src/qtui/ui/serverlistdlg.ui +++ b/src/qtui/ui/serverlistdlg.ui @@ -5,15 +5,15 @@ 0 0 - 430 - 444 + 465 + 482 Server List - :/default/server.png + false @@ -22,20 +22,54 @@ false - - 8 - 6 + + 8 + + + 8 + + + 8 + + + 8 + - - - 0 + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:14pt; font-weight:600; color:#ff0000;">Big Fat Warning: </span><span style=" font-size:14pt; color:#000000;">The settings in here now need a Core restart in order to take effect! This dialog is doomed and will go away as soon as its replacement is finished.</span></p></body></html> + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -50,23 +84,37 @@ false + + + 1 + + - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + &Add... - :/default/edit_add.png + @@ -79,7 +127,7 @@ &Edit... - :/default/edit.png + @@ -92,7 +140,7 @@ &Delete - :/default/edit_remove.png + @@ -115,12 +163,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -150,7 +207,7 @@ &Connect - :/default/connect_creating.png + false @@ -163,7 +220,7 @@ C&lose - :/default/button_cancel.png + true diff --git a/version.inc b/version.inc new file mode 100644 index 00000000..653864ef --- /dev/null +++ b/version.inc @@ -0,0 +1,18 @@ +// Versioning, should be kept current :) +// This is included in main.cpp + +{ using namespace Global; + + quasselVersion = "0.2.0-pre"; + quasselDate = "2008-01-12"; + quasselBuild = 344; + + //! Minimum client build number the core needs + clientBuildNeeded = 344; + clientVersionNeeded = quasselVersion; + + //! Minimum core build number the client needs + coreBuildNeeded = 344; + coreVersionNeeded = quasselVersion; + +}