common: Remove the copy assignment operator from DccConfig master
authorManuel Nickschas <sputnick@quassel-irc.org>
Fri, 30 Aug 2019 19:54:47 +0000 (21:54 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Fri, 30 Aug 2019 22:34:29 +0000 (00:34 +0200)
Since C++11 the standard no longer mandates the existence of an
implicit copy constructor if there is a user-supplied copy assignment
operator, and GCC 9 warns about that:

src/qtui/settingspages/dccsettingspage.cpp: In member function ‘virtual void DccSettingsPage::load()’:
src/qtui/settingspages/dccsettingspage.cpp:91:71: warning: implicitly-declared ‘DccConfig::DccConfig(const DccConfig&)’ is deprecated [-Wdeprecated-copy]

Remove the copy assignment operator altogether and rely on the
implicitly generated one, which does the same thing.

68 files changed:
CMakeLists.txt
cmake/QuasselCompileSettings.cmake
cmake/QuasselMacros.cmake
po/CMakeLists.txt
src/client/buffermodel.cpp
src/client/clientbacklogmanager.cpp
src/client/messagefilter.cpp
src/client/messagemodel.cpp
src/client/networkmodel.cpp
src/client/treemodel.cpp
src/common/dccconfig.cpp
src/common/dccconfig.h
src/common/ignorelistmanager.cpp
src/common/quassel.cpp
src/common/util.cpp
src/core/CMakeLists.txt
src/core/abstractsqlstorage.cpp
src/core/abstractsqlstorage.h
src/core/core.cpp
src/core/core.h
src/core/coreauthhandler.cpp
src/core/coreauthhandler.h
src/core/corebacklogmanager.cpp
src/core/corebuffersyncer.cpp
src/core/coreidentity.cpp
src/core/coreidentity.h
src/core/corenetwork.cpp
src/core/corenetwork.h
src/core/coresession.cpp
src/core/coresession.h
src/core/coresessioneventprocessor.cpp
src/core/metricsserver.cpp [new file with mode: 0644]
src/core/metricsserver.h [moved from src/qtui/debugconsole.h with 50% similarity]
src/core/oidentdconfiggenerator.cpp
src/core/postgresqlstorage.cpp
src/core/postgresqlstorage.h
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/sslserver.cpp
src/core/sslserver.h
src/core/storage.h
src/main/monoapplication.cpp
src/qtui/CMakeLists.txt
src/qtui/chatitem.cpp
src/qtui/chatline.cpp
src/qtui/chatline.h
src/qtui/chatlinemodelitem.cpp
src/qtui/chatview.cpp
src/qtui/chatviewsearchcontroller.cpp
src/qtui/debugconsole.ui [deleted file]
src/qtui/knotificationbackend.cpp
src/qtui/mainwin.cpp
src/qtui/nicklistwidget.cpp
src/qtui/qtuiapplication.cpp
src/qtui/settingspages/appearancesettingspage.cpp
src/qtui/settingspages/bufferviewsettingspage.cpp
src/qtui/settingspages/corehighlightsettingspage.cpp
src/qtui/settingspages/highlightsettingspage.cpp
src/qtui/settingspages/itemviewsettingspage.cpp
src/qtui/settingspages/itemviewsettingspage.h
src/uisupport/abstractbuffercontainer.cpp
src/uisupport/bufferview.cpp
src/uisupport/nickviewfilter.cpp
src/uisupport/styledlabel.cpp
src/uisupport/uistyle.cpp
src/uisupport/uistyle.h
tests/common/CMakeLists.txt
tests/common/utiltest.cpp [moved from src/qtui/debugconsole.cpp with 64% similarity]

index b42534f..cd9f79d 100644 (file)
@@ -108,6 +108,11 @@ endif()
 
 # The following options are not for end-user consumption, so don't list them in the feature summary
 option(FATAL_WARNINGS "Make compile warnings fatal (most useful for CI builds)" OFF)
+option(WARN_QT_DEPRECATION "Warn about deprecated Qt functionality" OFF)
+if (WARN_QT_DEPRECATION)
+    # Enable Qt deprecation warnings for Qt < 5.13 (on by default in newer versions)
+    add_definitions("-DQT_DEPRECATED_WARNINGS")
+endif()
 cmake_dependent_option(DEPLOY "Add required libs to bundle resources and create a dmg" OFF "APPLE" OFF)
 
 # List of authenticators and the cmake flags to build them
@@ -164,7 +169,7 @@ if (BUILD_GUI)
     list(APPEND qt_components Gui Widgets)
 endif()
 if (BUILD_CORE)
-    list(APPEND qt_components Script Sql)
+    list(APPEND qt_components Sql)
 endif()
 
 find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS ${qt_components})
@@ -207,19 +212,23 @@ if (BUILD_GUI)
         PURPOSE     "Required for audio notifications"
     )
 
-    find_package(LibsnoreQt5 0.7.0 QUIET)
-    set_package_properties(LibsnoreQt5 PROPERTIES TYPE OPTIONAL
-        URL "https://projects.kde.org/projects/playground/libs/snorenotify"
-        DESCRIPTION "a cross-platform notification framework"
-        PURPOSE     "Enable support for the snorenotify framework"
-    )
-    if (LibsnoreQt5_FOUND)
-        find_package(LibsnoreSettingsQt5 QUIET)
-        set_package_properties(LibsnoreSettingsQt5 PROPERTIES TYPE OPTIONAL
+    # snorenotify segfaults on startup on msys2
+    # we don't check for just MSYS to support the Ninja generator
+    if(NOT (WIN32 AND (NOT $ENV{MSYSTEM} STREQUAL "")))
+        find_package(LibsnoreQt5 0.7.0 QUIET)
+        set_package_properties(LibsnoreQt5 PROPERTIES TYPE OPTIONAL
             URL "https://projects.kde.org/projects/playground/libs/snorenotify"
             DESCRIPTION "a cross-platform notification framework"
             PURPOSE     "Enable support for the snorenotify framework"
         )
+        if (LibsnoreQt5_FOUND)
+            find_package(LibsnoreSettingsQt5 QUIET)
+            set_package_properties(LibsnoreSettingsQt5 PROPERTIES TYPE OPTIONAL
+                URL "https://projects.kde.org/projects/playground/libs/snorenotify"
+                DESCRIPTION "a cross-platform notification framework"
+                PURPOSE     "Enable support for the snorenotify framework"
+            )
+        endif()
     endif()
 
     if (WITH_WEBENGINE)
index 9de75dc..eb38958 100644 (file)
@@ -34,7 +34,6 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
         -fdiagnostics-color=always
         -fexceptions
         -fno-common
-        -fstack-protector-strong
         -Wall
         -Wextra
         -Wcast-align
@@ -50,6 +49,11 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
         "$<$<NOT:$<CONFIG:Debug>>:-U_FORTIFY_SOURCE;-D_FORTIFY_SOURCE=2>"
     )
 
+    # ssp is currently very broken on MinGW
+    if(NOT MINGW)
+        add_compile_options(-fstack-protector-strong)
+    endif()
+
     # Check for and set linker flags
     check_and_set_linker_flag("-Wl,-z,relro"            RELRO            LINKER_FLAGS)
     check_and_set_linker_flag("-Wl,-z,now"              NOW              LINKER_FLAGS)
index 6182f70..6ad562b 100644 (file)
@@ -20,9 +20,9 @@ include(QuasselCompileFeatures)
 #  - a library target named quassel_client with output name (lib)quassel-client(.so)
 #  - an alias target named Quassel::Client in global scope
 #
-# If the optional argument STATIC is given, a static library is built; otherwise, on
-# platforms other than Windows, a shared library is created. For shared libraries, also
-# an install rule is added.
+# If the optional argument STATIC is given, or the ENABLE_SHARED option is OFF,
+# a static library is built; otherwise a shared library is created. For shared
+# libraries, an install rule is also added.
 #
 # To generate an export header for the library, specify EXPORT. The header will be named
 # ${module}-export.h (where ${module} is the lower-case name of the module).
@@ -143,7 +143,7 @@ function(quassel_add_resource _name)
     #
     # On Windows, input redirection apparently doesn't work, however piping does. Use this for all platforms for
     # consistency, accommodating for the fact that the 'cat' equivalent on Windows is 'type'.
-    if (WIN32)
+    if (WIN32 AND NOT MSYS)
         set(cat_cmd type)
     else()
         set(cat_cmd cat)
index e7df627..8e5a45f 100644 (file)
@@ -51,14 +51,14 @@ if (TARGET Qt5::lconvert)
             COMMAND $<TARGET_FILE:Qt5::lupdate> -silent ${CMAKE_SOURCE_DIR}/src -ts ${tsfiles}
             COMMAND ${CMAKE_COMMAND} -E touch tsfiles.done
             DEPENDS ${tsfiles}
-            OUTPUT tsfiles.depends
+            OUTPUT tsfiles.done
         )
 
         # Generate the final translation files (.qm) for use by Qt
         add_custom_command(VERBATIM
             COMMENT "Compressing translations"
             COMMAND $<TARGET_FILE:Qt5::lrelease> -silent ${tsfiles}
-            DEPENDS tsfiles.depends
+            DEPENDS tsfiles.done
             OUTPUT ${qmfiles}
         )
 
index d4a94ea..0836b06 100644 (file)
@@ -138,7 +138,7 @@ void BufferModel::newBuffers(const QModelIndex& parent, int start, int end)
         return;
 
     for (int row = start; row <= end; row++) {
-        QModelIndex child = parent.child(row, 0);
+        QModelIndex child = parent.model()->index(row, 0, parent);
         newBuffer(child.data(NetworkModel::BufferIdRole).value<BufferId>());
     }
 }
index cf6ab5d..b969251 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "clientbacklogmanager.h"
 
+#include <algorithm>
 #include <ctime>
 
 #include <QDebug>
@@ -164,7 +165,7 @@ void ClientBacklogManager::dispatchMessages(const MessageList& messages, bool so
 
     clock_t start_t = clock();
     if (sort)
-        qSort(msgs);
+        std::sort(msgs.begin(), msgs.end());
     Client::messageProcessor()->process(msgs);
     clock_t end_t = clock();
 
index 10c9aa0..49676e3 100644 (file)
@@ -115,7 +115,7 @@ QString MessageFilter::idString() const
         return "*";
 
     QList<BufferId> bufferIds = _validBuffers.toList();
-    qSort(bufferIds);
+    std::sort(bufferIds.begin(), bufferIds.end());
 
     QStringList bufferIdStrings;
     foreach (BufferId id, bufferIds)
index e39c7a3..61c6bbd 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "messagemodel.h"
 
+#include <algorithm>
+
 #include <QEvent>
 
 #include "backlogsettings.h"
@@ -105,13 +107,13 @@ void MessageModel::insertMessages(const QList<Message>& msglist)
             else {
                 _messageBuffer = msglist.mid(processedMsgs);
             }
-            qSort(_messageBuffer);
+            std::sort(_messageBuffer.begin(), _messageBuffer.end());
             QCoreApplication::postEvent(this, new ProcessBufferEvent());
         }
     }
     else {
         _messageBuffer << msglist;
-        qSort(_messageBuffer);
+        std::sort(_messageBuffer.begin(), _messageBuffer.end());
     }
 }
 
index 17a9aaa..b398613 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "networkmodel.h"
 
+#include <algorithm>
 #include <utility>
 
 #include <QAbstractItemView>
@@ -1520,7 +1521,7 @@ void NetworkModel::checkForRemovedBuffers(const QModelIndex& parent, int start,
         return;
 
     for (int row = start; row <= end; row++) {
-        _bufferItemCache.remove(parent.child(row, 0).data(BufferIdRole).value<BufferId>());
+        _bufferItemCache.remove(index(row, 0, parent).data(BufferIdRole).value<BufferId>());
     }
 }
 
@@ -1530,7 +1531,7 @@ void NetworkModel::checkForNewBuffers(const QModelIndex& parent, int start, int
         return;
 
     for (int row = start; row <= end; row++) {
-        QModelIndex child = parent.child(row, 0);
+        QModelIndex child = parent.model()->index(row, 0, parent);
         _bufferItemCache[child.data(BufferIdRole).value<BufferId>()] = static_cast<BufferItem*>(child.internalPointer());
     }
 }
@@ -1605,7 +1606,7 @@ void NetworkModel::sortBufferIds(QList<BufferId>& bufferIds) const
             bufferItems << _bufferItemCache[bufferId];
     }
 
