~ubuntu-branches/ubuntu/vivid/quassel/vivid-updates

« back to all changes in this revision

Viewing changes to src/core/core.cpp

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-02-18 23:18:25 UTC
  • mfrom: (1.1.54)
  • Revision ID: package-import@ubuntu.com-20140218231825-6vvoh451otn95pkn
Tags: 0.10~beta1-0ubuntu1
* New upstream beta relase
  - Drop debian/patches/upstream_fix_fullscreen_mode.diff which had been
    cherrypicked from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/***************************************************************************
2
 
 *   Copyright (C) 2005-2013 by the Quassel Project                        *
 
2
 *   Copyright (C) 2005-2014 by the Quassel Project                        *
3
3
 *   devel@quassel-irc.org                                                 *
4
4
 *                                                                         *
5
5
 *   This program is free software; you can redistribute it and/or modify  *
21
21
#include <QCoreApplication>
22
22
 
23
23
#include "core.h"
 
24
#include "coreauthhandler.h"
24
25
#include "coresession.h"
25
26
#include "coresettings.h"
 
27
#include "logger.h"
26
28
#include "internalpeer.h"
 
29
#include "network.h"
27
30
#include "postgresqlstorage.h"
28
31
#include "quassel.h"
29
32
#include "sqlitestorage.h"
30
 
#include "network.h"
31
 
#include "logger.h"
32
 
 
33
33
#include "util.h"
34
34
 
35
 
#include "protocols/legacy/legacypeer.h"
36
 
 
37
35
// migration related
38
36
#include <QFile>
39
37
#ifdef Q_OS_WIN32
84
82
 
85
83
 
86
84
Core::Core()
87
 
    : _storage(0)
 
85
    : QObject(),
 
86
      _storage(0)
88
87
{
89
88
#ifdef HAVE_UMASK
90
89
    umask(S_IRWXG | S_IRWXO);
178
177
void Core::init()
179
178
{
180
179
    CoreSettings cs;
181
 
    _configured = initStorage(cs.storageSettings().toMap());
 
180
    // legacy
 
181
    QVariantMap dbsettings = cs.storageSettings().toMap();
 
182
    _configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap());
182
183
 
183
184
    if (Quassel::isOptionSet("select-backend")) {
184
185
        selectBackend(Quassel::optionValue("select-backend"));
217
218
 
218
219
Core::~Core()
219
220
{
220
 
    foreach(RemotePeer *peer, clientInfo.keys()) {
221
 
        peer->close(); // disconnect non authed clients
 
221
    // FIXME do we need more cleanup for handlers?
 
222
    foreach(CoreAuthHandler *handler, _connectingClients) {
 
223
        handler->deleteLater(); // disconnect non authed clients
222
224
    }
223
225
    qDeleteAll(sessions);
224
226
    qDeleteAll(_storageBackends);
270
272
 
271
273
 
272
274
/*** Core Setup ***/
 
275
 
 
276
QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
 
277
{
 
278
    return instance()->setupCore(adminUser, adminPassword, backend, setupData);
 
279
}
 
280
 
 
281
 
 
282
QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
 
283
{
 
284
    if (_configured)
 
285
        return tr("Core is already configured! Not configuring again...");
 
286
 
 
287
    if (adminUser.isEmpty() || adminPassword.isEmpty()) {
 
288
        return tr("Admin user or password not set.");
 
289
    }
 
290
    if (!(_configured = initStorage(backend, setupData, true))) {
 
291
        return tr("Could not setup storage!");
 
292
    }
 
293
 
 
294
    saveBackendSettings(backend, setupData);
 
295
 
 
296
    quInfo() << qPrintable(tr("Creating admin user..."));
 
297
    _storage->addUser(adminUser, adminPassword);
 
298
    startListening(); // TODO check when we need this
 
299
    return QString();
 
300
}
 
301
 
 
302
 
