X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fclient%2Fclientsyncer.cpp;h=b8608891a83d14237b7ece7f1de61bd5f5399e7f;hb=e03a43888d6264f94d974a6ffbe9187fd795f20e;hp=4ec529c012858f8c9af66837a1397ac2db643fec;hpb=a33e42aee121185f479667b2104a15fc2033762e;p=quassel.git diff --git a/src/client/clientsyncer.cpp b/src/client/clientsyncer.cpp index 4ec529c0..b8608891 100644 --- a/src/client/clientsyncer.cpp +++ b/src/client/clientsyncer.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel IRC Team * + * Copyright (C) 2005-09 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -25,20 +25,18 @@ #endif #include "client.h" -#include "global.h" #include "identity.h" -#include "ircuser.h" -#include "ircchannel.h" #include "network.h" +#include "networkmodel.h" +#include "quassel.h" #include "signalproxy.h" - +#include "util.h" ClientSyncer::ClientSyncer(QObject *parent) - : QObject(parent) + : QObject(parent), + _socket(0), + _blockSize(0) { - socket = 0; - blockSize = 0; - connect(Client::signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); } @@ -47,7 +45,7 @@ ClientSyncer::~ClientSyncer() { void ClientSyncer::coreHasData() { QVariant item; - while(SignalProxy::readDataFromDevice(socket, blockSize, item)) { + while(SignalProxy::readDataFromDevice(_socket, _blockSize, item)) { emit recvPartialItem(1,1); QVariantMap msg = item.toMap(); if(!msg.contains("MsgType")) { @@ -82,19 +80,19 @@ void ClientSyncer::coreHasData() { return; } } - if(blockSize > 0) { - emit recvPartialItem(socket->bytesAvailable(), blockSize); + if(_blockSize > 0) { + emit recvPartialItem(_socket->bytesAvailable(), _blockSize); } } void ClientSyncer::coreSocketError(QAbstractSocket::SocketError) { - qDebug() << "coreSocketError" << socket << socket->errorString(); - emit connectionError(socket->errorString()); - socket->deleteLater(); + qDebug() << "coreSocketError" << _socket << _socket->errorString(); + emit connectionError(_socket->errorString()); + _socket->deleteLater(); } void ClientSyncer::disconnectFromCore() { - if(socket) socket->close(); + if(_socket) _socket->close(); } void ClientSyncer::connectToCore(const QVariantMap &conn) { @@ -104,31 +102,31 @@ void ClientSyncer::connectToCore(const QVariantMap &conn) { // emit coreConnectionError(tr("Already connected to Core!")); // return; // } - if(socket != 0) { - socket->deleteLater(); - socket = 0; + 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); + _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); + Q_ASSERT(!_socket); -#ifndef QT_NO_OPENSSL +#ifdef HAVE_SSL QSslSocket *sock = new QSslSocket(Client::instance()); + connect(sock, SIGNAL(encrypted()), this, SIGNAL(encrypted())); #else if(conn["useSsl"].toBool()) { emit connectionError(tr("This client is built without SSL Support!
Disable the usage of SSL in the account settings.")); - emit encrypted(false); return; } QTcpSocket *sock = new QTcpSocket(Client::instance()); @@ -139,7 +137,7 @@ void ClientSyncer::connectToCore(const QVariantMap &conn) { sock->setProxy(proxy); } #endif - socket = sock; + _socket = sock; connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData())); connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected())); connect(sock, SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); @@ -156,10 +154,9 @@ void ClientSyncer::coreSocketConnected() { //emit coreConnectionMsg(tr("Synchronizing to core...")); QVariantMap clientInit; clientInit["MsgType"] = "ClientInit"; - clientInit["ClientVersion"] = Global::quasselVersion; - clientInit["ClientBuild"] = 860; // FIXME legacy! - clientInit["ClientDate"] = Global::quasselBuildDate; - clientInit["ProtocolVersion"] = Global::protocolVersion; + clientInit["ClientVersion"] = Quassel::buildInfo().fancyVersionString; + clientInit["ClientDate"] = Quassel::buildInfo().buildDate; + clientInit["ProtocolVersion"] = Quassel::buildInfo().protocolVersion; clientInit["UseSsl"] = coreConnectionInfo["useSsl"]; #ifndef QT_NO_COMPRESS clientInit["UseCompression"] = true; @@ -167,7 +164,39 @@ void ClientSyncer::coreSocketConnected() { clientInit["UseCompression"] = false; #endif - SignalProxy::writeDataToDevice(socket, clientInit); + SignalProxy::writeDataToDevice(_socket, clientInit); +} + +void ClientSyncer::useInternalCore() { + AccountId internalAccountId; + + CoreAccountSettings accountSettings; + QList knownAccounts = accountSettings.knownAccounts(); + foreach(AccountId id, knownAccounts) { + if(!id.isValid()) + continue; + QVariantMap data = accountSettings.retrieveAccountData(id); + if(data.contains("InternalAccount") && data["InternalAccount"].toBool()) { + internalAccountId = id; + break; + } + } + + if(!internalAccountId.isValid()) { + for(AccountId i = 1;; i++) { + if(!knownAccounts.contains(i)) { + internalAccountId = i; + break; + } + } + QVariantMap data; + data["InternalAccount"] = true; + accountSettings.storeAccountData(internalAccountId, data); + } + + coreConnectionInfo["AccountId"] = QVariant::fromValue(internalAccountId); + emit startInternalCore(this); + emit connectToInternalCore(Client::instance()->signalProxy()); } void ClientSyncer::coreSocketDisconnected() { @@ -178,60 +207,64 @@ void ClientSyncer::coreSocketDisconnected() { coreConnectionInfo.clear(); netsToSync.clear(); - blockSize = 0; + _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... - uint ver = 0; - if(!msg.contains("ProtocolVersion") && msg["CoreBuild"].toUInt() >= 732) ver = 1; // legacy! - if(msg.contains("ProtocolVersion")) ver = msg["ProtocolVersion"].toUInt(); - if(ver < Global::clientNeedsProtocol) { + uint ver = msg["ProtocolVersion"].toUInt(); + if(ver < Quassel::buildInfo().clientNeedsProtocol) { emit connectionError(tr("The Quassel Core you are trying to connect to is too old!
" - "Need at least core/client protocol v%1 to connect.").arg(Global::clientNeedsProtocol)); + "Need at least core/client protocol v%1 to connect.").arg(Quassel::buildInfo().clientNeedsProtocol)); disconnectFromCore(); return; } emit connectionMsg(msg["CoreInfo"].toString()); -#ifndef QT_NO_OPENSSL +#ifndef QT_NO_COMPRESS + if(msg["SupportsCompression"].toBool()) { + _socket->setProperty("UseCompression", true); + } +#endif + + _coreMsgBuffer = msg; +#ifdef HAVE_SSL if(coreConnectionInfo["useSsl"].toBool()) { if(msg["SupportSsl"].toBool()) { - QSslSocket *sslSocket = qobject_cast(socket); + QSslSocket *sslSocket = qobject_cast(_socket); Q_ASSERT(sslSocket); + connect(sslSocket, SIGNAL(encrypted()), this, SLOT(sslSocketEncrypted())); connect(sslSocket, SIGNAL(sslErrors(const QList &)), this, SLOT(sslErrors(const QList &))); + sslSocket->startClientEncryption(); - emit encrypted(true); - Client::instance()->setSecuredConnection(); } else { emit connectionError(tr("The Quassel Core you are trying to connect to does not support SSL!
If you want to connect anyways, disable the usage of SSL in the account settings.")); - emit encrypted(false); disconnectFromCore(); - return; } + return; } #endif + // if we use SSL we wait for the next step until every SSL warning has been cleared + connectionReady(); +} -#ifndef QT_NO_COMPRESS - if(msg["SupportsCompression"].toBool()) { - socket->setProperty("UseCompression", true); - } -#endif - - if(!msg["Configured"].toBool()) { +void ClientSyncer::connectionReady() { + if(!_coreMsgBuffer["Configured"].toBool()) { // start wizard - emit startCoreSetup(msg["StorageBackends"].toList()); - } else if(msg["LoginEnabled"].toBool()) { + emit startCoreSetup(_coreMsgBuffer["StorageBackends"].toList()); + } else if(_coreMsgBuffer["LoginEnabled"].toBool()) { emit startLogin(); } + _coreMsgBuffer.clear(); + resetWarningsHandler(); } void ClientSyncer::doCoreSetup(const QVariant &setupData) { QVariantMap setup; setup["MsgType"] = "CoreSetupData"; setup["SetupData"] = setupData; - SignalProxy::writeDataToDevice(socket, setup); + SignalProxy::writeDataToDevice(_socket, setup); } void ClientSyncer::loginToCore(const QString &user, const QString &passwd) { @@ -240,20 +273,25 @@ void ClientSyncer::loginToCore(const QString &user, const QString &passwd) { clientLogin["MsgType"] = "ClientLogin"; clientLogin["User"] = user; clientLogin["Password"] = passwd; - SignalProxy::writeDataToDevice(socket, clientLogin); + SignalProxy::writeDataToDevice(_socket, clientLogin); +} + +void ClientSyncer::internalSessionStateReceived(const QVariant &packedState) { + QVariantMap state = packedState.toMap(); + emit sessionProgress(1, 1); + Client::instance()->setConnectedToCore(coreConnectionInfo["AccountId"].value()); + syncToCore(state); } 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, coreConnectionInfo["AccountId"].value()); + disconnect(_socket, 0, this, 0); // rest of communication happens through SignalProxy + Client::instance()->setConnectedToCore(coreConnectionInfo["AccountId"].value(), _socket); syncToCore(state); } void ClientSyncer::syncToCore(const QVariantMap &sessionState) { - // create identities foreach(QVariant vid, sessionState["Identities"].toList()) { Client::instance()->coreIdentityCreated(vid.value()); @@ -262,8 +300,10 @@ void ClientSyncer::syncToCore(const QVariantMap &sessionState) { // create buffers // FIXME: get rid of this crap QVariantList bufferinfos = sessionState["BufferInfos"].toList(); + NetworkModel *networkModel = Client::networkModel(); + Q_ASSERT(networkModel); foreach(QVariant vinfo, bufferinfos) - Client::buffer(vinfo.value()); // create Buffers and BufferItems + networkModel->bufferUpdated(vinfo.value()); // create BufferItems QVariantList networkids = sessionState["NetworkIds"].toList(); @@ -275,6 +315,8 @@ void ClientSyncer::syncToCore(const QVariantMap &sessionState) { // create network objects foreach(QVariant networkid, networkids) { NetworkId netid = networkid.value(); + if(Client::network(netid)) + continue; Network *net = new Network(netid, Client::instance()); netsToSync.insert(net); connect(net, SIGNAL(initDone()), this, SLOT(networkInitDone())); @@ -296,14 +338,64 @@ void ClientSyncer::checkSyncState() { } } -#ifndef QT_NO_OPENSSL -void ClientSyncer::sslErrors(const QList &errors) { - qDebug() << "SSL Errors:"; - foreach(QSslError err, errors) - qDebug() << " " << err; +void ClientSyncer::setWarningsHandler(const char *slot) { + resetWarningsHandler(); + connect(this, SIGNAL(handleIgnoreWarnings(bool)), this, slot); +} + +void ClientSyncer::resetWarningsHandler() { + disconnect(this, SIGNAL(handleIgnoreWarnings(bool)), this, 0); +} + +void ClientSyncer::resetConnection() { +} + +#ifdef HAVE_SSL +void ClientSyncer::ignoreSslWarnings(bool permanently) { + QSslSocket *sock = qobject_cast(_socket); + if(sock) { + // ensure that a proper state is displayed and no longer a warning + emit socketStateChanged(sock->state()); + } + if(permanently) { + if(!sock) + qWarning() << Q_FUNC_INFO << "unable to save cert digest! Socket is either a nullptr or not a QSslSocket"; + else + KnownHostsSettings().saveKnownHost(sock); + } + emit connectionMsg(_coreMsgBuffer["CoreInfo"].toString()); + connectionReady(); +} + +void ClientSyncer::sslSocketEncrypted() { + QSslSocket *socket = qobject_cast(sender()); + if(socket) { + QByteArray digest = socket->peerCertificate().digest(); + } +} +void ClientSyncer::sslErrors(const QList &errors) { + QByteArray knownDigest; QSslSocket *socket = qobject_cast(sender()); - if(socket) + if(socket) { socket->ignoreSslErrors(); + knownDigest = KnownHostsSettings().knownDigest(socket); + if(knownDigest == socket->peerCertificate().digest()) { + connectionReady(); + return; + } + } + + QStringList warnings; + + foreach(QSslError err, errors) + warnings << err.errorString(); + + if(!knownDigest.isEmpty()) { + warnings << tr("Cert Digest changed! was: %1").arg(QString(prettyDigest(knownDigest))); + } + + setWarningsHandler(SLOT(ignoreSslWarnings(bool))); + emit connectionWarnings(warnings); } #endif