-    qSort(bufferItems.begin(), bufferItems.end(), bufferItemLessThan);
+    std::sort(bufferItems.begin(), bufferItems.end(), bufferItemLessThan);
 
     bufferIds.clear();
     foreach (BufferItem* bufferItem, bufferItems) {
index d1cc465..2819353 100644 (file)
@@ -571,7 +571,7 @@ void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex& parent, int start,
 
     QModelIndex child;
     for (int i = end; i >= start; i--) {
-        child = parent.child(i, 0);
+        child = parent.model()->index(i, 0, parent);
         Q_ASSERT(parentItem->child(i));
         qDebug() << ">>>" << i << child << child.data().toString();
     }
@@ -587,7 +587,7 @@ void TreeModel::debug_rowsInserted(const QModelIndex& parent, int start, int end
 
     QModelIndex child;
     for (int i = start; i <= end; i++) {
-        child = parent.child(i, 0);
+        child = parent.model()->index(i, 0, parent);
         Q_ASSERT(parentItem->child(i));
         qDebug() << "<<<" << i << child << child.data().toString();
     }
index 800ae88..93f6e9f 100644 (file)
@@ -37,22 +37,6 @@ DccConfig::DccConfig(QObject* parent)
     setAllowClientUpdates(true);
 }
 
-DccConfig& DccConfig::operator=(const DccConfig& other)
-{
-    if (this == &other)
-        return *this;
-
-    SyncableObject::operator=(other);
-
-    static auto propCount = staticMetaObject.propertyCount();
-    for (int i = 0; i < propCount; ++i) {
-        auto propName = staticMetaObject.property(i).name();
-        setProperty(propName, other.property(propName));
-    }
-
-    return *this;
-}
-
 bool DccConfig::operator==(const DccConfig& other)
 {
     // NOTE: We don't compare the SyncableObject attributes (isInitialized, clientUpdatesAllowed())
index 565ddf8..67fd9ef 100644 (file)
@@ -88,16 +88,6 @@ public:
      */
     DccConfig(QObject* parent = nullptr);
 
-    /**
-     * Assignment operator.
-     *
-     * @note Only assigns properties relevant for config management!
-     *
-     * @param[in] other Right-hand side instance
-     * @returns The updated instance
-     */
-    DccConfig& operator=(const DccConfig& other);
-
     /**
      * Equality operator.
      *
index 077189d..24a26ec 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <QDebug>
 #include <QStringList>
-#include <QtCore>
 
 IgnoreListManager& IgnoreListManager::operator=(const IgnoreListManager& other)
 {
index 09d8037..94c5ba2 100644 (file)
@@ -336,6 +336,7 @@ void Quassel::setupCliParser()
             {"icontheme", tr("Override the system icon theme ('breeze' is recommended)."), tr("theme")},
             {"qss", tr("Load a custom application stylesheet."), tr("file.qss")},
             {"hidewindow", tr("Start the client minimized to the system tray.")},
+            {"account", tr("Account id to connect to on startup."), tr("account"), "0"},
         };
     }
 
@@ -365,6 +366,9 @@ void Quassel::setupCliParser()
             {"require-ssl", tr("Require SSL for remote (non-loopback) client connections.")},
             {"ssl-cert", tr("Specify the path to the SSL certificate."), tr("path"), "configdir/quasselCert.pem"},
             {"ssl-key", tr("Specify the path to the SSL key."), tr("path"), "ssl-cert-path"},
+            {"metrics-daemon", tr("Enable metrics API.")},
+            {"metrics-port", tr("The port quasselcore will listen at for metrics requests. Only meaningful with --metrics-daemon."), tr("port"), "9558"},
+            {"metrics-listen", tr("The address(es) quasselcore will listen on for metrics requests. Same format as --listen."), tr("<address>[,...]"), "::1,127.0.0.1"}
 #endif
         };
     }
index aaf3aca..728b8ca 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <QCoreApplication>
 #include <QDateTime>
+#include <QTimeZone>
 #include <QDebug>
 #include <QTextCodec>
 #include <QVector>
@@ -357,32 +358,7 @@ QString formatDateTimeToOffsetISO(const QDateTime& dateTime)
     // See https://en.wikipedia.org/wiki/ISO_8601#cite_note-32
     // And https://www.ietf.org/rfc/rfc3339.txt
 
-#if 0
     // The expected way to get a UTC offset on ISO 8601 dates
     // Remove the "T" date/time separator
-    return dateTime.toTimeSpec(Qt::OffsetFromUTC).toString(Qt::ISODate).replace(10, 1, " ");
-#else
-    // Work around Qt bug that converts to UTC instead of including timezone information
-    // See https://bugreports.qt.io/browse/QTBUG-26161
-    //
-    // NOTE: Despite the bug report marking as fixed in Qt 5.2.0 (QT_VERSION >= 0x050200), this
-    // still appears broken in Qt 5.5.1.
-    //
-    // Credit to "user362638" for the solution below, modified to fit Quassel's needs
-    // https://stackoverflow.com/questions/18750569/qdatetime-isodate-with-timezone
-
-    // Get the local and UTC time
-    QDateTime local = QDateTime(dateTime);
-    QDateTime utc = local.toUTC();
-    utc.setTimeSpec(Qt::LocalTime);
-
-    // Find the UTC offset
-    int utcOffset = utc.secsTo(local);
-
-    // Force the local time to follow this offset
-    local.setUtcOffset(utcOffset);
-    // Now the output should be correct
-    // Remove the "T" date/time separator
-    return local.toString(Qt::ISODate).replace(10, 1, " ");
-#endif
+    return dateTime.toOffsetFromUtc(dateTime.offsetFromUtc()).toString(Qt::ISODate).replace(10, 1, " ");
 }
index a4cc809..017bccf 100644 (file)
@@ -32,6 +32,7 @@ target_sources(${TARGET} PRIVATE
     eventstringifier.cpp
     identserver.cpp
     ircparser.cpp
+    metricsserver.cpp
     netsplit.cpp
     oidentdconfiggenerator.cpp
     postgresqlstorage.cpp
@@ -48,7 +49,6 @@ target_link_libraries(${TARGET}
     PUBLIC
         Qt5::Core
         Qt5::Network
-        Qt5::Script
         Qt5::Sql
         Quassel::Common
 )
index 0ae3ebe..d43f59e 100644 (file)
 
 #include "abstractsqlstorage.h"
 
+#include <QDir>
+#include <QFileInfo>
 #include <QMutexLocker>
 #include <QSqlDriver>
 #include <QSqlError>
 #include <QSqlField>
 #include <QSqlQuery>
+#include <QThread>
 
 #include "quassel.h"
 
@@ -180,13 +183,13 @@ QString AbstractSqlStorage::queryString(const QString& queryName, int version)
     return query.trimmed();
 }
 
-QList<AbstractSqlStorage::SqlQueryResource> AbstractSqlStorage::setupQueries()
+std::vector<AbstractSqlStorage::SqlQueryResource> AbstractSqlStorage::setupQueries()
 {
-    QList<SqlQueryResource> queries;
+    std::vector<SqlQueryResource> queries;
     // The current schema is stored in the root folder, including setup scripts.
     QDir dir = QDir(QString(":/SQL/%1/").arg(displayName()));
     foreach (QFileInfo fileInfo, dir.entryInfoList(QStringList() << "setup*", QDir::NoFilter, QDir::Name)) {
-        queries << SqlQueryResource(queryString(fileInfo.baseName()), fileInfo.baseName());
+        queries.emplace_back(queryString(fileInfo.baseName()), fileInfo.baseName());
     }
     return queries;
 }
@@ -218,13 +221,13 @@ bool AbstractSqlStorage::setup(const QVariantMap& settings, const QProcessEnviro
     return success;
 }
 
-QList<AbstractSqlStorage::SqlQueryResource> AbstractSqlStorage::upgradeQueries(int version)
+std::vector<AbstractSqlStorage::SqlQueryResource> AbstractSqlStorage::upgradeQueries(int version)
 {
-    QList<SqlQueryResource> queries;
+    std::vector<SqlQueryResource> queries;
     // Upgrade queries are stored in the 'version/##' subfolders.
     QDir dir = QDir(QString(":/SQL/%1/version/%2/").arg(displayName()).arg(version));
     foreach (QFileInfo fileInfo, dir.entryInfoList(QStringList() << "upgrade*", QDir::NoFilter, QDir::Name)) {
-        queries << SqlQueryResource(queryString(fileInfo.baseName(), version), fileInfo.baseName());
+        queries.emplace_back(queryString(fileInfo.baseName(), version), fileInfo.baseName());
     }
     return queries;
 }
@@ -384,7 +387,7 @@ bool AbstractSqlStorage::watchQuery(QSqlQuery& query)
             valueStrings << QString("%1=%2").arg(iter.key(), value);
         }
         qCritical() << "                bound Values:" << qPrintable(valueStrings.join(", "));
-        qCritical() << "                Error Number:" << query.lastError().number();
+        qCritical() << "                  Error Code:" << qPrintable(query.lastError().nativeErrorCode());
         qCritical() << "               Error Message:" << qPrintable(query.lastError().text());
         qCritical() << "              Driver Message:" << qPrintable(query.lastError().driverText());
         qCritical() << "                  DB Message:" << qPrintable(query.lastError().databaseText());
@@ -492,7 +495,7 @@ void AbstractSqlMigrator::dumpStatus()
     QList<QVariant> list = boundValues();
     for (int i = 0; i < list.size(); ++i)
         qWarning() << i << ": " << list.at(i).toString().toLatin1().data();
-    qWarning() << "  Error Number:" << lastError().number();
+    qWarning() << "  Error Code:" << qPrintable(lastError().nativeErrorCode());
     qWarning() << "  Error Message:" << lastError().text();
 }
 
index d3fb792..e43188a 100644 (file)
 #pragma once
 
 #include <memory>
+#include <vector>
 
-#include <QList>
+#include <QHash>
+#include <QMutex>
 #include <QSqlDatabase>
 #include <QSqlError>
 #include <QSqlQuery>
 
 #include "storage.h"
 
+class QThread;
+
 class AbstractSqlMigrationReader;
 class AbstractSqlMigrationWriter;
 
@@ -92,7 +96,7 @@ protected:
      *
      * @return List of SQL query strings and filenames
      */
-    QList<SqlQueryResource> setupQueries();
+    std::vector<SqlQueryResource> setupQueries();
 
     /**
      * Gets the collection of SQL upgrade queries and filenames for a given schema version
@@ -100,7 +104,7 @@ protected:
      * @param ver  SQL schema version
      * @return List of SQL query strings and filenames
      */
-    QList<SqlQueryResource> upgradeQueries(int ver);
+    std::vector<SqlQueryResource> upgradeQueries(int ver);
     bool upgradeDb();
 
     bool watchQuery(QSqlQuery& query);
index a4133eb..b0c02c1 100644 (file)
@@ -213,6 +213,14 @@ void Core::init()
             _identServer = new IdentServer(this);
         }
 
+        if (Quassel::isOptionSet("metrics-daemon")) {
+            _metricsServer = new MetricsServer(this);
+#ifdef HAVE_SSL
+            _server.setMetricsServer(_metricsServer);
+            _v6server.setMetricsServer(_metricsServer);
+#endif
+        }
+
         Quassel::registerReloadHandler([]() {
             // Currently, only reloading SSL certificates and the sysident cache is supported
             if (Core::instance()) {
@@ -674,6 +682,10 @@ bool Core::startListening()
         _identServer->startListening();
     }
 
+    if (_metricsServer) {
+        _metricsServer->startListening();
+    }
+
     return success;
 }
 
@@ -683,6 +695,10 @@ void Core::stopListening(const QString& reason)
         _identServer->stopListening(reason);
     }
 
+    if (_metricsServer) {
+        _metricsServer->stopListening(reason);
+    }
+
     bool wasListening = false;
     if (_server.isListening()) {
         wasListening = true;
index ef04b77..2df1947 100644 (file)
@@ -45,6 +45,7 @@
 #include "deferredptr.h"
 #include "identserver.h"
 #include "message.h"
+#include "metricsserver.h"
 #include "oidentdconfiggenerator.h"
 #include "sessionthread.h"
 #include "singleton.h"
@@ -193,7 +194,7 @@ public:
 
     static void removeIdentity(UserId user, IdentityId identityId) { instance()->_storage->removeIdentity(user, identityId); }
 
-    static QList<CoreIdentity> identities(UserId user) { return instance()->_storage->identities(user); }
+    static std::vector<CoreIdentity> identities(UserId user) { return instance()->_storage->identities(user); }
 
     //! Create a Network in the Storage and store it's Id in the given NetworkInfo
     /** \note This method is thredsafe.
@@ -229,9 +230,9 @@ public:
     /** \note This method is thredsafe.
      *
      *  \param user        The core user
-     *  \return QList<NetworkInfo>.
+     *  \return std::vector<NetworkInfo>.
      */
-    static inline QList<NetworkInfo> networks(UserId user) { return instance()->_storage->networks(user); }
+    static inline std::vector<NetworkInfo> networks(UserId user) { return instance()->_storage->networks(user); }
 
     //! Get a list of Networks to restore
     /** Return a list of networks the user was connected at the time of core shutdown
@@ -239,7 +240,7 @@ public:
      *
      *  \param user  The User Id in question
      */
-    static inline QList<NetworkId> connectedNetworks(UserId user) { return instance()->_storage->connectedNetworks(user); }
+    static inline std::vector<NetworkId> connectedNetworks(UserId user) { return instance()->_storage->connectedNetworks(user); }
 
     //! Update the connected state of a network
     /** \note This method is threadsafe
@@ -406,7 +407,7 @@ public:
      *  \param limit    if != -1 limit the returned list to a max of \limit entries
      *  \return The requested list of messages
      */
-    static inline QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1)
+    static inline std::vector<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1)
     {
         return instance()->_storage->requestMsgs(user, bufferId, first, last, limit);
     }
@@ -419,7 +420,7 @@ public:
      *  \param type     The Message::Types that should be returned
      *  \return The requested list of messages
      */
-    static inline QList<Message> requestMsgsFiltered(UserId user,
+    static inline std::vector<Message> requestMsgsFiltered(UserId user,
                                                      BufferId bufferId,
                                                      MsgId first = -1,
                                                      MsgId last = -1,
@@ -436,7 +437,7 @@ public:
      *  \param limit    Max amount of messages
      *  \return The requested list of messages
      */
-    static inline QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1)
+    static inline std::vector<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1)
     {
         return instance()->_storage->requestAllMsgs(user, first, last, limit);
     }
@@ -448,7 +449,7 @@ public:
      *  \param type     The Message::Types that should be returned
      *  \return The requested list of messages
      */
-    static inline QList<Message> requestAllMsgsFiltered(UserId user,
+    static inline std::vector<Message> requestAllMsgsFiltered(UserId user,
                                                         MsgId first = -1,
                                                         MsgId last = -1,
                                                         int limit = -1,
@@ -465,7 +466,7 @@ public:
      *  \param user  The user whose buffers we request
      *  \return A list of the BufferInfos for all buffers as requested
      */
-    static inline QList<BufferInfo> requestBuffers(UserId user) { return instance()->_storage->requestBuffers(user); }
+    static inline std::vector<BufferInfo> requestBuffers(UserId user) { return instance()->_storage->requestBuffers(user); }
 
     //! Request a list of BufferIds for a given NetworkId
     /** \note This method is threadsafe.
@@ -474,7 +475,7 @@ public:
      *  \param networkId  The NetworkId of the network in question
      *  \return List of BufferIds belonging to the Network
      */
-    static inline QList<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId)
+    static inline std::vector<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId)
     {
         return instance()->_storage->requestBufferIdsForNetwork(user, networkId);
     }
@@ -655,6 +656,7 @@ public:
 
     inline OidentdConfigGenerator* oidentdConfigGenerator() const { return _oidentdConfigGenerator; }
     inline IdentServer* identServer() const { return _identServer; }
+    inline MetricsServer* metricsServer() const { return _metricsServer; }
 
     static const int AddClientEventId;
 
@@ -785,6 +787,7 @@ private:
     QDateTime _startTime;
 
     IdentServer* _identServer{nullptr};
+    MetricsServer* _metricsServer{nullptr};
 
     bool _initialized{false};
     bool _configured{false};
index d8f81ab..ef24592 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "coreauthhandler.h"
 
+#include <QtEndian>
+
 #ifdef HAVE_SSL
 #    include <QSslSocket>
 #endif
@@ -29,6 +31,7 @@
 CoreAuthHandler::CoreAuthHandler(QTcpSocket* socket, QObject* parent)
     : AuthHandler(parent)
     , _peer(nullptr)
+    , _metricsServer(Core::instance()->metricsServer())
     , _magicReceived(false)
     , _legacy(false)
     , _clientRegistered(false)
@@ -247,9 +250,15 @@ void CoreAuthHandler::handle(const Protocol::Login& msg)
         qInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(socket()->peerAddress().toString(), msg.user));
         _peer->dispatch(Protocol::LoginFailed(tr(
             "<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.")));
+        if (_metricsServer) {
+            _metricsServer->addLoginAttempt(msg.user, false);
+        }
         return;
     }
     _peer->dispatch(Protocol::LoginSuccess());
+    if (_metricsServer) {
+        _metricsServer->addLoginAttempt(uid, true);
+    }
 
     qInfo() << qPrintable(tr("Client %1 initialized and authenticated successfully as \"%2\" (UserId: %3).")
                           .arg(socket()->peerAddress().toString(), msg.user, QString::number(uid.toInt())));
index 0cb9a96..e47be38 100644 (file)
@@ -22,6 +22,7 @@
 #define COREAUTHHANDLER_H
 
 #include "authhandler.h"
+#include "metricsserver.h"
 #include "peerfactory.h"
 #include "remotepeer.h"
 #include "types.h"
@@ -60,6 +61,7 @@ private slots:
 
 private:
     RemotePeer* _peer;
+    MetricsServer* _metricsServer;
 
     bool _magicReceived;
     bool _legacy;
index d72aa71..deb2ac9 100644 (file)
@@ -20,6 +20,9 @@
 
 #include "corebacklogmanager.h"
 
+#include <algorithm>
+#include <iterator>
+
 #include <QDebug>
 
 #include "core.h"