273
303
QString Core::setupCoreForInternalUsage()
274
304
{
275
305
    Q_ASSERT(!_storageBackends.isEmpty());
276
 
    QVariantMap setupData;
 
306
 
277
307
    qsrand(QDateTime::currentDateTime().toTime_t());
278
308
    int pass = 0;
279
309
    for (int i = 0; i < 10; i++) {
280
310
        pass *= 10;
281
311
        pass += qrand() % 10;
282
312
    }
283
 
    setupData["AdminUser"] = "AdminUser";
284
 
    setupData["AdminPasswd"] = QString::number(pass);
285
 
    setupData["Backend"] = QString("SQLite"); // mono client currently needs sqlite
286
 
    return setupCore(setupData);
287
 
}
288
 
 
289
 
 
290
 
QString Core::setupCore(QVariantMap setupData)
291
 
{
292
 
    QString user = setupData.take("AdminUser").toString();
293
 
    QString password = setupData.take("AdminPasswd").toString();
294
 
    if (user.isEmpty() || password.isEmpty()) {
295
 
        return tr("Admin user or password not set.");
296
 
    }
297
 
    if (_configured || !(_configured = initStorage(setupData, true))) {
298
 
        return tr("Could not setup storage!");
299
 
    }
300
 
    CoreSettings s;
301
 
    s.setStorageSettings(setupData);
302
 
    quInfo() << qPrintable(tr("Creating admin user..."));
303
 
    _storage->addUser(user, password);
304
 
    startListening(); // TODO check when we need this
305
 
    return QString();
 
313
 
 
314
    // mono client currently needs sqlite
 
315
    return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap());
306
316
}
307
317
 
308
318
 
346
356
 
347
357
// old db settings:
348
358
// "Type" => "sqlite"
349
 
bool Core::initStorage(const QString &backend, QVariantMap settings, bool setup)
 
359
bool Core::initStorage(const QString &backend, const QVariantMap &settings, bool setup)
350
360
{
351
361
    _storage = 0;
352
362
 
388
398
}
389
399
 
390
400
 
391
 
bool Core::initStorage(QVariantMap dbSettings, bool setup)
392
 
{
393
 
    return initStorage(dbSettings["Backend"].toString(), dbSettings["ConnectionProperties"].toMap(), setup);
394
 
}
395
 
 
396
 
 
397
401
void Core::syncStorage()
398
402
{
399
403
    if (_storage)
415
419
 
416
420
/*** Network Management ***/
417
421
 
 
422
bool Core::sslSupported()
 
423
{
 
424
#ifdef HAVE_SSL
 
425
    SslServer *sslServer = qobject_cast<SslServer *>(&instance()->_server);
 
426
    return sslServer && sslServer->isCertValid();
 
427
#else
 
428
    return false;
 
429
#endif
 
430
}
 
431
 
 
432
 
418
433
bool Core::startListening()
419
434
{
420
435
    // in mono mode we only start a local port if a port is specified in the cli call
517
532
    Q_ASSERT(server);
518
533
    while (server->hasPendingConnections()) {
519
534
        QTcpSocket *socket = server->nextPendingConnection();
520
 
        RemotePeer *peer = new LegacyPeer(socket, this);
521
 
 
522
 
        connect(peer, SIGNAL(disconnected()), SLOT(clientDisconnected()));
523
 
        connect(peer, SIGNAL(dataReceived(QVariant)), SLOT(processClientMessage(QVariant)));
524
 
        connect(peer, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
525
 
 
526
 
        clientInfo.insert(peer, QVariantMap());
 
535
 
 
536
        CoreAuthHandler *handler = new CoreAuthHandler(socket, this);
 
537
        _connectingClients.insert(handler);
 
538
 
 
539
        connect(handler, SIGNAL(disconnected()), SLOT(clientDisconnected()));
 
540
        connect(handler, SIGNAL(socketError(QAbstractSocket::SocketError,QString)), SLOT(socketError(QAbstractSocket::SocketError,QString)));
 
541
        connect(handler, SIGNAL(handshakeComplete(RemotePeer*,UserId)), SLOT(setupClientSession(RemotePeer*,UserId)));
 
542
 
527
543
        quInfo() << qPrintable(tr("Client connected from"))  << qPrintable(socket->peerAddress().toString());
528
544
 
529
545
        if (!_configured) {
533
549
}
534
550
 
535
551
 
536
 
void Core::processClientMessage(const QVariant &data)
537
 
{
538
 
    RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
539
 
    if (!peer) {
540
 
        qWarning() << Q_FUNC_INFO << "Message not sent by RemoteConnection!";
541
 
        return;
542
 
    }
543
 
 
544
 
    QVariantMap msg = data.toMap();
545
 
    if (!msg.contains("MsgType")) {
546
 
        // Client is way too old, does not even use the current init format
547
 
        qWarning() << qPrintable(tr("Antique client trying to connect... refusing."));
548
 
        peer->close();
549
 
        return;
550
 
    }
551
 
 
552
 
    // OK, so we have at least an init message format we can understand
553
 
    if (msg["MsgType"] == "ClientInit") {
554
 
        QVariantMap reply;
555
 
 
556
 
        // Just version information -- check it!
557
 
        uint ver = msg["ProtocolVersion"].toUInt();
558
 
        if (ver < Quassel::buildInfo().coreNeedsProtocol) {
559
 
            reply["MsgType"] = "ClientInitReject";
560
 
            reply["Error"] = tr("<b>Your Quassel Client is too old!</b><br>"
561
 
                                "This core needs at least client/core protocol version %1.<br>"
562
 
                                "Please consider upgrading your client.").arg(Quassel::buildInfo().coreNeedsProtocol);
563
 
            peer->writeSocketData(reply);
564
 
            qWarning() << qPrintable(tr("Client")) << peer->description() << qPrintable(tr("too old, rejecting."));
565
 
            peer->close();
566
 
            return;
567
 
        }
568
 
 
569
 
        reply["ProtocolVersion"] = Quassel::buildInfo().protocolVersion;
570
 
        reply["CoreVersion"] = Quassel::buildInfo().fancyVersionString;
571
 
        reply["CoreDate"] = Quassel::buildInfo().buildDate;
572
 
        reply["CoreStartTime"] = startTime(); // v10 clients don't necessarily parse this, see below
573
 
 
574
 
        // FIXME: newer clients no longer use the hardcoded CoreInfo (for now), since it gets the
575
 
        //        time zone wrong. With the next protocol bump (10 -> 11), we should remove this
576
 
        //        or make it properly configurable.
577
 
 
578
 
        int uptime = startTime().secsTo(QDateTime::currentDateTime().toUTC());
579
 
        int updays = uptime / 86400; uptime %= 86400;
580
 
        int uphours = uptime / 3600; uptime %= 3600;
581
 
        int upmins = uptime / 60;
582
 
        reply["CoreInfo"] = tr("<b>Quassel Core Version %1</b><br>"
583
 
                               "Built: %2<br>"
584
 
                               "Up %3d%4h%5m (since %6)").arg(Quassel::buildInfo().fancyVersionString)
585
 
                            .arg(Quassel::buildInfo().buildDate)
586
 
                            .arg(updays).arg(uphours, 2, 10, QChar('0')).arg(upmins, 2, 10, QChar('0')).arg(startTime().toString(Qt::TextDate));
587
 
 
588
 
        reply["CoreFeatures"] = (int)Quassel::features();
589
 
 
590
 
#ifdef HAVE_SSL
591
 
        SslServer *sslServer = qobject_cast<SslServer *>(&_server);
592
 
        QSslSocket *sslSocket = qobject_cast<QSslSocket *>(peer->socket());
593
 
        bool supportSsl = sslServer && sslSocket && sslServer->isCertValid();
594
 
#else
595
 
        bool supportSsl = false;
596
 
#endif
597
 
 
598
 
#ifndef QT_NO_COMPRESS
599
 
        bool supportsCompression = true;
600
 
#else
601
 
        bool supportsCompression = false;
602
 
#endif
603
 
 
604
 
        reply["SupportSsl"] = supportSsl;
605
 
        reply["SupportsCompression"] = supportsCompression;
606
 
        // switch to ssl/compression after client has been informed about our capabilities (see below)
607
 
 
608
 
        reply["LoginEnabled"] = true;
609
 
 
610
 
        // check if we are configured, start wizard otherwise
611
 
        if (!_configured) {
612
 
            reply["Configured"] = false;
613
 
            QList<QVariant> backends;
614
 
            foreach(Storage *backend, _storageBackends.values()) {
615
 
                QVariantMap v;
616
 
                v["DisplayName"] = backend->displayName();
617
 
                v["Description"] = backend->description();
618
 
                v["SetupKeys"] = backend->setupKeys();
619
 
                v["SetupDefaults"] = backend->setupDefaults();
620
 
                backends.append(v);
621
 
            }
622
 
            reply["StorageBackends"] = backends;
623
 
            reply["LoginEnabled"] = false;
624
 
        }
625
 
        else {
626
 
            reply["Configured"] = true;
627
 
        }
628
 
        clientInfo[peer] = msg; // store for future reference
629
 
        reply["MsgType"] = "ClientInitAck";
630
 
        peer->writeSocketData(reply);
631
 
        peer->socket()->flush(); // ensure that the write cache is flushed before we switch to ssl
632
 
 
633
 
#ifdef HAVE_SSL
634
 
        // after we told the client that we are ssl capable we switch to ssl mode
635
 
        if (supportSsl && msg["UseSsl"].toBool()) {
636
 
            qDebug() << qPrintable(tr("Starting TLS for Client:"))  << peer->description();
637
 
            connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(sslErrors(const QList<QSslError> &)));
638
 
            sslSocket->startServerEncryption();
639
 
        }
640
 
#endif
641
 
 
642
 
#ifndef QT_NO_COMPRESS
643
 
        if (supportsCompression && msg["UseCompression"].toBool()) {
644
 
            peer->socket()->setProperty("UseCompression", true);
645
 
            qDebug() << "Using compression for Client:" << qPrintable(peer->socket()->peerAddress().toString());
646
 
        }
647
 
#endif
648
 
    }
649
 
    else {
650
 
        // for the rest, we need an initialized connection
651
 
        if (!clientInfo.contains(peer)) {
652
 
            QVariantMap reply;
653
 
            reply["MsgType"] = "ClientLoginReject";
654
 
            reply["Error"] = tr("<b>Client not initialized!</b><br>You need to send an init message before trying to login.");
655
 
            peer->writeSocketData(reply);
656
 
            qWarning() << qPrintable(tr("Client")) << qPrintable(peer->socket()->peerAddress().toString()) << qPrintable(tr("did not send an init message before trying to login, rejecting."));
657
 
            peer->close(); return;
658
 
        }
659
 
        if (msg["MsgType"] == "CoreSetupData") {
660
 
            QVariantMap reply;
661
 
            QString result = setupCore(msg["SetupData"].toMap());
662
 
            if (!result.isEmpty()) {
663
 
                reply["MsgType"] = "CoreSetupReject";
664
 
                reply["Error"] = result;
665
 
            }
666
 
            else {
667
 
                reply["MsgType"] = "CoreSetupAck";
668
 
            }
669
 
            peer->writeSocketData(reply);
670
 
        }
671
 
        else if (msg["MsgType"] == "ClientLogin") {
672
 
            QVariantMap reply;
673
 
            UserId uid = _storage->validateUser(msg["User"].toString(), msg["Password"].toString());
674
 
            if (uid == 0) {
675
 
                reply["MsgType"] = "ClientLoginReject";
676
 
                reply["Error"] = tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.");
677
 
                peer->writeSocketData(reply);
678
 
                return;
679
 
            }
680
 
            reply["MsgType"] = "ClientLoginAck";
681
 
            peer->writeSocketData(reply);
682
 
            quInfo() << qPrintable(tr("Client")) << qPrintable(peer->socket()->peerAddress().toString()) << qPrintable(tr("initialized and authenticated successfully as \"%1\" (UserId: %2).").arg(msg["User"].toString()).arg(uid.toInt()));
683
 
            setupClientSession(peer, uid);
684
 
        }
685
 
    }
686
 
}
687
 
 
688
 
 
689
552
// Potentially called during the initialization phase (before handing the connection off to the session)
690
553
void Core::clientDisconnected()
691
554
{
692
 
    RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
693
 
    Q_ASSERT(peer);
 
555
    CoreAuthHandler *handler = qobject_cast<CoreAuthHandler *>(sender());
 
556
    Q_ASSERT(handler);
694
557
 
695
 
    quInfo() << qPrintable(tr("Non-authed client disconnected.")) << qPrintable(peer->socket()->peerAddress().toString());
696
 
    clientInfo.remove(peer);
697
 
    peer->deleteLater();
 
558
    quInfo() << qPrintable(tr("Non-authed client disconnected:")) << qPrintable(handler->socket()->peerAddress().toString());
 
559
    _connectingClients.remove(handler);
 
560
    handler->deleteLater();
698
561
 
699
562
    // make server listen again if still not configured
700
563
    if (!_configured) {
708
571
 
709
572
void Core::setupClientSession(RemotePeer *peer, UserId uid)
710
573
{
 
574
    CoreAuthHandler *handler = qobject_cast<CoreAuthHandler *>(sender());
 
575
    Q_ASSERT(handler);
 
576
 
711
577
    // From now on everything is handled by the client session
712
 
    disconnect(peer, 0, this, 0);
713
 
    peer->socket()->flush();
714
 
    clientInfo.remove(peer);
 
578
    disconnect(handler, 0, this, 0);
 
579
    _connectingClients.remove(handler);
 
580
    handler->deleteLater();
715
581
 
716
582
    // Find or create session for validated user
717
583
    SessionThread *session;
721
587
    else {
722
588
        session = createSession(uid);
723
589
        if (!session) {
724
 
            qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(peer->socket()->peerAddress().toString());
 
590
            qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(peer->description());
725
591
            peer->close();
 
592
            peer->deleteLater();
726
593
            return;
727
594
        }
728
595
    }
747
614
{
748
615
    // Find or create session for validated user
749
616
    if (!sessions.contains(uid)) {
750
 
        qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(peer->socket()->peerAddress().toString());
 
617
        qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(peer->description());
751
618
        peer->close();
 
619
        peer->deleteLater();
752
620
        return;
753
621
    }
754
622
 
801
669
}
802
670
 
803
671
 
804
 
#ifdef HAVE_SSL
805
 
void Core::sslErrors(const QList<QSslError> &errors)
 
672
void Core::socketError(QAbstractSocket::SocketError err, const QString &errorString)
806
673
{
807
 
    Q_UNUSED(errors);
808
 
    QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
809
 
    if (socket)
810
 
        socket->ignoreSslErrors();
 
674
    qWarning() << QString("Socket error %1: %2").arg(err).arg(errorString);
811
675
}
812
676
 
813
677
 
814
 
#endif
815
 
 
816
 
void Core::socketError(QAbstractSocket::SocketError err)
 
678
QVariantList Core::backendInfo()
817
679
{
818
 
    RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
819
 
    if (peer && err != QAbstractSocket::RemoteHostClosedError)
820
 
        qWarning() << "Core::socketError()" << peer->socket() << err << peer->socket()->errorString();
 
680
    QVariantList backends;
 
681
    foreach(const Storage *backend, instance()->_storageBackends.values()) {
 
682
        QVariantMap v;
 
683
        v["DisplayName"] = backend->displayName();
 
684
        v["Description"] = backend->description();
 
685
        v["SetupKeys"] = backend->setupKeys();
 
686
        v["SetupDefaults"] = backend->setupDefaults();
 
687
        backends.append(v);
 
688
    }
 
689
    return backends;
821
690
}
822
691
 
823
692