@@ -33,23 +36,19 @@ CoreBacklogManager::CoreBacklogManager(CoreSession* coreSession)
 QVariantList CoreBacklogManager::requestBacklog(BufferId bufferId, MsgId first, MsgId last, int limit, int additional)
 {
     QVariantList backlog;
-    QList<Message> msgList;
-    msgList = Core::requestMsgs(coreSession()->user(), bufferId, first, last, limit);
-
-    QList<Message>::const_iterator msgIter = msgList.constBegin();
-    QList<Message>::const_iterator msgListEnd = msgList.constEnd();
-    while (msgIter != msgListEnd) {
-        backlog << qVariantFromValue(*msgIter);
-        ++msgIter;
-    }
+    auto msgList = Core::requestMsgs(coreSession()->user(), bufferId, first, last, limit);
+
+    std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+        return QVariant::fromValue(msg);
+    });
 
     if (additional && limit != 0) {
         MsgId oldestMessage = first;
-        if (!msgList.isEmpty()) {
-            if (msgList.first().msgId() < msgList.last().msgId())
-                oldestMessage = msgList.first().msgId();
+        if (!msgList.empty()) {
+            if (msgList.front().msgId() < msgList.back().msgId())
+                oldestMessage = msgList.front().msgId();
             else
-                oldestMessage = msgList.last().msgId();
+                oldestMessage = msgList.back().msgId();
         }
 
         if (first != -1) {
@@ -63,12 +62,9 @@ QVariantList CoreBacklogManager::requestBacklog(BufferId bufferId, MsgId first,
         // that is, if the list of messages is not truncated by the limit
         if (last == oldestMessage) {
             msgList = Core::requestMsgs(coreSession()->user(), bufferId, -1, last, additional);
-            msgIter = msgList.constBegin();
-            msgListEnd = msgList.constEnd();
-            while (msgIter != msgListEnd) {
-                backlog << qVariantFromValue(*msgIter);
-                ++msgIter;
-            }
+            std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+                return QVariant::fromValue(msg);
+            });
         }
     }
 
@@ -78,23 +74,19 @@ QVariantList CoreBacklogManager::requestBacklog(BufferId bufferId, MsgId first,
 QVariantList CoreBacklogManager::requestBacklogFiltered(BufferId bufferId, MsgId first, MsgId last, int limit, int additional, int type, int flags)
 {
     QVariantList backlog;
-    QList<Message> msgList;
-    msgList = Core::requestMsgsFiltered(coreSession()->user(), bufferId, first, last, limit, Message::Types{type}, Message::Flags{flags});
-
-    QList<Message>::const_iterator msgIter = msgList.constBegin();
-    QList<Message>::const_iterator msgListEnd = msgList.constEnd();
-    while (msgIter != msgListEnd) {
-        backlog << qVariantFromValue(*msgIter);
-        ++msgIter;
-    }
+    auto msgList = Core::requestMsgsFiltered(coreSession()->user(), bufferId, first, last, limit, Message::Types{type}, Message::Flags{flags});
+
+    std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+        return QVariant::fromValue(msg);
+    });
 
     if (additional && limit != 0) {
         MsgId oldestMessage = first;
-        if (!msgList.isEmpty()) {
-            if (msgList.first().msgId() < msgList.last().msgId())
-                oldestMessage = msgList.first().msgId();
+        if (!msgList.empty()) {
+            if (msgList.front().msgId() < msgList.back().msgId())
+                oldestMessage = msgList.front().msgId();
             else
-                oldestMessage = msgList.last().msgId();
+                oldestMessage = msgList.back().msgId();
         }
 
         if (first != -1) {
@@ -108,12 +100,9 @@ QVariantList CoreBacklogManager::requestBacklogFiltered(BufferId bufferId, MsgId
         // that is, if the list of messages is not truncated by the limit
         if (last == oldestMessage) {
             msgList = Core::requestMsgsFiltered(coreSession()->user(), bufferId, -1, last, additional, Message::Types{type}, Message::Flags{flags});
-            msgIter = msgList.constBegin();
-            msgListEnd = msgList.constEnd();
-            while (msgIter != msgListEnd) {
-                backlog << qVariantFromValue(*msgIter);
-                ++msgIter;
-            }
+            std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+                return QVariant::fromValue(msg);
+            });
         }
     }
 
@@ -123,15 +112,11 @@ QVariantList CoreBacklogManager::requestBacklogFiltered(BufferId bufferId, MsgId
 QVariantList CoreBacklogManager::requestBacklogAll(MsgId first, MsgId last, int limit, int additional)
 {
     QVariantList backlog;
-    QList<Message> msgList;
-    msgList = Core::requestAllMsgs(coreSession()->user(), first, last, limit);
-
-    QList<Message>::const_iterator msgIter = msgList.constBegin();
-    QList<Message>::const_iterator msgListEnd = msgList.constEnd();
-    while (msgIter != msgListEnd) {
-        backlog << qVariantFromValue(*msgIter);
-        ++msgIter;
-    }
+    auto msgList = Core::requestAllMsgs(coreSession()->user(), first, last, limit);
+
+    std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+        return QVariant::fromValue(msg);
+    });
 
     if (additional) {
         if (first != -1) {
@@ -139,20 +124,17 @@ QVariantList CoreBacklogManager::requestBacklogAll(MsgId first, MsgId last, int
         }
         else {
             last = -1;
-            if (!msgList.isEmpty()) {
-                if (msgList.first().msgId() < msgList.last().msgId())
-                    last = msgList.first().msgId();
+            if (!msgList.empty()) {
+                if (msgList.front().msgId() < msgList.back().msgId())
+                    last = msgList.front().msgId();
                 else
-                    last = msgList.last().msgId();
+                    last = msgList.back().msgId();
             }
         }
         msgList = Core::requestAllMsgs(coreSession()->user(), -1, last, additional);
-        msgIter = msgList.constBegin();
-        msgListEnd = msgList.constEnd();
-        while (msgIter != msgListEnd) {
-            backlog << qVariantFromValue(*msgIter);
-            ++msgIter;
-        }
+        std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+            return QVariant::fromValue(msg);
+        });
     }
 
     return backlog;
@@ -161,15 +143,11 @@ QVariantList CoreBacklogManager::requestBacklogAll(MsgId first, MsgId last, int
 QVariantList CoreBacklogManager::requestBacklogAllFiltered(MsgId first, MsgId last, int limit, int additional, int type, int flags)
 {
     QVariantList backlog;
-    QList<Message> msgList;
-    msgList = Core::requestAllMsgsFiltered(coreSession()->user(), first, last, limit, Message::Types{type}, Message::Flags{flags});
-
-    QList<Message>::const_iterator msgIter = msgList.constBegin();
-    QList<Message>::const_iterator msgListEnd = msgList.constEnd();
-    while (msgIter != msgListEnd) {
-        backlog << qVariantFromValue(*msgIter);
-        ++msgIter;
-    }
+    auto msgList = Core::requestAllMsgsFiltered(coreSession()->user(), first, last, limit, Message::Types{type}, Message::Flags{flags});
+
+    std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+        return QVariant::fromValue(msg);
+    });
 
     if (additional) {
         if (first != -1) {
@@ -177,20 +155,17 @@ QVariantList CoreBacklogManager::requestBacklogAllFiltered(MsgId first, MsgId la
         }
         else {
             last = -1;
-            if (!msgList.isEmpty()) {
-                if (msgList.first().msgId() < msgList.last().msgId())
-                    last = msgList.first().msgId();
+            if (!msgList.empty()) {
+                if (msgList.front().msgId() < msgList.back().msgId())
+                    last = msgList.front().msgId();
                 else
-                    last = msgList.last().msgId();
+                    last = msgList.back().msgId();
             }
         }
         msgList = Core::requestAllMsgsFiltered(coreSession()->user(), -1, last, additional, Message::Types{type}, Message::Flags{flags});
-        msgIter = msgList.constBegin();
-        msgListEnd = msgList.constEnd();
-        while (msgIter != msgListEnd) {
-            backlog << qVariantFromValue(*msgIter);
-            ++msgIter;
-        }
+        std::transform(msgList.cbegin(), msgList.cend(), std::back_inserter(backlog), [](auto&& msg) {
+            return QVariant::fromValue(msg);
+        });
     }
 
     return backlog;
index 4f3830e..266f344 100644 (file)
 
 #include "corebuffersyncer.h"
 
+#include <algorithm>
+#include <iterator>
+#include <set>
+
 #include "core.h"
 #include "corenetwork.h"
 #include "coresession.h"
@@ -184,15 +188,14 @@ void CoreBufferSyncer::requestPurgeBufferIds()
 void CoreBufferSyncer::purgeBufferIds()
 {
     _purgeBuffers = false;
-    QList<BufferInfo> bufferInfos = Core::requestBuffers(_coreSession->user());
-    QSet<BufferId> actualBuffers;
-    foreach (BufferInfo bufferInfo, bufferInfos) {
-        actualBuffers << bufferInfo.bufferId();
-    }
+    auto bufferInfos = Core::requestBuffers(_coreSession->user());
+    std::set<BufferId> actualBuffers;
+    std::transform(bufferInfos.cbegin(), bufferInfos.cend(), std::inserter(actualBuffers, actualBuffers.end()),
+                   [](auto&& bufferInfo) { return bufferInfo.bufferId(); });
 
     QSet<BufferId> storedIds = lastSeenBufferIds().toSet() + markerLineBufferIds().toSet();
     foreach (BufferId bufferId, storedIds) {
-        if (!actualBuffers.contains(bufferId)) {
+        if (actualBuffers.find(bufferId) == actualBuffers.end()) {
             BufferSyncer::removeBuffer(bufferId);
         }
     }
index 4329a28..5671ae8 100644 (file)
@@ -25,7 +25,7 @@
 CoreIdentity::CoreIdentity(IdentityId id, QObject* parent)
     : Identity(id, parent)
 #ifdef HAVE_SSL
-    , _certManager(*this)
+    , _certManager(this)
 #endif
 {
 #ifdef HAVE_SSL
@@ -37,7 +37,7 @@ CoreIdentity::CoreIdentity(IdentityId id, QObject* parent)
 CoreIdentity::CoreIdentity(const Identity& other, QObject* parent)
     : Identity(other, parent)
 #ifdef HAVE_SSL
-    , _certManager(*this)
+    , _certManager(this)
 #endif
 {
 #ifdef HAVE_SSL
@@ -51,7 +51,7 @@ CoreIdentity::CoreIdentity(const CoreIdentity& other, QObject* parent)
 #ifdef HAVE_SSL
     , _sslKey(other._sslKey)
     , _sslCert(other._sslCert)
-    , _certManager(*this)
+    , _certManager(this)
 #endif
 {
 #ifdef HAVE_SSL
@@ -86,24 +86,14 @@ void CoreIdentity::setSslCert(const QByteArray& encoded)
 
 #endif
 
-CoreIdentity& CoreIdentity::operator=(const CoreIdentity& identity)
-{
-    Identity::operator=(identity);
-#ifdef HAVE_SSL
-    _sslKey = identity._sslKey;
-    _sslCert = identity._sslCert;
-#endif
-    return *this;
-}
-
 #ifdef HAVE_SSL
 // ========================================
 //  CoreCertManager
 // ========================================
 
-CoreCertManager::CoreCertManager(CoreIdentity& identity)
-    : CertManager(identity.id())
-    , identity(identity)
+CoreCertManager::CoreCertManager(CoreIdentity* identity)
+    : CertManager(identity->id())
+    , _identity(identity)
 {
     setAllowClientUpdates(true);
 }
@@ -115,13 +105,13 @@ void CoreCertManager::setId(IdentityId id)
 
 void CoreCertManager::setSslKey(const QByteArray& encoded)
 {
-    identity.setSslKey(encoded);
+    _identity->setSslKey(encoded);
     CertManager::setSslKey(encoded);
 }
 
 void CoreCertManager::setSslCert(const QByteArray& encoded)
 {
-    identity.setSslCert(encoded);
+    _identity->setSslCert(encoded);
     CertManager::setSslCert(encoded);
 }
 
index a211a72..573f9c5 100644 (file)
@@ -20,6 +20,8 @@
 
 #pragma once
 
+#include "core-export.h"
+
 #include "identity.h"
 
 #ifdef HAVE_SSL
@@ -34,12 +36,12 @@ class SignalProxy;
 // ========================================
 #ifdef HAVE_SSL
 class CoreIdentity;
-class CoreCertManager : public CertManager
+class CORE_EXPORT CoreCertManager : public CertManager
 {
     Q_OBJECT
 
 public:
-    CoreCertManager(CoreIdentity& identity);
+    CoreCertManager(CoreIdentity* identity);
 
 #    ifdef HAVE_SSL
     const QSslKey& sslKey() const override;
@@ -53,7 +55,7 @@ public slots:
     void setId(IdentityId id);
 
 private:
-    CoreIdentity& identity;
+    CoreIdentity* _identity{nullptr};
 };
 
 #endif  // HAVE_SSL
@@ -61,7 +63,7 @@ private:
 // =========================================
 //  CoreIdentity
 // =========================================
-class CoreIdentity : public Identity
+class CORE_EXPORT CoreIdentity : public Identity
 {
     Q_OBJECT
 
@@ -81,8 +83,6 @@ public:
     void setSslCert(const QByteArray& encoded);
 #endif /* HAVE_SSL */
 
-    CoreIdentity& operator=(const CoreIdentity& identity);
-
 private:
 #ifdef HAVE_SSL
     QSslKey _sslKey;
@@ -95,12 +95,12 @@ private:
 #ifdef HAVE_SSL
 inline const QSslKey& CoreCertManager::sslKey() const
 {
-    return identity.sslKey();
+    return _identity->sslKey();
 }
 
 inline const QSslCertificate& CoreCertManager::sslCert() const
 {
-    return identity.sslCert();
+    return _identity->sslCert();
 }
 
 #endif
index e6699c1..8506dea 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <QDebug>
 #include <QHostInfo>
+#include <QTextBoundaryFinder>
 
 #include "core.h"
 #include "coreidentity.h"
@@ -37,6 +38,7 @@ CoreNetwork::CoreNetwork(const NetworkId& networkid, CoreSession* session)
     : Network(networkid, session)
     , _coreSession(session)
     , _userInputHandler(new CoreUserInputHandler(this))
+    , _metricsServer(Core::instance()->metricsServer())
     , _autoReconnectCount(0)
     , _quitRequested(false)
     , _disconnectExpected(false)
@@ -184,6 +186,10 @@ void CoreNetwork::connectToIrc(bool reconnecting)
         _socketId = Core::instance()->identServer()->addWaitingSocket();
     }
 
+    if (_metricsServer) {
+        _metricsServer->addNetwork(userId());
+    }
+
     if (!reconnecting && useAutoReconnect() && _autoReconnectCount == 0) {
         _autoReconnectTimer.setInterval(autoReconnectInterval() * 1000);
         if (unlimitedReconnectRetries())
@@ -290,6 +296,9 @@ void CoreNetwork::disconnectFromIrc(bool requested, const QString& reason, bool
     }
     disablePingTimeout();
     _msgQueue.clear();
+    if (_metricsServer) {
+        _metricsServer->messageQueue(userId(), 0);
+    }
 
     IrcUser* me_ = me();
     if (me_) {
@@ -366,6 +375,9 @@ void CoreNetwork::putRawLine(const QByteArray& s, bool prepend)
             // Add to back, waiting in order
             _msgQueue.append(s);
         }
+        if (_metricsServer) {
+            _metricsServer->messageQueue(userId(), _msgQueue.size());
+        }
     }
 }
 
@@ -505,6 +517,9 @@ void CoreNetwork::onSocketHasData()
 {
     while (socket.canReadLine()) {
         QByteArray s = socket.readLine();
+        if (_metricsServer) {
+            _metricsServer->receiveDataNetwork(userId(), s.size());
+        }
         if (s.endsWith("\r\n"))
             s.chop(2);
         else if (s.endsWith("\n"))
@@ -605,6 +620,9 @@ void CoreNetwork::onSocketDisconnected()
 {
     disablePingTimeout();
     _msgQueue.clear();
+    if (_metricsServer) {
+        _metricsServer->messageQueue(userId(), 0);
+    }
 
     _autoWhoCycleTimer.stop();
     _autoWhoTimer.stop();
@@ -644,6 +662,10 @@ void CoreNetwork::onSocketDisconnected()
         else
             _autoReconnectTimer.start();
     }
+
+    if (_metricsServer) {
+        _metricsServer->removeNetwork(userId());
+    }
 }
 
 void CoreNetwork::onSocketStateChanged(QAbstractSocket::SocketState socketState)
@@ -1503,6 +1525,9 @@ void CoreNetwork::fillBucketAndProcessQueue()
     // As long as there's tokens available and messages remaining, sending messages from the queue
     while (!_msgQueue.empty() && _tokenBucket > 0) {
         writeToSocket(_msgQueue.takeFirst());
+        if (_metricsServer) {
+            _metricsServer->messageQueue(userId(), _msgQueue.size());
+        }
     }
 }
 
@@ -1515,6 +1540,9 @@ void CoreNetwork::writeToSocket(const QByteArray& data)
     }
     socket.write(data);
     socket.write("\r\n");
+    if (_metricsServer) {
+        _metricsServer->transmitDataNetwork(userId(), data.size() + 2);
+    }
     if (!_skipMessageRates) {
         // Only subtract from the token bucket if message rate limiting is enabled
         _tokenBucket--;
index bcab1df..01d71ed 100644 (file)
@@ -521,6 +521,7 @@ private:
     qint64 _socketId{0};
 
     CoreUserInputHandler* _userInputHandler;
+    MetricsServer* _metricsServer;
 
     QHash<QString, QString> _channelKeys;  // stores persistent channels and their passwords, if any
 
index 119d73d..a05b6ba 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <utility>
 
-#include <QtScript>
-
 #include "core.h"
 #include "corebacklogmanager.h"
 #include "corebuffersyncer.h"
@@ -78,10 +76,10 @@ CoreSession::CoreSession(UserId uid, bool restoreState, bool strictIdentEnabled,
     , _sessionEventProcessor(new CoreSessionEventProcessor(this))
     , _ctcpParser(new CtcpParser(this))
     , _ircParser(new IrcParser(this))
-    , scriptEngine(new QScriptEngine(this))
     , _processMessages(false)
     , _ignoreListManager(this)
     , _highlightRuleManager(this)
+    , _metricsServer(Core::instance()->metricsServer())
 {
     SignalProxy* p = signalProxy();
     p->setHeartBeatInterval(30);
@@ -120,7 +118,6 @@ CoreSession::CoreSession(UserId uid, bool restoreState, bool strictIdentEnabled,
     _coreInfo->setCoreData(data);
 
     loadSettings();
-    initScriptEngine();
 
     eventManager()->registerObject(ircParser(), EventManager::NormalPriority);
     eventManager()->registerObject(sessionEventProcessor(), EventManager::HighPriority);  // needs to process events *before* the stringifier!
@@ -151,6 +148,10 @@ CoreSession::CoreSession(UserId uid, bool restoreState, bool strictIdentEnabled,
         restoreSessionState();
 
     emit initialized();
+
+    if (_metricsServer) {
+        _metricsServer->addSession(user(), Core::instance()->strictSysIdent(_user));
+    }
 }
 
 void CoreSession::shutdown()
@@ -171,6 +172,10 @@ void CoreSession::shutdown()
         // Nothing to do, suicide so the core can shut down
         deleteLater();
     }
+
+    if (_metricsServer) {
+        _metricsServer->removeSession(user());
+    }
 }
 
 void CoreSession::onNetworkDisconnected(NetworkId networkId)
@@ -202,11 +207,11 @@ void CoreSession::loadSettings()
 
     // migrate to db
     QList<IdentityId> ids = s.identityIds();
-    QList<NetworkInfo> networkInfos = Core::networks(user());
+    std::vector<NetworkInfo> networkInfos = Core::networks(user());
     for (IdentityId id : ids) {
         CoreIdentity identity(s.identity(id));
         IdentityId newId = Core::createIdentity(user(), identity);
-        QList<NetworkInfo>::iterator networkIter = networkInfos.begin();
+        auto networkIter = networkInfos.begin();
         while (networkIter != networkInfos.end()) {
             if (networkIter->identity == id) {
                 networkIter->identity = newId;
@@ -239,10 +244,8 @@ void CoreSession::saveSessionState() const
 
 void CoreSession::restoreSessionState()
 {
-    QList<NetworkId> nets = Core::connectedNetworks(user());
-    CoreNetwork* net = nullptr;
-    for (NetworkId id :  nets) {
-        net = network(id);
+    for (NetworkId id : Core::connectedNetworks(user())) {
+        auto net = network(id);
         Q_ASSERT(net);
         net->connectToIrc();
     }
@@ -257,6 +260,10 @@ void CoreSession::addClient(RemotePeer* peer)
     _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
 
     signalProxy()->setTargetPeer(nullptr);
+
+    if (_metricsServer) {
+        _metricsServer->addClient(user());
+    }
 }
 
 void CoreSession::addClient(InternalPeer* peer)
@@ -271,6 +278,10 @@ void CoreSession::removeClient(Peer* peer)
     if (p)
         qInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
     _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
+
+    if (_metricsServer) {
+        _metricsServer->removeClient(user());
+    }
 }
 
 QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const
@@ -346,7 +357,7 @@ void CoreSession::processMessageEvent(MessageEvent* event)
     });
 }
 
-QList<BufferInfo> CoreSession::buffers() const
+std::vector<BufferInfo> CoreSession::buffers() const
 {
     return Core::requestBuffers(user());
 }
@@ -515,21 +526,6 @@ Protocol::SessionState CoreSession::sessionState() const
     return Protocol::SessionState(identities, bufferInfos, networkIds);
 }
 
-void CoreSession::initScriptEngine()
-{
-    signalProxy()->attachSlot(SIGNAL(scriptRequest(QString)), this, &CoreSession::scriptRequest);
-    signalProxy()->attachSignal(this, &CoreSession::scriptResult);
-
-    // FIXME
-    // QScriptValue storage_ = scriptEngine->newQObject(storage);
-    // scriptEngine->globalObject().setProperty("storage", storage_);
-}
-
-void CoreSession::scriptRequest(QString script)
-{
-    emit scriptResult(scriptEngine->evaluate(script).toString());
-}
-
 /*** Identity Handling ***/
 void CoreSession::createIdentity(const Identity& identity, const QVariantMap& additional)
 {
@@ -661,7 +657,6 @@ void CoreSession::removeNetwork(NetworkId id)
 
 void CoreSession::destroyNetwork(NetworkId id)
 {
-    QList<BufferId> removedBuffers = Core::requestBufferIdsForNetwork(user(), id);
     Network* net = _networks.take(id);
     if (net && Core::removeNetwork(user(), id)) {
         // make sure that all unprocessed RawMessages from this network are removed
@@ -675,7 +670,7 @@ void CoreSession::destroyNetwork(NetworkId id)
             }
         }
         // remove buffers from syncer
-        for (BufferId bufferId : removedBuffers) {
+        for (BufferId bufferId : Core::requestBufferIdsForNetwork(user(), id)) {
             _bufferSyncer->removeBuffer(bufferId);
         }
         emit networkRemoved(id);
index 99cd593..f47d175 100644 (file)
@@ -21,6 +21,7 @@
 #pragma once
 
 #include <utility>
+#include <vector>
 
 #include <QHash>
 #include <QSet>
@@ -32,6 +33,7 @@
 #include "coreignorelistmanager.h"
 #include "coreinfo.h"
 #include "message.h"
+#include "metricsserver.h"
 #include "peer.h"
 #include "protocol.h"
 #include "storage.h"
@@ -57,8 +59,6 @@ class SignalProxy;
 
 struct NetworkInfo;
 
-class QScriptEngine;
-
 class CoreSession : public QObject
 {
     Q_OBJECT
@@ -66,7 +66,7 @@ class CoreSession : public QObject
 public:
     CoreSession(UserId, bool restoreState, bool strictIdentEnabled, QObject* parent = nullptr);
 
-    QList<BufferInfo> buffers() const;
+    std::vector<BufferInfo> buffers() const;
     inline UserId user() const { return _user; }
     CoreNetwork* network(NetworkId) const;
     CoreIdentity* identity(IdentityId) const;
@@ -172,8 +172,6 @@ signals:
     void displayMsg(Message message);
     void displayStatusMsg(QString, QString);
 
-    void scriptResult(QString result);
-
     //! Identity has been created.
     /** This signal is propagated to the clients to tell them that the given identity has been created.
      *  \param identity The new identity.
@@ -205,8 +203,6 @@ private slots:
 
     void destroyNetwork(NetworkId);
 
-    void scriptRequest(QString script);
-
     void clientsConnected();
     void clientsDisconnected();
 
@@ -220,7 +216,6 @@ private:
     void processMessages();
 
     void loadSettings();
-    void initScriptEngine();
 
     /// Hook for converting events to the old displayMsg() handlers
     Q_INVOKABLE void processMessageEvent(MessageEvent* event);
@@ -252,8 +247,6 @@ private:
     CtcpParser* _ctcpParser;
     IrcParser* _ircParser;
 
-    QScriptEngine* scriptEngine;
-
     /**
      * This method obtains the prefixes of the message's sender within a channel, by looking up their channelmodes, and
      * processing them to prefixes based on the network's settings.
@@ -279,6 +272,7 @@ private:
     bool _processMessages;
     CoreIgnoreListManager _ignoreListManager;
     CoreHighlightRuleManager _highlightRuleManager;
+    MetricsServer* _metricsServer{nullptr};
 };
 
 struct NetworkInternalMessage
index af30bfb..0287980 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "coresessioneventprocessor.h"
 
+#include <algorithm>
+
 #include "coreirclisthelper.h"
 #include "corenetwork.h"
 #include "coresession.h"
@@ -1536,7 +1538,7 @@ void CoreSessionEventProcessor::handleCtcpClientinfo(CtcpEvent* e)
     QStringList supportedHandlers;
     for (const QString& handler : providesHandlers())
         supportedHandlers << handler.toUpper();
-    qSort(supportedHandlers);
+    std::sort(supportedHandlers.begin(), supportedHandlers.end());
     e->setReply(supportedHandlers.join(" "));
 }
 
diff --git a/src/core/metricsserver.cpp b/src/core/metricsserver.cpp
new file mode 100644 (file)
index 0000000..c0f4bbe
--- /dev/null
@@ -0,0 +1,408 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2019 by the Quassel Project                        *
+ *   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.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#include "metricsserver.h"
+
+#include <utility>
+
+#include <QByteArray>
+#include <QDebug>
+#include <QHostAddress>
+#include <QStringList>
+#include <QTcpSocket>
+
+#include "core.h"
+#include "corenetwork.h"
+
+MetricsServer::MetricsServer(QObject* parent)
+    : QObject(parent)
+{
+    connect(&_server, &QTcpServer::newConnection, this, &MetricsServer::incomingConnection);
+    connect(&_v6server, &QTcpServer::newConnection, this, &MetricsServer::incomingConnection);
+}
+
+bool MetricsServer::startListening()
+{
+    bool success = false;
+
+    uint16_t port = Quassel::optionValue("metrics-port").toUShort();
+
+    const QString listen = Quassel::optionValue("metrics-listen");
+    const QStringList listen_list = listen.split(",", QString::SkipEmptyParts);
+    for (const QString& listen_term : listen_list) { // TODO: handle multiple interfaces for same TCP version gracefully
+        QHostAddress addr;
+        if (!addr.setAddress(listen_term)) {
+            qCritical() << qPrintable(
+                tr("Invalid listen address %1")
+                    .arg(listen_term)
+            );
+        }
+        else {
+            switch (addr.protocol()) {
+            case QAbstractSocket::IPv6Protocol:
+                if (_v6server.listen(addr, port)) {
+                    qInfo() << qPrintable(
+                        tr("Listening for metrics requests on IPv6 %1 port %2")
+                            .arg(addr.toString())
+                            .arg(_v6server.serverPort())
+                    );
+                    success = true;
+                }
+                else
+                    qWarning() << qPrintable(
+                        tr("Could not open IPv6 interface %1:%2: %3")
+                            .arg(addr.toString())
+                            .arg(port)
+                            .arg(_v6server.errorString()));
+                break;
+            case QAbstractSocket::IPv4Protocol:
+                if (_server.listen(addr, port)) {
+                    qInfo() << qPrintable(
+                        tr("Listening for metrics requests on IPv4 %1 port %2")
+                            .arg(addr.toString())
+                            .arg(_server.serverPort())
+                    );
+                    success = true;
+                }
+                else {
+                    // if v6 succeeded on Any, the port will be already in use - don't display the error then
+                    if (!success || _server.serverError() != QAbstractSocket::AddressInUseError)
+                        qWarning() << qPrintable(
+                            tr("Could not open IPv4 interface %1:%2: %3")
+                                .arg(addr.toString())
+                                .arg(port)
+                                .arg(_server.errorString()));
+                }
+                break;
+            default:
+                qCritical() << qPrintable(
+                    tr("Invalid listen address %1, unknown network protocol")
+                        .arg(listen_term)
+                );
+                break;
+            }
+        }
+    }
+
+    if (!success) {
+        qWarning() << qPrintable(tr("Metrics could not open any network interfaces to listen on! No metrics functionality will be available"));
+    }
+
+    return success;
+}
+
+void MetricsServer::stopListening(const QString& msg)
+{
+    bool wasListening = false;
+
+    if (_server.isListening()) {
+        wasListening = true;
+        _server.close();
+    }
+    if (_v6server.isListening()) {
+        wasListening = true;
+        _v6server.close();
+    }
+
+    if (wasListening) {
+        if (msg.isEmpty())
+            qInfo() << "No longer listening for metrics requests.";
+        else
+            qInfo() << qPrintable(msg);
+    }
+}
+
+void MetricsServer::incomingConnection()
+{
+    auto server = qobject_cast<QTcpServer*>(sender());
+    Q_ASSERT(server);
+    while (server->hasPendingConnections()) {
+        QTcpSocket* socket = server->nextPendingConnection();
+        connect(socket, &QIODevice::readyRead, this, &MetricsServer::respond);
+        connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater);
+    }
+}
+
+QString parseHttpString(const QByteArray& request, int& index)
+{
+    QString content;
+    int end = request.indexOf(' ', index);
+    if (end == -1) {
+        end = request.length();
+    }
+
+    if (end > -1) {
+        content = QString::fromUtf8(request.mid(index, end - index));
+        index = end + 1;
+    }
+    else {
+        index = request.length();
+    }
+    return content;
+}
+
+void MetricsServer::respond()
+{
+    auto socket = qobject_cast<QTcpSocket*>(sender());
+    Q_ASSERT(socket);
+
+    if (!socket->canReadLine()) {
+        return;
+    }
+
+    int index = 0;
+    QString verb;
+    QString requestPath;
+    QString version;
+    QByteArray request;
+    for (int i = 0; i < 5 && verb == ""; i++) {
+        request = socket->readLine(4096);
+        if (request.endsWith("\r\n")) {
+            request.chop(2);
+        }
+        else if (request.endsWith("\n")) {
+            request.chop(1);
+        }
+
+        verb = parseHttpString(request, index);
+        requestPath = parseHttpString(request, index);
+        version = parseHttpString(request, index);
+    }
+
+    if (requestPath == "/metrics") {
+        if (version == "HTTP/1.1") {
+            socket->write(
+                "HTTP/1.1 200 OK\r\n"
+                "Content-Type: text/plain; version=0.0.4\r\n"
+                "Connection: close\r\n"
+                "\r\n"
+            );
+        }
+        int64_t timestamp = QDateTime::currentMSecsSinceEpoch();
+        for (const auto& key : _sessions.keys()) {
+            const QString& name = _sessions[key];
+            socket->write("# HELP quassel_network_bytes_received Number of currently open connections from quassel clients\n");
+            socket->write("# TYPE quassel_client_sessions gauge\n");
+            socket->write(
+                QString("quassel_client_sessions{user=\"%1\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_clientSessions.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+            socket->write("# HELP quassel_network_bytes_received Number of currently open connections to IRC networks\n");
+            socket->write("# TYPE quassel_network_sessions gauge\n");
+            socket->write(
+                QString("quassel_network_sessions{user=\"%1\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_networkSessions.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+            socket->write("# HELP quassel_network_bytes_received Amount of bytes sent to IRC\n");
+            socket->write("# TYPE quassel_network_bytes_sent counter\n");
+            socket->write(
+                QString("quassel_network_bytes_sent{user=\"%1\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_networkDataTransmit.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+            socket->write("# HELP quassel_network_bytes_received Amount of bytes received from IRC\n");
+            socket->write("# TYPE quassel_network_bytes_received counter\n");
+            socket->write(
+                QString("quassel_network_bytes_received{user=\"%1\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_networkDataReceive.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+            socket->write("# HELP quassel_message_queue The number of messages currently queued for that user\n");
+            socket->write("# TYPE quassel_message_queue gauge\n");
+            socket->write(
+                QString("quassel_message_queue{user=\"%1\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_messageQueue.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+            socket->write("# HELP quassel_login_attempts The number of times the user has attempted to log in\n");
+            socket->write("# TYPE quassel_login_attempts counter\n");
+            socket->write(
+                QString("quassel_login_attempts{user=\"%1\",successful=\"false\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_loginAttempts.value(key, 0) - _successfulLogins.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+            socket->write(
+                QString("quassel_login_attempts{user=\"%1\",successful=\"true\"} %2 %3\n")
+                    .arg(name)
+                    .arg(_successfulLogins.value(key, 0))
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+        }
+        if (!_certificateExpires.isNull()) {
+            socket->write("# HELP quassel_ssl_expire_time_seconds Expiration of the current TLS certificate in unixtime\n");
+            socket->write("# TYPE quassel_ssl_expire_time_seconds gauge\n");
+            socket->write(
+                QString("quassel_ssl_expire_time_seconds %1 %2\n")
+                    .arg(_certificateExpires.toMSecsSinceEpoch() / 1000)
+                    .arg(timestamp)
+                    .toUtf8()
+            );
+        }
+        socket->write(
+                QString("quassel_login{successful=\"false\"} %1\n")
+                        .arg(QString::number((float) _loginFailed))
+                        .toUtf8()
+        );
+        socket->write(
+                QString("quassel_login{successful=\"true\"} %1\n")
+                        .arg(QString::number((float) _loginSuccessful))
+                        .toUtf8()
+        );
+        socket->close();
+    }
+    else if (requestPath == "/healthz") {
+        if (version == "HTTP/1.1") {
+            socket->write(
+                "HTTP/1.1 200 OK\r\n"
+                "Content-Type: text/plain\r\n"
+                "Connection: close\r\n"
+                "\r\n"
+            );
+        }
+        socket->write(
+            "OK\n"
+        );
+        socket->close();
+    }
+    else {
+        if (version == "HTTP/1.1") {
+            socket->write(
+                "HTTP/1.1 404 Not Found\r\n"
+                "Content-Type: text/html\r\n"
+                "Connection: close\r\n"
+                "\r\n"
+            );
+        }
+        socket->write(
+            QString(
+                "<html>\n"
+                "<head><title>404 Not Found</title></head>\n"
+                "<body>\n"
+                "<center><h1>404 Not Found</h1></center>\n"
+                "<hr><center>quassel %1 </center>\n"
+                "</body>\n"
+                "</html>\n")
+                .arg(Quassel::buildInfo().baseVersion)
+                .toUtf8()
+        );
+        socket->close();
+    }
+}
+
+void MetricsServer::addLoginAttempt(UserId user, bool successful) {
+    _loginAttempts.insert(user, _loginAttempts.value(user, 0) + 1);
+    if (successful) {
+        _successfulLogins.insert(user, _successfulLogins.value(user, 0) + 1);
+    }
+}
+
+void MetricsServer::addLoginAttempt(const QString& user, bool successful) {
+    UserId userId = _sessions.key(user);
+    if (userId.isValid()) {
+        addLoginAttempt(userId, successful);
+    }
+}
+
+void MetricsServer::addSession(UserId user, const QString& name)
+{
+    _sessions.insert(user, name);
+}
+
+void MetricsServer::removeSession(UserId user)
+{
+    _sessions.remove(user);
+}
+
+void MetricsServer::addClient(UserId user)
+{
+    _clientSessions.insert(user, _clientSessions.value(user, 0) + 1);
+}
+
+void MetricsServer::removeClient(UserId user)
+{
+    int count = _clientSessions.value(user, 0) - 1;
+    if (count <= 0) {
+        _clientSessions.remove(user);
+    }
+    else {
+        _clientSessions.insert(user, count);
+    }
+}
+
+void MetricsServer::addNetwork(UserId user)
+{
+    _networkSessions.insert(user, _networkSessions.value(user, 0) + 1);
+}
+
+void MetricsServer::removeNetwork(UserId user)
+{
+    int count = _networkSessions.value(user, 0) - 1;
+    if (count <= 0) {
+        _networkSessions.remove(user);
+    }
+    else {
+        _networkSessions.insert(user, count);
+    }
+}
+
+void MetricsServer::transmitDataNetwork(UserId user, uint64_t size)
+{
+    _networkDataTransmit.insert(user, _networkDataTransmit.value(user, 0) + size);
+}
+
+void MetricsServer::receiveDataNetwork(UserId user, uint64_t size)
+{
+    _networkDataReceive.insert(user, _networkDataReceive.value(user, 0) + size);
+}
+
+void MetricsServer::messageQueue(UserId user, uint64_t size)
+{
+    _messageQueue.insert(user, size);
+}
+
+void MetricsServer::setCertificateExpires(QDateTime expires)
+{
+    _certificateExpires = std::move(expires);
+}
+
+void MetricsServer::loginSuccessful()
+{
+    _loginSuccessful++;
+}
+
+void MetricsServer::loginFailed()
+{
+    _loginFailed++;
+}
similarity index 50%
rename from src/qtui/debugconsole.h
rename to src/core/metricsserver.h
index c973f32..1d26833 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef DEBUGCONSOLE_H
-#define DEBUGCONSOLE_H
+#pragma once
 
-#include "ui_debugconsole.h"
+#include <QHash>
+#include <QObject>
+#include <QString>
+#include <QTcpServer>
 
-class DebugConsole : public QDialog
+#include "coreidentity.h"
+
+class MetricsServer : public QObject
 {
     Q_OBJECT
 
 public:
-    DebugConsole(QWidget* parent = nullptr);
+    explicit MetricsServer(QObject* parent = nullptr);
+
+    bool startListening();
+    void stopListening(const QString& msg);
+
+    void addLoginAttempt(UserId user, bool successful);
+    void addLoginAttempt(const QString& user, bool successful);
+
+    void addSession(UserId user, const QString& name);
+    void removeSession(UserId user);
+
+    void addClient(UserId user);
+    void removeClient(UserId user);
+
+    void addNetwork(UserId user);
+    void removeNetwork(UserId user);
+
+    void transmitDataNetwork(UserId user, uint64_t size);
+    void receiveDataNetwork(UserId user, uint64_t size);
+
+    void loginSuccessful();
+    void loginFailed();
 
-public slots:
-    void scriptResult(QString result);
+    void messageQueue(UserId user, uint64_t size);
 
-signals:
-    void scriptRequest(QString script);
+    void setCertificateExpires(QDateTime expires);
 
 private slots:
-    void on_evalButton_clicked();
+    void incomingConnection();
+    void respond();
 
 private:
-    Ui::DebugConsole ui;
-};
+    QTcpServer _server, _v6server;
+
+    QHash<UserId, uint64_t> _loginAttempts{};
+    QHash<UserId, uint64_t> _successfulLogins{};
+
+    QHash<UserId, QString> _sessions{};
+
+    QHash<UserId, int64_t> _clientSessions{};
+    QHash<UserId, int64_t> _networkSessions{};
 
-#endif
+    QHash<UserId, uint64_t> _networkDataTransmit{};
+    QHash<UserId, uint64_t> _networkDataReceive{};
+
+    QHash<UserId, uint64_t> _messageQueue{};
+
+    uint64_t _loginSuccessful{};
+    uint64_t _loginFailed{};
+
+    QDateTime _certificateExpires{};
+};
index 03594b4..91a7f5b 100644 (file)
@@ -44,7 +44,7 @@ OidentdConfigGenerator::~OidentdConfigGenerator()
 
 bool OidentdConfigGenerator::init()
 {
-    _configDir = QDir::homePath();
+    _configDir.setPath(QDir::homePath());
     _configFileName = ".oidentd.conf";
 
     if (Quassel::isOptionSet("oidentd-conffile"))
index 40ff80c..2aa2855 100644 (file)
 
 #include "postgresqlstorage.h"
 
-#include <QtSql>
+#include <QByteArray>
+#include <QDataStream>
+#include <QSqlDriver>
+#include <QSqlField>
 
 #include "network.h"
 #include "quassel.h"
@@ -673,9 +676,9 @@ void PostgreSqlStorage::removeIdentity(UserId user, IdentityId identityId)
     }
 }
 
-QList<CoreIdentity> PostgreSqlStorage::identities(UserId user)
+std::vector<CoreIdentity> PostgreSqlStorage::identities(UserId user)
 {
-    QList<CoreIdentity> identities;
+    std::vector<CoreIdentity> identities;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -727,7 +730,7 @@ QList<CoreIdentity> PostgreSqlStorage::identities(UserId user)
             nicks << nickQuery.value(0).toString();
         }
         identity.setNicks(nicks);
-        identities << identity;
+        identities.push_back(std::move(identity));
     }
     db.commit();
     return identities;
@@ -905,9 +908,9 @@ bool PostgreSqlStorage::removeNetwork(UserId user, const NetworkId& networkId)
     return true;
 }
 
-QList<NetworkInfo> PostgreSqlStorage::networks(UserId user)
+std::vector<NetworkInfo> PostgreSqlStorage::networks(UserId user)
 {
-    QList<NetworkInfo> nets;
+    std::vector<NetworkInfo> nets;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -981,15 +984,15 @@ QList<NetworkInfo> PostgreSqlStorage::networks(UserId user)
             servers << server;
         }
         net.serverList = servers;
-        nets << net;
+        nets.push_back(std::move(net));
     }
     db.commit();
     return nets;
 }
 
-QList<NetworkId> PostgreSqlStorage::connectedNetworks(UserId user)
+std::vector<NetworkId> PostgreSqlStorage::connectedNetworks(UserId user)
 {
-    QList<NetworkId> connectedNets;
+    std::vector<NetworkId> connectedNets;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -1005,7 +1008,7 @@ QList<NetworkId> PostgreSqlStorage::connectedNetworks(UserId user)
     watchQuery(query);
 
     while (query.next()) {
-        connectedNets << query.value(0).toInt();
+        connectedNets.emplace_back(query.value(0).toInt());
     }
 
     db.commit();
@@ -1207,9 +1210,9 @@ BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId& bufferI
     return bufferInfo;
 }
 
-QList<BufferInfo> PostgreSqlStorage::requestBuffers(UserId user)
+std::vector<BufferInfo> PostgreSqlStorage::requestBuffers(UserId user)
 {
-    QList<BufferInfo> bufferlist;
+    std::vector<BufferInfo> bufferlist;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -1225,19 +1228,19 @@ QList<BufferInfo> PostgreSqlStorage::requestBuffers(UserId user)
     safeExec(query);
     watchQuery(query);
     while (query.next()) {
-        bufferlist << BufferInfo(query.value(0).toInt(),
-                                 query.value(1).toInt(),
-                                 (BufferInfo::Type)query.value(2).toInt(),
-                                 query.value(3).toInt(),
-                                 query.value(4).toString());
+        bufferlist.emplace_back(query.value(0).toInt(),
+                                query.value(1).toInt(),
+                                (BufferInfo::Type)query.value(2).toInt(),
+                                query.value(3).toInt(),
+                                query.value(4).toString());
     }
     db.commit();
     return bufferlist;
 }
 
-QList<BufferId> PostgreSqlStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId)
+std::vector<BufferId> PostgreSqlStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId)
 {
-    QList<BufferId> bufferList;
+    std::vector<BufferId> bufferList;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -1254,7 +1257,7 @@ QList<BufferId> PostgreSqlStorage::requestBufferIdsForNetwork(UserId user, Netwo
     safeExec(query);
     watchQuery(query);
     while (query.next()) {
-        bufferList << BufferId(query.value(0).toInt());
+        bufferList.emplace_back(query.value(0).toInt());
     }
     db.commit();
     return bufferList;
@@ -1752,9 +1755,9 @@ bool PostgreSqlStorage::logMessages(MessageList& msgs)
     return true;
 }
 
-QList<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit)
+std::vector<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -1813,17 +1816,17 @@ QList<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, Ms
                     query.value(7).toString(),
                     (Message::Flags)query.value(3).toInt());
         msg.setMsgId(query.value(0).toLongLong());
-        messagelist << msg;
+        messagelist.push_back(std::move(msg));
     }
 
     db.commit();
     return messagelist;
 }
 
-QList<Message> PostgreSqlStorage::requestMsgsFiltered(
+std::vector<Message> PostgreSqlStorage::requestMsgsFiltered(
     UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     QSqlDatabase db = logDb();
     if (!beginReadOnlyTransaction(db)) {
@@ -1881,16 +1884,16 @@ QList<Message> PostgreSqlStorage::requestMsgsFiltered(
                     query.value(7).toString(),
                     Message::Flags{query.value(3).toInt()});
         msg.setMsgId(query.value(0).toLongLong());
-        messagelist << msg;
+        messagelist.push_back(std::move(msg));
     }
 
     db.commit();
     return messagelist;
 }
 
-QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
+std::vector<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     // requestBuffers uses it's own transaction.
     QHash<BufferId, BufferInfo> bufferInfoHash;
@@ -1937,17 +1940,17 @@ QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId
                     query.value(8).toString(),
                     (Message::Flags)query.value(4).toInt());
         msg.setMsgId(query.value(0).toLongLong());
-        messagelist << msg;
+        messagelist.push_back(std::move(msg));
     }
 
     db.commit();
     return messagelist;
 }
 
-QList<Message> PostgreSqlStorage::requestAllMsgsFiltered(
+std::vector<Message> PostgreSqlStorage::requestAllMsgsFiltered(
     UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     // requestBuffers uses it's own transaction.
     QHash<BufferId, BufferInfo> bufferInfoHash;
@@ -2001,7 +2004,7 @@ QList<Message> PostgreSqlStorage::requestAllMsgsFiltered(
                     query.value(8).toString(),
                     Message::Flags{query.value(4).toInt()});
         msg.setMsgId(query.value(0).toLongLong());
-        messagelist << msg;
+        messagelist.push_back(std::move(msg));
     }
 
     db.commit();
index f93bf69..51ff090 100644 (file)
@@ -63,14 +63,14 @@ public slots:
     IdentityId createIdentity(UserId user, CoreIdentity& identity) override;
     bool updateIdentity(UserId user, const CoreIdentity& identity) override;
     void removeIdentity(UserId user, IdentityId identityId) override;
-    QList<CoreIdentity> identities(UserId user) override;
+    std::vector<CoreIdentity> identities(UserId user) override;
 
     /* Network handling */
     NetworkId createNetwork(UserId user, const NetworkInfo& info) override;
     bool updateNetwork(UserId user, const NetworkInfo& info) override;
     bool removeNetwork(UserId user, const NetworkId& networkId) override;
-    QList<NetworkInfo> networks(UserId user) override;
-    QList<NetworkId> connectedNetworks(UserId user) override;
+    std::vector<NetworkInfo> networks(UserId user) override;
+    std::vector<NetworkId> connectedNetworks(UserId user) override;
     void setNetworkConnected(UserId user, const NetworkId& networkId, bool isConnected) override;
 
     /* persistent channels */
@@ -87,8 +87,8 @@ public slots:
     /* Buffer handling */
     BufferInfo bufferInfo(UserId user, const NetworkId& networkId, BufferInfo::Type type, const QString& buffer = "", bool create = true) override;
     BufferInfo getBufferInfo(UserId user, const BufferId& bufferId) override;
-    QList<BufferInfo> requestBuffers(UserId user) override;
-    QList<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId) override;
+    std::vector<BufferInfo> requestBuffers(UserId user) override;
+    std::vector<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId) override;
     bool removeBuffer(const UserId& user, const BufferId& bufferId) override;
     bool renameBuffer(const UserId& user, const BufferId& bufferId, const QString& newName) override;
     bool mergeBuffersPermanently(const UserId& user, const BufferId& bufferId1, const BufferId& bufferId2) override;
@@ -108,21 +108,21 @@ public slots:
     /* Message handling */
     bool logMessage(Message& msg) override;
     bool logMessages(MessageList& msgs) override;
-    QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
-    QList<Message> requestMsgsFiltered(UserId user,
-                                       BufferId bufferId,
-                                       MsgId first = -1,
-                                       MsgId last = -1,
-                                       int limit = -1,
-                                       Message::Types type = Message::Types{-1},
-                                       Message::Flags flags = Message::Flags{-1}) override;
-    QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
-    QList<Message> requestAllMsgsFiltered(UserId user,
-                                          MsgId first = -1,
-                                          MsgId last = -1,
-                                          int limit = -1,
-                                          Message::Types type = Message::Types{-1},
-                                          Message::Flags flags = Message::Flags{-1}) override;
+    std::vector<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    std::vector<Message> requestMsgsFiltered(UserId user,
+                                             BufferId bufferId,
+                                             MsgId first = -1,
+                                             MsgId last = -1,
+                                             int limit = -1,
+                                             Message::Types type = Message::Types{-1},
+                                             Message::Flags flags = Message::Flags{-1}) override;
+    std::vector<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    std::vector<Message> requestAllMsgsFiltered(UserId user,
+                                                MsgId first = -1,
+                                                MsgId last = -1,
+                                                int limit = -1,
+                                                Message::Types type = Message::Types{-1},
+                                                Message::Flags flags = Message::Flags{-1}) override;
 
     /* Sysident handling */
     QMap<UserId, QString> getAllAuthUserNames() override;
index 5874013..1a75713 100644 (file)
 
 #include "sqlitestorage.h"
 
-#include <QtSql>
+#include <QByteArray>
+#include <QDataStream>
+#include <QLatin1String>
+#include <QVariant>
 
 #include "network.h"
 #include "quassel.h"
@@ -192,7 +195,7 @@ UserId SqliteStorage::addUser(const QString& user, const QString& password, cons
         lockForWrite();
         safeExec(query);
         if (query.lastError().isValid()
-            && query.lastError().number() == 19) {  // user already exists - sadly 19 seems to be the general constraint violation error...
+            && query.lastError().nativeErrorCode() == QLatin1String{"19"}) {  // user already exists - sadly 19 seems to be the general constraint violation error...
             db.rollback();
         }
         else {
@@ -647,9 +650,9 @@ void SqliteStorage::removeIdentity(UserId user, IdentityId identityId)
     unlock();
 }
 
-QList<CoreIdentity> SqliteStorage::identities(UserId user)
+std::vector<CoreIdentity> SqliteStorage::identities(UserId user)
 {
-    QList<CoreIdentity> identities;
+    std::vector<CoreIdentity> identities;
     QSqlDatabase db = logDb();
     db.transaction();
 
@@ -696,8 +699,8 @@ QList<CoreIdentity> SqliteStorage::identities(UserId user)
             while (nickQuery.next()) {
                 nicks << nickQuery.value(0).toString();
             }
-            identity.setNicks(nicks);
-            identities << identity;
+            identity.setNicks(std::move(nicks));
+            identities.push_back(std::move(identity));
         }
         db.commit();
     }
@@ -935,9 +938,9 @@ bool SqliteStorage::removeNetwork(UserId user, const NetworkId& networkId)
     return true;
 }
 
-QList<NetworkInfo> SqliteStorage::networks(UserId user)
+std::vector<NetworkInfo> SqliteStorage::networks(UserId user)
 {
-    QList<NetworkInfo> nets;
+    std::vector<NetworkInfo> nets;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1005,7 +1008,7 @@ QList<NetworkInfo> SqliteStorage::networks(UserId user)
                         servers << server;
                     }
                     net.serverList = servers;
-                    nets << net;
+                    nets.push_back(std::move(net));
                 }
             }
         }
@@ -1015,9 +1018,9 @@ QList<NetworkInfo> SqliteStorage::networks(UserId user)
     return nets;
 }
 
-QList<NetworkId> SqliteStorage::connectedNetworks(UserId user)
+std::vector<NetworkId> SqliteStorage::connectedNetworks(UserId user)
 {
-    QList<NetworkId> connectedNets;
+    std::vector<NetworkId> connectedNets;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1031,7 +1034,7 @@ QList<NetworkId> SqliteStorage::connectedNetworks(UserId user)
         watchQuery(query);
 
         while (query.next()) {
-            connectedNets << query.value(0).toInt();
+            connectedNets.emplace_back(query.value(0).toInt());
         }
         db.commit();
     }
@@ -1292,9 +1295,9 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId& bufferId)
     return bufferInfo;
 }
 
-QList<BufferInfo> SqliteStorage::requestBuffers(UserId user)
+std::vector<BufferInfo> SqliteStorage::requestBuffers(UserId user)
 {
-    QList<BufferInfo> bufferlist;
+    std::vector<BufferInfo> bufferlist;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1308,11 +1311,11 @@ QList<BufferInfo> SqliteStorage::requestBuffers(UserId user)
         safeExec(query);
         watchQuery(query);
         while (query.next()) {
-            bufferlist << BufferInfo(query.value(0).toInt(),
-                                     query.value(1).toInt(),
-                                     (BufferInfo::Type)query.value(2).toInt(),
-                                     query.value(3).toInt(),
-                                     query.value(4).toString());
+            bufferlist.emplace_back(query.value(0).toInt(),
+                                    query.value(1).toInt(),
+                                    (BufferInfo::Type)query.value(2).toInt(),
+                                    query.value(3).toInt(),
+                                    query.value(4).toString());
         }
         db.commit();
     }
@@ -1321,9 +1324,9 @@ QList<BufferInfo> SqliteStorage::requestBuffers(UserId user)
     return bufferlist;
 }
 
-QList<BufferId> SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId)
+std::vector<BufferId> SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId)
 {
-    QList<BufferId> bufferList;
+    std::vector<BufferId> bufferList;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1338,7 +1341,7 @@ QList<BufferId> SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId
         safeExec(query);
         watchQuery(query);
         while (query.next()) {
-            bufferList << BufferId(query.value(0).toInt());
+            bufferList.emplace_back(query.value(0).toInt());
         }
         db.commit();
     }
@@ -1409,7 +1412,7 @@ bool SqliteStorage::renameBuffer(const UserId& user, const BufferId& bufferId, c
 
         error = query.lastError().isValid();
         // unexepcted error occured (19 == constraint violation)
-        if (error && query.lastError().number() != 19) {
+        if (error && query.lastError().nativeErrorCode() != QLatin1String{"19"}) {
             watchQuery(query);
         }
         else {
@@ -1790,7 +1793,7 @@ bool SqliteStorage::logMessage(Message& msg)
 
         if (logMessageQuery.lastError().isValid()) {
             // constraint violation - must be NOT NULL constraint - probably the sender is missing...
-            if (logMessageQuery.lastError().number() == 19) {
+            if (logMessageQuery.lastError().nativeErrorCode() == QLatin1String{"19"}) {
                 QSqlQuery addSenderQuery(db);
                 addSenderQuery.prepare(queryString("insert_sender"));
                 addSenderQuery.bindValue(":sender", msg.sender());
@@ -1894,9 +1897,9 @@ bool SqliteStorage::logMessages(MessageList& msgs)
     return !error;
 }
 
-QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit)
+std::vector<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1963,7 +1966,7 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
                 query.value(7).toString(),
                 (Message::Flags)query.value(3).toInt());
             msg.setMsgId(query.value(0).toLongLong());
-            messagelist << msg;
+            messagelist.push_back(std::move(msg));
         }
     }
     db.commit();
@@ -1972,10 +1975,10 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
     return messagelist;
 }
 
-QList<Message> SqliteStorage::requestMsgsFiltered(
+std::vector<Message> SqliteStorage::requestMsgsFiltered(
     UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -2047,7 +2050,7 @@ QList<Message> SqliteStorage::requestMsgsFiltered(
                 query.value(7).toString(),
                 Message::Flags{query.value(3).toInt()});
             msg.setMsgId(query.value(0).toLongLong());
-            messagelist << msg;
+            messagelist.push_back(std::move(msg));
         }
     }
     db.commit();
@@ -2056,9 +2059,9 @@ QList<Message> SqliteStorage::requestMsgsFiltered(
     return messagelist;
 }
 
-QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
+std::vector<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -2110,7 +2113,7 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
                 query.value(8).toString(),
                 (Message::Flags)query.value(4).toInt());
             msg.setMsgId(query.value(0).toLongLong());
-            messagelist << msg;
+            messagelist.push_back(std::move(msg));
         }
     }
     db.commit();
@@ -2118,9 +2121,9 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
     return messagelist;
 }
 
-QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+std::vector<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
 {
-    QList<Message> messagelist;
+    std::vector<Message> messagelist;
 
     QSqlDatabase db = logDb();
     db.transaction();
@@ -2177,7 +2180,7 @@ QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M
                 query.value(8).toString(),
                 Message::Flags{query.value(4).toInt()});
             msg.setMsgId(query.value(0).toLongLong());
-            messagelist << msg;
+            messagelist.push_back(std::move(msg));
         }
     }
     db.commit();
@@ -2219,15 +2222,13 @@ bool SqliteStorage::safeExec(QSqlQuery& query, int retryCount)
     if (!query.lastError().isValid())
         return true;
 
-    switch (query.lastError().number()) {
-    case 5:  // SQLITE_BUSY         5   /* The database file is locked */
-             // fallthrough
-    case 6:  // SQLITE_LOCKED       6   /* A table in the database is locked */
+    QString nativeErrorCode = query.lastError().nativeErrorCode();
+
+    // SQLITE_BUSY         5   /* The database file is locked */
+    // SQLITE_LOCKED       6   /* A table in the database is locked */
+    if (nativeErrorCode == QLatin1String{"5"} || nativeErrorCode == QLatin1String{"6"}) {
         if (retryCount < _maxRetryCount)
             return safeExec(query, retryCount + 1);
-        break;
-    default:
-        ;
     }
     return false;
 }
index 31f18d3..30617a8 100644 (file)
@@ -20,6 +20,9 @@
 
 #pragma once
 
+#include <memory>
+
+#include <QReadWriteLock>
 #include <QSqlDatabase>
 
 #include "abstractsqlstorage.h"
@@ -64,14 +67,14 @@ public slots:
     IdentityId createIdentity(UserId user, CoreIdentity& identity) override;
     bool updateIdentity(UserId user, const CoreIdentity& identity) override;
     void removeIdentity(UserId user, IdentityId identityId) override;
-    QList<CoreIdentity> identities(UserId user) override;
+    std::vector<CoreIdentity> identities(UserId user) override;
 
     /* Network handling */
     NetworkId createNetwork(UserId user, const NetworkInfo& info) override;
     bool updateNetwork(UserId user, const NetworkInfo& info) override;
     bool removeNetwork(UserId user, const NetworkId& networkId) override;
-    QList<NetworkInfo> networks(UserId user) override;
-    QList<NetworkId> connectedNetworks(UserId user) override;
+    std::vector<NetworkInfo> networks(UserId user) override;
+    std::vector<NetworkId> connectedNetworks(UserId user) override;
     void setNetworkConnected(UserId user, const NetworkId& networkId, bool isConnected) override;
 
     /* persistent channels */
@@ -88,8 +91,8 @@ public slots:
     /* Buffer handling */
     BufferInfo bufferInfo(UserId user, const NetworkId& networkId, BufferInfo::Type type, const QString& buffer = "", bool create = true) override;
     BufferInfo getBufferInfo(UserId user, const BufferId& bufferId) override;
-    QList<BufferInfo> requestBuffers(UserId user) override;
-    QList<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId) override;
+    std::vector<BufferInfo> requestBuffers(UserId user) override;
+    std::vector<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId) override;
     bool removeBuffer(const UserId& user, const BufferId& bufferId) override;
     bool renameBuffer(const UserId& user, const BufferId& bufferId, const QString& newName) override;
     bool mergeBuffersPermanently(const UserId& user, const BufferId& bufferId1, const BufferId& bufferId2) override;
@@ -109,21 +112,21 @@ public slots:
     /* Message handling */
     bool logMessage(Message& msg) override;
     bool logMessages(MessageList& msgs) override;
-    QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
-    QList<Message> requestMsgsFiltered(UserId user,
-                                       BufferId bufferId,
-                                       MsgId first = -1,
-                                       MsgId last = -1,
-                                       int limit = -1,
-                                       Message::Types type = Message::Types{-1},
-                                       Message::Flags flags = Message::Flags{-1}) override;
-    QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
-    QList<Message> requestAllMsgsFiltered(UserId user,
-                                          MsgId first = -1,
-                                          MsgId last = -1,
-                                          int limit = -1,
-                                          Message::Types type = Message::Types{-1},
-                                          Message::Flags flags = Message::Flags{-1}) override;
+    std::vector<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    std::vector<Message> requestMsgsFiltered(UserId user,
+                                             BufferId bufferId,
+                                             MsgId first = -1,
+                                             MsgId last = -1,
+                                             int limit = -1,
+                                             Message::Types type = Message::Types{-1},
+                                             Message::Flags flags = Message::Flags{-1}) override;
+    std::vector<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    std::vector<Message> requestAllMsgsFiltered(UserId user,
+                                                MsgId first = -1,
+                                                MsgId last = -1,
+                                                int limit = -1,
+                                                Message::Types type = Message::Types{-1},
+                                                Message::Flags flags = Message::Flags{-1}) override;
 
     /* Sysident handling */
     QMap<UserId, QString> getAllAuthUserNames() override;
index e5d6e27..16e3f3e 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <QDateTime>
 
+#include "core.h"
 #include "quassel.h"
 
 #ifdef HAVE_SSL
@@ -199,6 +200,11 @@ bool SslServer::setCertificate(const QString& path, const QString& keyPath)
         return false;
     }
 
+    _certificateExpires = untestedCert.expiryDate();
+    if (_metricsServer) {
+        _metricsServer->setCertificateExpires(_certificateExpires);
+    }
+
     _isCertValid = true;
 
     // All keys are valid, update the externally visible copy used for new connections.
@@ -223,4 +229,11 @@ QSslKey SslServer::loadKey(QFile* keyFile)
     return key;
 }
 
+void SslServer::setMetricsServer(MetricsServer* metricsServer) {
+    _metricsServer = metricsServer;
+    if (_metricsServer) {
+        _metricsServer->setCertificateExpires(_certificateExpires);
+    }
+}
+
 #endif  // HAVE_SSL
index 8e91ddd..bd54202 100644 (file)
@@ -28,6 +28,8 @@
 #    include <QSslKey>
 #    include <QTcpServer>
 
+#    include "metricsserver.h"
+
 class SslServer : public QTcpServer
 {
     Q_OBJECT
@@ -52,6 +54,8 @@ public:
      */
     bool reloadCerts();
 
+    void setMetricsServer(MetricsServer* metricsServer);
+
 protected:
     void incomingConnection(qintptr socketDescriptor) override;
 
@@ -69,6 +73,8 @@ private:
     bool loadCerts();
     QSslKey loadKey(QFile* keyFile);
 
+    MetricsServer* _metricsServer{nullptr};
+
     QLinkedList<QTcpSocket*> _pendingConnections;
     QSslCertificate _cert;
     QSslKey _key;
@@ -78,6 +84,8 @@ private:
     // Used when reloading certificates later
     QString _sslCertPath;  /// Path to the certificate file
     QString _sslKeyPath;   /// Path to the private key file (may be in same file as above)
+
+    QDateTime _certificateExpires;
 };
 
 #endif  // HAVE_SSL
index b28a99f..4fdc848 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef STORAGE_H
-#define STORAGE_H
+#pragma once
 
-#include <QtCore>
+#include <vector>
+
+#include <QMap>
+#include <QObject>
+#include <QProcessEnvironment>
+#include <QString>
+#include <QVariant>
+#include <QVariantList>
 
 #include "coreidentity.h"
 #include "message.h"
@@ -194,7 +200,7 @@ public slots:
     virtual IdentityId createIdentity(UserId user, CoreIdentity& identity) = 0;
     virtual bool updateIdentity(UserId user, const CoreIdentity& identity) = 0;
     virtual void removeIdentity(UserId user, IdentityId identityId) = 0;
-    virtual QList<CoreIdentity> identities(UserId user) = 0;
+    virtual std::vector<CoreIdentity> identities(UserId user) = 0;
 
     /* Network handling */
 
@@ -228,7 +234,7 @@ public slots:
      *  \param user        The core user
      *  \return QList<NetworkInfo>.
      */
-    virtual QList<NetworkInfo> networks(UserId user) = 0;
+    virtual std::vector<NetworkInfo> networks(UserId user) = 0;
 
     //! Get a list of Networks to restore
     /** Return a list of networks the user was connected at the time of core shutdown
@@ -236,7 +242,7 @@ public slots:
      *
      *  \param user  The User Id in question
      */
-    virtual QList<NetworkId> connectedNetworks(UserId user) = 0;
+    virtual std::vector<NetworkId> connectedNetworks(UserId user) = 0;
 
     //! Update the connected state of a network
     /** \note This method is threadsafe
@@ -335,7 +341,7 @@ public slots:
      *  \param user  The user whose buffers we request
      *  \return A list of the BufferInfos for all buffers as requested
      */
-    virtual QList<BufferInfo> requestBuffers(UserId user) = 0;
+    virtual std::vector<BufferInfo> requestBuffers(UserId user) = 0;
 
     //! Request a list of BufferIds for a given NetworkId
     /** \note This method is threadsafe.
@@ -344,7 +350,7 @@ public slots:
      *  \param networkId  The NetworkId of the network in question
      *  \return List of BufferIds belonging to the Network
      */
-    virtual QList<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId) = 0;
+    virtual std::vector<BufferId> requestBufferIdsForNetwork(UserId user, NetworkId networkId) = 0;
 
     //! Remove permanently a buffer and it's content from the storage backend
     /** This call cannot be reverted!
@@ -498,7 +504,7 @@ public slots:
      *  \param limit    if != -1 limit the returned list to a max of \limit entries
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
+    virtual std::vector<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
     //! Request a certain number messages stored in a given buffer, matching certain filters
     /** \param buffer   The buffer we request messages from
@@ -508,14 +514,13 @@ public slots:
      *  \param type     The Message::Types that should be returned
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestMsgsFiltered(UserId user,
-                                               BufferId bufferId,
-                                               MsgId first = -1,
-                                               MsgId last = -1,
-                                               int limit = -1,
-                                               Message::Types type = Message::Types{-1},
-                                               Message::Flags flags = Message::Flags{-1})
-        = 0;
+    virtual std::vector<Message> requestMsgsFiltered(UserId user,
+                                                     BufferId bufferId,
+                                                     MsgId first = -1,
+                                                     MsgId last = -1,
+                                                     int limit = -1,
+                                                     Message::Types type = Message::Types{-1},
+                                                     Message::Flags flags = Message::Flags{-1}) = 0;
 
     //! Request a certain number of messages across all buffers
     /** \param first    if != -1 return only messages with a MsgId >= first
@@ -523,7 +528,7 @@ public slots:
      *  \param limit    Max amount of messages
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
+    virtual std::vector<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
     //! Request a certain number of messages across all buffers, matching certain filters
     /** \param first    if != -1 return only messages with a MsgId >= first
@@ -532,13 +537,12 @@ public slots:
      *  \param type     The Message::Types that should be returned
      *  \return The requested list of messages
      */
-    virtual QList<Message> requestAllMsgsFiltered(UserId user,
-                                                  MsgId first = -1,
-                                                  MsgId last = -1,
-                                                  int limit = -1,
-                                                  Message::Types type = Message::Types{-1},
-                                                  Message::Flags flags = Message::Flags{-1})
-        = 0;
+    virtual std::vector<Message> requestAllMsgsFiltered(UserId user,
+                                                        MsgId first = -1,
+                                                        MsgId last = -1,
+                                                        int limit = -1,
+                                                        Message::Types type = Message::Types{-1},
+                                                        Message::Flags flags = Message::Flags{-1}) = 0;
 
     //! Fetch all authusernames
     /** \return      Map of all current UserIds to permitted idents
@@ -572,5 +576,3 @@ private:
     bool checkHashedPasswordSha2_512(const QString& password, const QString& hashedPassword);
     QString sha2_512(const QString& input);
 };
-
-#endif
index daee316..aa54ddf 100644 (file)
@@ -30,7 +30,11 @@ class InternalPeer;
 
 MonolithicApplication::MonolithicApplication(int& argc, char** argv)
     : QtUiApplication(argc, argv)
-{}
+{
+#if QT_VERSION >= 0x050700
+    QGuiApplication::setDesktopFileName(Quassel::buildInfo().applicationName);
+#endif
+}
 
 void MonolithicApplication::init()
 {
index eee27cb..034d6c6 100644 (file)
@@ -24,7 +24,6 @@ target_sources(${TARGET} PRIVATE
     coreinfodlg.cpp
     coresessionwidget.cpp
     debugbufferviewoverlay.cpp
-    debugconsole.cpp
     debuglogdlg.cpp
     debugmessagemodelfilter.cpp
     inputwidget.cpp
@@ -71,7 +70,6 @@ target_sources(${TARGET} PRIVATE
     coreinfodlg.ui
     coresessionwidget.ui
     debugbufferviewoverlay.ui
-    debugconsole.ui
     debuglogdlg.ui
     inputwidget.ui
     msgprocessorstatuswidget.ui
index 1f4897a..913c81e 100644 (file)
@@ -142,11 +142,12 @@ void ChatItem::initLayoutHelper(QTextLayout* layout, QTextOption::WrapMode wrapM
     option.setAlignment(alignment);
     layout->setTextOption(option);
 
-    QList<QTextLayout::FormatRange> formatRanges = QtUi::style()
-                                                       ->toTextLayoutList(formatList(),
-                                                                          layout->text().length(),
-                                                                          data(ChatLineModel::MsgLabelRole).value<UiStyle::MessageLabel>());
-    layout->setAdditionalFormats(formatRanges);
+    UiStyle::FormatContainer formatRanges = QtUi::style()->toTextLayoutList(
+        formatList(),
+        layout->text().length(),
+        data(ChatLineModel::MsgLabelRole).value<UiStyle::MessageLabel>()
+    );
+    UiStyle::setTextLayoutFormats(*layout, formatRanges);
 }
 
 void ChatItem::initLayout(QTextLayout* layout) const
@@ -347,16 +348,16 @@ QVector<QTextLayout::FormatRange> ChatItem::additionalFormats() const
     }
 
     // Add all formats that have an extra label to the additionalFormats list
-    QList<QTextLayout::FormatRange> additionalFormats;
+    UiStyle::FormatContainer additionalFormats;
     for (size_t i = 0; i < labelFmtList.size() - 1; ++i) {
         if (labelFmtList[i].label != itemLabel) {
             additionalFormats << QtUi::style()->toTextLayoutList({std::make_pair(labelFmtList[i].offset, labelFmtList[i].format)},
-                                                                 labelFmtList[i + 1].offset,
-                                                                 labelFmtList[i].label);
+                                                                   labelFmtList[i + 1].offset,
+                                                                   labelFmtList[i].label);
         }
     }
 
-    return additionalFormats.toVector();
+    return UiStyle::containerToVector(additionalFormats);
 }
 
 bool ChatItem::hasSelection() const
index 22dd9a7..80b0d56 100644 (file)
 
 #include "chatline.h"
 
+#include <QAbstractItemModel>
 #include <QDateTime>
 #include <QGraphicsSceneMouseEvent>
+#include <QGraphicsSceneHoverEvent>
+#include <QPainter>
 #include <QString>
-#include <QtGui>
+#include <QStyleOptionGraphicsItem>
+#include <QTextCharFormat>
+
+class QAbstractItemModel;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneHoverEvent;
+class QPainter;
+class QStyleOptionGraphicsItem;
 
 #include "bufferinfo.h"
 #include "buffersyncer.h"
@@ -47,9 +57,8 @@ ChatLine::ChatLine(int row,
                    const QPointF& contentsPos,
                    QGraphicsItem* parent)
     : QGraphicsItem(parent)
-    , _row(row)
-    ,  // needs to be set before the items
-    _model(model)
+    , _row(row) // needs to be set before the items
+    , _model(model)
     , _contentsItem(contentsPos, contentsWidth, this)
     , _senderItem(QRectF(senderPos, QSizeF(senderWidth, _contentsItem.height())), this)
     , _timestampItem(QRectF(0, 0, timestampWidth, _contentsItem.height()), this)
index 4ca4ba1..2f22edc 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef CHATLINE_H_
-#define CHATLINE_H_
+#pragma once
 
 #include <QGraphicsItem>
+#include <QModelIndex>
+#include <QRectF>
 
 #include "chatitem.h"
 #include "chatlinemodel.h"
 #include "chatscene.h"
 
+class QAbstractItemModel;
+class QEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneHoverEvent;
+class QPainter;
+class QStyleOptionGraphicsItem;
+
 class ChatLine : public QGraphicsItem
 {
 public:
@@ -122,5 +130,3 @@ private:
     ChatItem* _mouseGrabberItem;
     ChatItem* _hoverItem;
 };
-
-#endif
index a8e1ae0..9ebc126 100644 (file)
@@ -200,7 +200,7 @@ void ChatLineModelItem::computeWrapList() const
     option.setWrapMode(QTextOption::NoWrap);
     layout.setTextOption(option);
 
-    layout.setAdditionalFormats(QtUi::style()->toTextLayoutList(_styledMsg.contentsFormatList(), length, messageLabel()));
+    UiStyle::setTextLayoutFormats(layout, QtUi::style()->toTextLayoutList(_styledMsg.contentsFormatList(), length, messageLabel()));
     layout.beginLayout();
     QTextLine line = layout.createLine();
     line.setNumColumns(length);
index 3a432bf..da331b6 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "chatview.h"
 
+#include <algorithm>
+
 #include <QGraphicsTextItem>
 #include <QKeyEvent>
 #include <QMenu>
@@ -292,7 +294,7 @@ QSet<ChatLine*> ChatView::visibleChatLines(Qt::ItemSelectionMode mode) const
 QList<ChatLine*> ChatView::visibleChatLinesSorted(Qt::ItemSelectionMode mode) const
 {
     QList<ChatLine*> result = visibleChatLines(mode).toList();
-    qSort(result.begin(), result.end(), chatLinePtrLessThan);
+    std::sort(result.begin(), result.end(), chatLinePtrLessThan);
     return result;
 }
 
index b81e261..57ca2c0 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "chatviewsearchcontroller.h"
 
+#include <algorithm>
+
 #include <QAbstractItemModel>
 #include <QPainter>
 
@@ -330,7 +332,7 @@ void ChatViewSearchController::repositionHighlights(ChatLine* line)
         }
     }
 
-    qSort(searchHighlights.begin(), searchHighlights.end(), SearchHighlightItem::firstInLine);
+    std::sort(searchHighlights.begin(), searchHighlights.end(), SearchHighlightItem::firstInLine);
 
     Q_ASSERT(wordPos.count() == searchHighlights.count());
     for (int i = 0; i < searchHighlights.count(); i++) {
diff --git a/src/qtui/debugconsole.ui b/src/qtui/debugconsole.ui
deleted file mode 100644 (file)
index aa0dc34..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DebugConsole</class>
- <widget class="QDialog" name="DebugConsole">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>490</width>
-    <height>435</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Debug Console</string>
-  </property>
-  <layout class="QVBoxLayout">
-   <property name="spacing">
-    <number>2</number>
-   </property>
-   <property name="margin">
-    <number>3</number>
-   </property>
-   <item>
-    <layout class="QHBoxLayout">
-     <property name="spacing">
-      <number>10</number>
-     </property>
-     <item>
-      <spacer>
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item>
-      <widget class="QRadioButton" name="selectLocal">
-       <property name="text">
-        <string>local</string>
-       </property>
-       <property name="checked">
-        <bool>false</bool>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QRadioButton" name="selectCore">
-       <property name="text">
-        <string>core</string>
-       </property>
-       <property name="checked">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <spacer>
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="QTextEdit" name="scriptEdit"/>
-   </item>
-   <item>
-    <widget class="QPushButton" name="evalButton">
-     <property name="text">
-      <string>Evaluate!</string>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QLabel" name="resultLabel">
-     <property name="text">
-      <string/>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>selectLocal</tabstop>
-  <tabstop>selectCore</tabstop>
-  <tabstop>scriptEdit</tabstop>
-  <tabstop>evalButton</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
index a3415d5..5282bd7 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <KNotifications/KNotification>
 #include <KNotifyConfig/KNotifyConfigWidget>
+#include <knotifications_version.h>
 
 #include "client.h"
 #include "icon.h"
@@ -65,7 +66,7 @@ void KNotificationBackend::notify(const Notification& n)
     QString message = QString("<b>&lt;%1&gt;</b> %2").arg(n.sender, n.message.toHtmlEscaped());
     KNotification* notification = KNotification::event(type,
                                                        message,
-                                                       icon::get("dialog-information").pixmap(48),
+                                                       QStringLiteral("dialog-information"),
                                                        QtUi::mainWindow(),
                                                        KNotification::RaiseWidgetOnActivation | KNotification::CloseWhenWidgetActivated
                                                            | KNotification::CloseOnTimeout);
@@ -73,7 +74,11 @@ void KNotificationBackend::notify(const Notification& n)
             selectOverload<uint>(&KNotification::activated),
             this,
             selectOverload<>(&KNotificationBackend::notificationActivated));
-    notification->setActions(QStringList("View"));
+#if KNOTIFICATIONS_VERSION >= QT_VERSION_CHECK(5,31,0)
+    notification->setDefaultAction(tr("View"));
+#else
+    notification->setActions(QStringList{tr("View")});
+#endif
     notification->setProperty("notificationId", n.notificationId);
 
     _notifications.append(qMakePair(n.notificationId, QPointer<KNotification>(notification)));
index 2b43a7e..5b0118a 100644 (file)
@@ -1195,7 +1195,8 @@ void MainWin::saveMainToolBarStatus(bool enabled)
 
 void MainWin::doAutoConnect()
 {
-    if (!Client::coreConnection()->connectToCore()) {
+    int accountId = Quassel::optionValue("account").toInt();
+    if (!Client::coreConnection()->connectToCore(accountId)) {
         // No autoconnect selected (or no accounts)
         showCoreConnectionDlg();
     }
index fed4911..6ee4752 100644 (file)
@@ -177,7 +177,7 @@ void NickListWidget::rowsAboutToBeRemoved(const QModelIndex& parent, int start,
     else {
         // check if there are explicitly buffers removed
         for (int i = start; i <= end; i++) {
-            QVariant variant = parent.child(i, 0).data(NetworkModel::BufferIdRole);
+            QVariant variant = parent.model()->index(i, 0, parent).data(NetworkModel::BufferIdRole);
             if (!variant.isValid())
                 continue;
 
index 4685d51..b7e8e8c 100644 (file)
@@ -36,6 +36,9 @@ QtUiApplication::QtUiApplication(int& argc, char** argv)
 #if QT_VERSION >= 0x050600
     QGuiApplication::setFallbackSessionManagementEnabled(false);
 #endif
+#if QT_VERSION >= 0x050700
+    QGuiApplication::setDesktopFileName(Quassel::buildInfo().clientApplicationName);
+#endif
 }
 
 void QtUiApplication::init()
index 937b842..55d2acf 100644 (file)
@@ -53,7 +53,7 @@ AppearanceSettingsPage::AppearanceSettingsPage(QWidget* parent)
     initIconThemeComboBox();
 
     foreach (QComboBox* comboBox, findChildren<QComboBox*>()) {
-        connect(comboBox, selectOverload<const QString&>(&QComboBox::currentIndexChanged), this, &AppearanceSettingsPage::widgetHasChanged);
+        connect(comboBox, &QComboBox::currentTextChanged, this, &AppearanceSettingsPage::widgetHasChanged);
     }
     foreach (QCheckBox* checkBox, findChildren<QCheckBox*>()) {
         connect(checkBox, &QAbstractButton::clicked, this, &AppearanceSettingsPage::widgetHasChanged);
index 1097dff..37214cd 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "bufferviewsettingspage.h"
 
+#include <algorithm>
 #include <utility>
 
 #include <QMessageBox>
@@ -248,7 +249,7 @@ void BufferViewSettingsPage::newBufferView(const QString& bufferViewName)
         }
         else {
             bufferIds = Client::networkModel()->allBufferIds();
-            qSort(bufferIds);
+            std::sort(bufferIds.begin(), bufferIds.end());
             config->setProperty("OriginalBufferList", toVariantList<BufferId>(bufferIds));
         }
     }
index 9707c70..e07c87d 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "corehighlightsettingspage.h"
 
+#include <algorithm>
+
 #include <QHeaderView>
 #include <QMessageBox>
 #include <QTableWidget>
@@ -420,7 +422,7 @@ void CoreHighlightSettingsPage::removeSelectedHighlightRows()
     for (auto selectedItem : selectedItemList) {
         selectedRows.append(selectedItem->row());
     }
-    qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
+    std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
     int lastRow = -1;
     for (auto row : selectedRows) {
         if (row != lastRow) {
@@ -438,7 +440,7 @@ void CoreHighlightSettingsPage::removeSelectedIgnoredRows()
     for (auto selectedItem : selectedItemList) {
         selectedRows.append(selectedItem->row());
     }
-    qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
+    std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
     int lastRow = -1;
     for (auto row : selectedRows) {
         if (row != lastRow) {
index 1a6a51a..af0af1f 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "highlightsettingspage.h"
 
+#include <algorithm>
+
 #include <QHeaderView>
 #include <QMessageBox>
 
@@ -197,7 +199,7 @@ void HighlightSettingsPage::removeSelectedRows()
     foreach (QTableWidgetItem* selectedItem, selectedItemList) {
         selectedRows.append(selectedItem->row());
     }
-    qSort(selectedRows.begin(), selectedRows.end(), qGreater<int>());
+    std::sort(selectedRows.begin(), selectedRows.end(), std::greater<>());
     int lastRow = -1;
     foreach (int row, selectedRows) {
         if (row != lastRow) {
index 02453c7..e4136e0 100644 (file)
@@ -28,7 +28,6 @@
 
 ItemViewSettingsPage::ItemViewSettingsPage(QWidget* parent)
     : SettingsPage(tr("Interface"), tr("Chat & Nick Lists"), parent)
-    , _mapper(new QSignalMapper(this))
 {
     ui.setupUi(this);
 
@@ -43,11 +42,11 @@ ItemViewSettingsPage::ItemViewSettingsPage(QWidget* parent)
 
     ui.bufferViewPreview->expandAll();
 
-    foreach (ColorButton* button, findChildren<ColorButton*>()) {
-        connect(button, &ColorButton::colorChanged, _mapper, selectOverload<>(&QSignalMapper::map));
-        _mapper->setMapping(button, button);
+    for (ColorButton* button : findChildren<ColorButton*>()) {
+        connect(button, &ColorButton::colorChanged, button, [this, button]() {
+            updateBufferViewPreview(button);
+        });
     }
-    connect(_mapper, selectOverload<QWidget*>(&QSignalMapper::mapped), this, &ItemViewSettingsPage::updateBufferViewPreview);
 
     initAutoWidgets();
 }
index 8b141e2..794a7e3 100644 (file)
@@ -46,7 +46,6 @@ private slots:
 
 private:
     Ui::ItemViewSettingsPage ui;
-    QSignalMapper* _mapper;
     QTreeWidgetItem *_networkItem, *_defaultBufferItem, *_inactiveBufferItem, *_activeBufferItem, *_unreadBufferItem, *_highlightedBufferItem;
 
     inline QString settingsKey() const override { return QString("ItemViews"); }
index f986c0b..ee34905 100644 (file)
@@ -47,7 +47,7 @@ void AbstractBufferContainer::rowsAboutToBeRemoved(const QModelIndex& parent, in
     else {
         // check if there are explicitly buffers removed
         for (int i = start; i <= end; i++) {
-            QVariant variant = parent.child(i, 0).data(NetworkModel::BufferIdRole);
+            QVariant variant = parent.model()->index(i, 0, parent).data(NetworkModel::BufferIdRole);
             if (!variant.isValid())
                 continue;
 
index a17c1a0..f603bf5 100644 (file)
@@ -494,13 +494,13 @@ void BufferView::changeBuffer(Direction direction)
             if (currentIndex.row() == 0)
                 newParent = lastNetIndex;
             if (model()->hasChildren(newParent))
-                resultingIndex = newParent.child(model()->rowCount(newParent) - 1, 0);
+                resultingIndex = newParent.model()->index(model()->rowCount(newParent) - 1, 0, newParent);
             else
                 resultingIndex = newParent;
         }
         else {
             if (model()->hasChildren(currentIndex))
-                resultingIndex = currentIndex.child(0, 0);
+                resultingIndex = currentIndex.model()->index(0, 0, currentIndex);
             else
                 resultingIndex = currentIndex.sibling(currentIndex.row() + 1, 0);
         }
@@ -510,7 +510,7 @@ void BufferView::changeBuffer(Direction direction)
         if (direction == Forward)
             resultingIndex = model()->index(0, 0, QModelIndex());
         else
-            resultingIndex = lastNetIndex.child(model()->rowCount(lastNetIndex) - 1, 0);
+            resultingIndex = lastNetIndex.model()->index(model()->rowCount(lastNetIndex) - 1, 0, lastNetIndex);
     }
 
     selectionModel()->setCurrentIndex(resultingIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
index 3bb42f8..5058de7 100644 (file)
@@ -44,7 +44,7 @@ bool NickViewFilter::filterAcceptsRow(int source_row, const QModelIndex& source_
     if (!source_parent.isValid())
         return true;
 
-    QModelIndex source_child = source_parent.child(source_row, 0);
+    QModelIndex source_child = source_parent.model()->index(source_row, 0, source_parent);
     return (sourceModel()->data(source_child, NetworkModel::BufferIdRole).value<BufferId>() == _bufferId);
 }
 
index 78973fc..f54bea8 100644 (file)
@@ -110,10 +110,8 @@ void StyledLabel::updateSizeHint()
 
 void StyledLabel::setText(const QString& text)
 {
-    UiStyle* style = GraphicalUi::uiStyle();
-
-    UiStyle::StyledString sstr = style->styleString(style->mircToInternal(text), UiStyle::FormatType::PlainMsg);
-    QList<QTextLayout::FormatRange> layoutList = style->toTextLayoutList(sstr.formatList, sstr.plainText.length(), UiStyle::MessageLabel::None);
+    UiStyle::StyledString sstr = UiStyle::styleString(UiStyle::mircToInternal(text), UiStyle::FormatType::PlainMsg);
+    UiStyle::FormatContainer layoutList = GraphicalUi::uiStyle()->toTextLayoutList(sstr.formatList, sstr.plainText.length(), UiStyle::MessageLabel::None);
 
     // Use default font rather than the style's
     QTextLayout::FormatRange fmtRange;
@@ -135,7 +133,7 @@ void StyledLabel::setText(const QString& text)
     }
 
     _layout.setText(sstr.plainText);
-    _layout.setAdditionalFormats(layoutList);
+    UiStyle::setTextLayoutFormats(_layout, layoutList);
 
     layout();
 
index 6e0291c..19f6e16 100644 (file)
@@ -583,9 +583,9 @@ QString UiStyle::formatCode(FormatType ftype)
     return _formatCodes.key(ftype);
 }
 
-QList<QTextLayout::FormatRange> UiStyle::toTextLayoutList(const FormatList& formatList, int textLength, MessageLabel messageLabel) const
+UiStyle::FormatContainer UiStyle::toTextLayoutList(const FormatList& formatList, int textLength, MessageLabel messageLabel) const
 {
-    QList<QTextLayout::FormatRange> formatRanges;
+    UiStyle::FormatContainer formatRanges;
     QTextLayout::FormatRange range;
     size_t i = 0;
     for (i = 0; i < formatList.size(); i++) {
index d1308fd..888abcd 100644 (file)
@@ -49,6 +49,28 @@ public:
     UiStyle(QObject* parent = nullptr);
     ~UiStyle() override;
 
+// For backwards compatibility with Qt 5.5, the setFormats method was introduced
+// in Qt 5.6, but the old setAdditionalFormats was deprecated in 5.6 as well.
+//
+// So we use the old one on Qt 5.5, and the new one everywhere else.
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+    using FormatContainer = QVector<QTextLayout::FormatRange>;
+    static inline void setTextLayoutFormats(QTextLayout& layout, const FormatContainer& formats) {
+        layout.setFormats(formats);
+    }
+    static inline QVector<QTextLayout::FormatRange> containerToVector(const FormatContainer& container) {
+        return container;
+    }
+#else
+    using FormatContainer = QList<QTextLayout::FormatRange>;
+    static inline void setTextLayoutFormats(QTextLayout& layout, const FormatContainer& formats) {
+        layout.setAdditionalFormats(formats);
+    }
+    static inline QVector<QTextLayout::FormatRange> containerToVector(const FormatContainer& container) {
+        return container.toVector();
+    }
+#endif
+
     //! This enumerates the possible formats a text element may have. */
     /** These formats are ordered on increasing importance, in cases where a given property is specified
      *  by multiple active formats.
@@ -275,7 +297,7 @@ public:
     QTextCharFormat format(const Format& format, MessageLabel messageLabel) const;
     QFontMetricsF* fontMetrics(FormatType formatType, MessageLabel messageLabel) const;
 
-    QList<QTextLayout::FormatRange> toTextLayoutList(const FormatList&, int textLength, MessageLabel messageLabel) const;
+    FormatContainer toTextLayoutList(const FormatList&, int textLength, MessageLabel messageLabel) const;
 
     inline const QBrush& brush(ColorRole role) const { return _uiStylePalette.at((int)role); }
     inline void setBrush(ColorRole role, const QBrush& brush) { _uiStylePalette[(int)role] = brush; }
index 9ca7d4f..f031977 100644 (file)
@@ -10,3 +10,5 @@ quassel_add_test(SignalProxyTest
     LIBRARIES
         Quassel::Test::Util
 )
+
+quassel_add_test(UtilTest)
similarity index 64%
rename from src/qtui/debugconsole.cpp
rename to tests/common/utiltest.cpp
index 8f7c758..a3f0722 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#include "debugconsole.h"
+#include <QDebug>
+#include <QDateTime>
+#include <QTimeZone>
 
-#include "client.h"
-#include "signalproxy.h"
+#include "testglobal.h"
+#include "util.h"
 
-DebugConsole::DebugConsole(QWidget* parent)
-    : QDialog(parent)
+TEST(UtilTest, formatDateTimeToOffsetISO)
 {
-    ui.setupUi(this);
+    QDateTime dateTime{{2006, 01, 02}, {15, 04, 05}, QTimeZone{"UTC+01:00"}};
 
-    Client::signalProxy()->attachSignal(this, &DebugConsole::scriptRequest);
-    Client::signalProxy()->attachSlot(SIGNAL(scriptResult(QString)), this, &DebugConsole::scriptResult);
-}
+    ASSERT_TRUE(dateTime.isValid());
+    ASSERT_FALSE(dateTime.isNull());
 
-void DebugConsole::on_evalButton_clicked()
-{
-    if (ui.selectCore->isChecked()) {
-        emit scriptRequest(ui.scriptEdit->toPlainText());
-    }
-}
-
-void DebugConsole::scriptResult(QString result)
-{
-    ui.resultLabel->setText(result);
+    EXPECT_EQ(formatDateTimeToOffsetISO(dateTime), QString("2006-01-02 15:04:05+01:00"));
+    EXPECT_EQ(formatDateTimeToOffsetISO(dateTime.toUTC()), QString("2006-01-02 14:04:05Z"));
+    EXPECT_EQ(formatDateTimeToOffsetISO(dateTime.toOffsetFromUtc(0)), QString("2006-01-02 14:04:05Z"));
+    EXPECT_EQ(formatDateTimeToOffsetISO(dateTime.toOffsetFromUtc(7200)), QString("2006-01-02 16:04:05+02:00"));
+    EXPECT_EQ(formatDateTimeToOffsetISO(dateTime.toTimeZone(QTimeZone{"UTC"})), QString("2006-01-02 14:04:05Z"));
 }