qa: Resolve deprecation warnings in newer Qt versions
[quassel.git] / src / core / postgresqlstorage.cpp
index 3c15b2c..030423f 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   Copyright (C) 2005-2020 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 
 #include "postgresqlstorage.h"
 
-#include <QtSql>
+#include <QByteArray>
+#include <QDataStream>
+#include <QSqlDriver>
+#include <QSqlField>
 
-#include "logger.h"
 #include "network.h"
 #include "quassel.h"
 
-PostgreSqlStorage::PostgreSqlStorage(QObject *parent)
-    : AbstractSqlStorage(parent),
-    _port(-1)
-{
-}
-
-
-PostgreSqlStorage::~PostgreSqlStorage()
-{
-}
-
+PostgreSqlStorage::PostgreSqlStorage(QObject* parent)
+    : AbstractSqlStorage(parent)
+{}
 
 std::unique_ptr<AbstractSqlMigrationWriter> PostgreSqlStorage::createMigrationWriter()
 {
@@ -47,55 +41,45 @@ std::unique_ptr<AbstractSqlMigrationWriter> PostgreSqlStorage::createMigrationWr
     properties["Hostname"] = _hostName;
     properties["Port"] = _port;
     properties["Database"] = _databaseName;
-    writer->setConnectionProperties(properties);
+    writer->setConnectionProperties(properties, {}, false);
     return std::unique_ptr<AbstractSqlMigrationWriter>{writer};
 }
 
-
 bool PostgreSqlStorage::isAvailable() const
 {
     if (!QSqlDatabase::isDriverAvailable("QPSQL")) {
-        quWarning() << qPrintable(tr("PostgreSQL driver plugin not available for Qt. Installed drivers:"))
-                    << qPrintable(QSqlDatabase::drivers().join(", "));
+        qWarning() << qPrintable(tr("PostgreSQL driver plugin not available for Qt. Installed drivers:"))
+                   << qPrintable(QSqlDatabase::drivers().join(", "));
         return false;
     }
     return true;
 }
 
-
 QString PostgreSqlStorage::backendId() const
 {
     return QString("PostgreSQL");
 }
 
-
 QString PostgreSqlStorage::displayName() const
 {
-    return backendId(); // Note: Pre-0.13 clients use the displayName property for backend idenfication
+    return backendId();  // Note: Pre-0.13 clients use the displayName property for backend idenfication
 }
 
-
 QString PostgreSqlStorage::description() const
 {
     // FIXME: proper description
     return tr("PostgreSQL Turbo Bomber HD!");
 }
 
-
 QVariantList PostgreSqlStorage::setupData() const
 {
     QVariantList data;
-    data << "Username" << tr("Username") << QString("quassel")
-         << "Password" << tr("Password") << QString()
-         << "Hostname" << tr("Hostname") << QString("localhost")
-         << "Port"     << tr("Port")     << 5432
-         << "Database" << tr("Database") << QString("quassel")
-         ;
+    data << "Username" << tr("Username") << QString("quassel") << "Password" << tr("Password") << QString() << "Hostname" << tr("Hostname")
+         << QString("localhost") << "Port" << tr("Port") << 5432 << "Database" << tr("Database") << QString("quassel");
     return data;
 }
 
-
-bool PostgreSqlStorage::initDbSession(QSqlDatabase &db)
+bool PostgreSqlStorage::initDbSession(QSqlDatabase& db)
 {
     // check whether the Qt driver performs string escaping or not.
     // i.e. test if it doubles slashes.
@@ -103,14 +87,14 @@ bool PostgreSqlStorage::initDbSession(QSqlDatabase &db)
     testField.setType(QVariant::String);
     testField.setValue("\\");
     QString formattedString = db.driver()->formatValue(testField);
-    switch(formattedString.count('\\')) {
+    switch (formattedString.count('\\')) {
     case 2:
         // yes it does... and we cannot do anything to change the behavior of Qt.
         // If this is a legacy DB (Postgres < 8.2), then everything is already ok,
         // as this is the expected behavior.
         // If it is a newer version, switch to legacy mode.
 
-        quWarning() << "Switching Postgres to legacy mode. (set standard conforming strings to off)";
+        qWarning() << "Switching Postgres to legacy mode. (set standard conforming strings to off)";
         // If the following calls fail, it is a legacy DB anyways, so it doesn't matter
         // and no need to check the outcome.
         db.exec("set standard_conforming_strings = off");
@@ -124,14 +108,15 @@ bool PostgreSqlStorage::initDbSession(QSqlDatabase &db)
             if (query.lastError().isValid()) {
                 // We cannot enable standard conforming strings...
                 // since Quassel does no escaping by itself, this would yield a major vulnerability.
-                quError() << "Failed to enable standard_conforming_strings for the Postgres db!";
+                qCritical() << "Failed to enable standard_conforming_strings for the Postgres db!";
                 return false;
             }
         }
         break;
     default:
         // The slash got replaced with 0 or more than 2 slashes! o_O
-        quError() << "Your version of Qt does something _VERY_ strange to slashes in QSqlQueries! You should consult your trusted doctor!";
+        qCritical()
+            << "Your version of Qt does something _VERY_ strange to slashes in QSqlQueries! You should consult your trusted doctor!";
         return false;
         break;
     }
@@ -139,24 +124,31 @@ bool PostgreSqlStorage::initDbSession(QSqlDatabase &db)
     // Set the PostgreSQL session timezone to UTC, since we want timestamps stored in UTC
     QSqlQuery tzQuery = db.exec("SET timezone = 'UTC'");
     if (tzQuery.lastError().isValid()) {
-        quError() << "Failed to set timezone to UTC!";
+        qCritical() << "Failed to set timezone to UTC!";
         return false;
     }
 
     return true;
 }
 
-
-void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties)
+void PostgreSqlStorage::setConnectionProperties(const QVariantMap& properties, const QProcessEnvironment& environment, bool loadFromEnvironment)
 {
-    _userName = properties["Username"].toString();
-    _password = properties["Password"].toString();
-    _hostName = properties["Hostname"].toString();
-    _port = properties["Port"].toInt();
-    _databaseName = properties["Database"].toString();
+    if (loadFromEnvironment) {
+        _userName = environment.value("DB_PGSQL_USERNAME");
+        _password = environment.value("DB_PGSQL_PASSWORD");
+        _hostName = environment.value("DB_PGSQL_HOSTNAME");
+        _port = environment.value("DB_PGSQL_PORT").toInt();
+        _databaseName = environment.value("DB_PGSQL_DATABASE");
+    }
+    else {
+        _userName = properties["Username"].toString();
+        _password = properties["Password"].toString();
+        _hostName = properties["Hostname"].toString();
+        _port = properties["Port"].toInt();
+        _databaseName = properties["Database"].toString();
+    }
 }
 
-
 int PostgreSqlStorage::installedSchemaVersion()
 {
     QSqlQuery query(logDb());
@@ -176,22 +168,40 @@ int PostgreSqlStorage::installedSchemaVersion()
     return AbstractSqlStorage::installedSchemaVersion();
 }
 
-
-bool PostgreSqlStorage::updateSchemaVersion(int newVersion)
+bool PostgreSqlStorage::updateSchemaVersion(int newVersion, bool clearUpgradeStep)
 {
-    QSqlQuery query(logDb());
+    // Atomically update the schema version and clear the upgrade step, if specified
+    // Note: This will need reworked if "updateSchemaVersion" is ever called within a transaction.
+    QSqlDatabase db = logDb();
+    if (!beginTransaction(db)) {
+        qWarning() << "PostgreSqlStorage::updateSchemaVersion(int, bool): cannot start transaction!";
+        qWarning() << " -" << qPrintable(db.lastError().text());
+        return false;
+    }
+
+    QSqlQuery query(db);
     query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'");
     query.bindValue(":version", newVersion);
     safeExec(query);
 
-    bool success = true;
     if (!watchQuery(query)) {
-        qCritical() << "PostgreSqlStorage::updateSchemaVersion(int): Updating schema version failed!";
-        success = false;
+        qCritical() << "PostgreSqlStorage::updateSchemaVersion(int, bool): Updating schema version failed!";
+        db.rollback();
+        return false;
+    }
+
+    if (clearUpgradeStep) {
+        // Try clearing the upgrade step if requested
+        if (!setSchemaVersionUpgradeStep("")) {
+            db.rollback();
+            return false;
+        }
     }
-    return success;
-}
 
+    // Successful, commit and return true
+    db.commit();
+    return true;
+}
 
 bool PostgreSqlStorage::setupSchemaVersion(int version)
 {
@@ -208,8 +218,51 @@ bool PostgreSqlStorage::setupSchemaVersion(int version)
     return success;
 }
 
+QString PostgreSqlStorage::schemaVersionUpgradeStep()
+{
+    QSqlQuery query(logDb());
+    query.prepare("SELECT value FROM coreinfo WHERE key = 'schemaupgradestep'");
+    safeExec(query);
+    watchQuery(query);
+    if (query.first())
+        return query.value(0).toString();
 
-UserId PostgreSqlStorage::addUser(const QString &user, const QString &password, const QString &authenticator)
+    // Fall back to the default value
+    return AbstractSqlStorage::schemaVersionUpgradeStep();
+}
+
+bool PostgreSqlStorage::setSchemaVersionUpgradeStep(QString upgradeQuery)
+{
+    // Intentionally do not wrap in a transaction so other functions can include multiple operations
+
+    QSqlQuery query(logDb());
+    query.prepare("UPDATE coreinfo SET value = :upgradestep WHERE key = 'schemaupgradestep'");
+    query.bindValue(":upgradestep", upgradeQuery);
+    safeExec(query);
+
+    // Make sure that the query didn't fail (shouldn't ever happen), and that some non-zero number
+    // of rows were affected
+    bool success = watchQuery(query) && query.numRowsAffected() != 0;
+
+    if (!success) {
+        // The key might not exist (Quassel 0.13.0 and older).  Try inserting it...
+        query = QSqlQuery(logDb());
+        query.prepare("INSERT INTO coreinfo (key, value) VALUES ('schemaupgradestep', :upgradestep)");
+        query.bindValue(":upgradestep", upgradeQuery);
+        safeExec(query);
+
+        if (!watchQuery(query)) {
+            qCritical() << Q_FUNC_INFO << "Setting schema upgrade step failed!";
+            success = false;
+        }
+        else {
+            success = true;
+        }
+    }
+    return success;
+}
+
+UserId PostgreSqlStorage::addUser(const QString& user, const QString& password, const QString& authenticator)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("insert_quasseluser"));
@@ -227,8 +280,7 @@ UserId PostgreSqlStorage::addUser(const QString &user, const QString &password,
     return uid;
 }
 
-
-bool PostgreSqlStorage::updateUser(UserId user, const QString &password)
+bool PostgreSqlStorage::updateUser(UserId user, const QString& password)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_userpassword"));
@@ -240,8 +292,7 @@ bool PostgreSqlStorage::updateUser(UserId user, const QString &password)
     return query.numRowsAffected() != 0;
 }
 
-
-void PostgreSqlStorage::renameUser(UserId user, const QString &newName)
+void PostgreSqlStorage::renameUser(UserId user, const QString& newName)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_username"));
@@ -252,8 +303,7 @@ void PostgreSqlStorage::renameUser(UserId user, const QString &newName)
     emit userRenamed(user, newName);
 }
 
-
-UserId PostgreSqlStorage::validateUser(const QString &user, const QString &password)
+UserId PostgreSqlStorage::validateUser(const QString& user, const QString& password)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("select_authuser"));
@@ -261,7 +311,11 @@ UserId PostgreSqlStorage::validateUser(const QString &user, const QString &passw
     safeExec(query);
     watchQuery(query);
 
-    if (query.first() && checkHashedPassword(query.value(0).toInt(), password, query.value(1).toString(), static_cast<Storage::HashVersion>(query.value(2).toInt()))) {
+    if (query.first()
+        && checkHashedPassword(query.value(0).toInt(),
+                               password,
+                               query.value(1).toString(),
+                               static_cast<Storage::HashVersion>(query.value(2).toInt()))) {
         return query.value(0).toInt();
     }
     else {
@@ -269,8 +323,7 @@ UserId PostgreSqlStorage::validateUser(const QString &user, const QString &passw
     }
 }
 
-
-UserId PostgreSqlStorage::getUserId(const QString &user)
+UserId PostgreSqlStorage::getUserId(const QString& user)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("select_userid"));
@@ -317,7 +370,6 @@ UserId PostgreSqlStorage::internalUser()
     }
 }
 
-
 void PostgreSqlStorage::delUser(UserId user)
 {
     QSqlDatabase db = logDb();
@@ -340,8 +392,7 @@ void PostgreSqlStorage::delUser(UserId user)
     }
 }
 
-
-void PostgreSqlStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data)
+void PostgreSqlStorage::setUserSetting(UserId userId, const QString& settingName, const QVariant& data)
 {
     QByteArray rawData;
     QDataStream out(&rawData, QIODevice::WriteOnly);
@@ -373,8 +424,7 @@ void PostgreSqlStorage::setUserSetting(UserId userId, const QString &settingName
     watchQuery(setQuery);
 }
 
-
-QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData)
+QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString& settingName, const QVariant& defaultData)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("select_user_setting"));
@@ -396,8 +446,58 @@ QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString &setting
     }
 }
 
+void PostgreSqlStorage::setCoreState(const QVariantList& data)
+{
+    QByteArray rawData;
+    QDataStream out(&rawData, QIODevice::WriteOnly);
+    out.setVersion(QDataStream::Qt_4_2);
+    out << data;
+
+    QSqlDatabase db = logDb();
+    QSqlQuery selectQuery(db);
+    selectQuery.prepare(queryString("select_core_state"));
+    selectQuery.bindValue(":key", "active_sessions");
+    safeExec(selectQuery);
+    watchQuery(selectQuery);
+
+    QString setQueryString;
+    if (!selectQuery.first()) {
+        setQueryString = queryString("insert_core_state");
+    }
+    else {
+        setQueryString = queryString("update_core_state");
+    }
+
+    QSqlQuery setQuery(db);
+    setQuery.prepare(setQueryString);
+    setQuery.bindValue(":key", "active_sessions");
+    setQuery.bindValue(":value", rawData);
+    safeExec(setQuery);
+    watchQuery(setQuery);
+}
+
+QVariantList PostgreSqlStorage::getCoreState(const QVariantList& defaultData)
+{
+    QSqlQuery query(logDb());
+    query.prepare(queryString("select_core_state"));
+    query.bindValue(":key", "active_sessions");
+    safeExec(query);
+    watchQuery(query);
 
-IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity)
+    if (query.first()) {
+        QVariantList data;
+        QByteArray rawData = query.value(0).toByteArray();
+        QDataStream in(&rawData, QIODevice::ReadOnly);
+        in.setVersion(QDataStream::Qt_4_2);
+        in >> data;
+        return data;
+    }
+    else {
+        return defaultData;
+    }
+}
+
+IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity& identity)
 {
     IdentityId identityId;
 
@@ -428,17 +528,12 @@ IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity
     query.bindValue(":kickreason", identity.kickReason());
     query.bindValue(":partreason", identity.partReason());
     query.bindValue(":quitreason", identity.quitReason());
-#ifdef HAVE_SSL
     query.bindValue(":sslcert", identity.sslCert().toPem());
     query.bindValue(":sslkey", identity.sslKey().toPem());
-#else
-    query.bindValue(":sslcert", QByteArray());
-    query.bindValue(":sslkey", QByteArray());
-#endif
     safeExec(query);
     if (!watchQuery(query)) {
         db.rollback();
-        return IdentityId();
+        return {};
     }
 
     query.first();
@@ -447,31 +542,30 @@ IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity
 
     if (!identityId.isValid()) {
         db.rollback();
-        return IdentityId();
+        return {};
     }
 
     QSqlQuery insertNickQuery(db);
     insertNickQuery.prepare(queryString("insert_nick"));
-    foreach(QString nick, identity.nicks()) {
+    foreach (QString nick, identity.nicks()) {
         insertNickQuery.bindValue(":identityid", identityId.toInt());
         insertNickQuery.bindValue(":nick", nick);
         safeExec(insertNickQuery);
         if (!watchQuery(insertNickQuery)) {
             db.rollback();
-            return IdentityId();
+            return {};
         }
     }
 
     if (!db.commit()) {
         qWarning() << "PostgreSqlStorage::createIdentity(): committing data failed!";
         qWarning() << " -" << qPrintable(db.lastError().text());
-        return IdentityId();
+        return {};
     }
     return identityId;
 }
 
-
-bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity)
+bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity& identity)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -512,13 +606,8 @@ bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity
     query.bindValue(":kickreason", identity.kickReason());
     query.bindValue(":partreason", identity.partReason());
     query.bindValue(":quitreason", identity.quitReason());
-#ifdef HAVE_SSL
     query.bindValue(":sslcert", identity.sslCert().toPem());
     query.bindValue(":sslkey", identity.sslKey().toPem());
-#else
-    query.bindValue(":sslcert", QByteArray());
-    query.bindValue(":sslkey", QByteArray());
-#endif
     query.bindValue(":identityid", identity.id().toInt());
 
     safeExec(query);
@@ -538,7 +627,7 @@ bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity
 
     QSqlQuery insertNickQuery(db);
     insertNickQuery.prepare(queryString("insert_nick"));
-    foreach(QString nick, identity.nicks()) {
+    foreach (QString nick, identity.nicks()) {
         insertNickQuery.bindValue(":identityid", identity.id().toInt());
         insertNickQuery.bindValue(":nick", nick);
         safeExec(insertNickQuery);
@@ -556,7 +645,6 @@ bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity
     return true;
 }
 
-
 void PostgreSqlStorage::removeIdentity(UserId user, IdentityId identityId)
 {
     QSqlDatabase db = logDb();
@@ -579,10 +667,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)) {
@@ -621,10 +708,8 @@ QList<CoreIdentity> PostgreSqlStorage::identities(UserId user)
         identity.setKickReason(query.value(15).toString());
         identity.setPartReason(query.value(16).toString());
         identity.setQuitReason(query.value(17).toString());
-#ifdef HAVE_SSL
         identity.setSslCert(query.value(18).toByteArray());
         identity.setSslKey(query.value(19).toByteArray());
-#endif
 
         nickQuery.bindValue(":identityid", identity.id().toInt());
         QList<QString> nicks;
@@ -634,14 +719,13 @@ 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;
 }
 
-
-NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info)
+NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo& info)
 {
     NetworkId networkId;
 
@@ -659,7 +743,7 @@ NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info)
     safeExec(query);
     if (!watchQuery(query)) {
         db.rollback();
-        return NetworkId();
+        return {};
     }
 
     query.first();
@@ -667,32 +751,31 @@ NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info)
 
     if (!networkId.isValid()) {
         db.rollback();
-        return NetworkId();
+        return {};
     }
 
     QSqlQuery insertServersQuery(db);
     insertServersQuery.prepare(queryString("insert_server"));
-    foreach(Network::Server server, info.serverList) {
+    foreach (Network::Server server, info.serverList) {
         insertServersQuery.bindValue(":userid", user.toInt());
         insertServersQuery.bindValue(":networkid", networkId.toInt());
         bindServerInfo(insertServersQuery, server);
         safeExec(insertServersQuery);
         if (!watchQuery(insertServersQuery)) {
             db.rollback();
-            return NetworkId();
+            return {};
         }
     }
 
     if (!db.commit()) {
         qWarning() << "PostgreSqlStorage::createNetwork(): committing data failed!";
         qWarning() << " -" << qPrintable(db.lastError().text());
-        return NetworkId();
+        return {};
     }
     return networkId;
 }
 
-
-void PostgreSqlStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info)
+void PostgreSqlStorage::bindNetworkInfo(QSqlQuery& query, const NetworkInfo& info)
 {
     query.bindValue(":networkname", info.networkName);
     query.bindValue(":identityid", info.identity.isValid() ? info.identity.toInt() : QVariant());
@@ -717,12 +800,13 @@ void PostgreSqlStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &inf
     query.bindValue(":messagerateburstsize", info.messageRateBurstSize);
     query.bindValue(":messageratedelay", info.messageRateDelay);
     query.bindValue(":unlimitedmessagerate", info.unlimitedMessageRate);
+    query.bindValue(":skipcaps", info.skipCapsToString());
+
     if (info.networkId.isValid())
         query.bindValue(":networkid", info.networkId.toInt());
 }
 
-
-void PostgreSqlStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server)
+void PostgreSqlStorage::bindServerInfo(QSqlQuery& query, const Network::Server& server)
 {
     query.bindValue(":hostname", server.host);
     query.bindValue(":port", server.port);
@@ -738,8 +822,7 @@ void PostgreSqlStorage::bindServerInfo(QSqlQuery &query, const Network::Server &
     query.bindValue(":sslverify", server.sslVerify);
 }
 
-
-bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo &info)
+bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo& info)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -774,7 +857,7 @@ bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo &info)
 
     QSqlQuery insertServersQuery(db);
     insertServersQuery.prepare(queryString("insert_server"));
-    foreach(Network::Server server, info.serverList) {
+    foreach (Network::Server server, info.serverList) {
         insertServersQuery.bindValue(":userid", user.toInt());
         insertServersQuery.bindValue(":networkid", info.networkId.toInt());
         bindServerInfo(insertServersQuery, server);
@@ -793,8 +876,7 @@ bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo &info)
     return true;
 }
 
-
-bool PostgreSqlStorage::removeNetwork(UserId user, const NetworkId &networkId)
+bool PostgreSqlStorage::removeNetwork(UserId user, const NetworkId& networkId)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -817,10 +899,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)) {
@@ -868,6 +949,7 @@ QList<NetworkInfo> PostgreSqlStorage::networks(UserId user)
         net.messageRateBurstSize = networksQuery.value(20).toUInt();
         net.messageRateDelay = networksQuery.value(21).toUInt();
         net.unlimitedMessageRate = networksQuery.value(22).toBool();
+        net.skipCapsFromString(networksQuery.value(23).toString());
 
         serversQuery.bindValue(":networkid", net.networkId.toInt());
         safeExec(serversQuery);
@@ -894,16 +976,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)) {
@@ -919,15 +1000,14 @@ 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();
     return connectedNets;
 }
 
-
-void PostgreSqlStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected)
+void PostgreSqlStorage::setNetworkConnected(UserId user, const NetworkId& networkId, bool isConnected)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_network_connected"));
@@ -938,8 +1018,7 @@ void PostgreSqlStorage::setNetworkConnected(UserId user, const NetworkId &networ
     watchQuery(query);
 }
 
-
-QHash<QString, QString> PostgreSqlStorage::persistentChannels(UserId user, const NetworkId &networkId)
+QHash<QString, QString> PostgreSqlStorage::persistentChannels(UserId user, const NetworkId& networkId)
 {
     QHash<QString, QString> persistentChans;
 
@@ -965,8 +1044,7 @@ QHash<QString, QString> PostgreSqlStorage::persistentChannels(UserId user, const
     return persistentChans;
 }
 
-
-void PostgreSqlStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined)
+void PostgreSqlStorage::setChannelPersistent(UserId user, const NetworkId& networkId, const QString& channel, bool isJoined)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_buffer_persistent_channel"));
@@ -978,8 +1056,7 @@ void PostgreSqlStorage::setChannelPersistent(UserId user, const NetworkId &netwo
     watchQuery(query);
 }
 
-
-void PostgreSqlStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key)
+void PostgreSqlStorage::setPersistentChannelKey(UserId user, const NetworkId& networkId, const QString& channel, const QString& key)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_buffer_set_channel_key"));
@@ -991,7 +1068,6 @@ void PostgreSqlStorage::setPersistentChannelKey(UserId user, const NetworkId &ne
     watchQuery(query);
 }
 
-
 QString PostgreSqlStorage::awayMessage(UserId user, NetworkId networkId)
 {
     QSqlQuery query(logDb());
@@ -1006,8 +1082,7 @@ QString PostgreSqlStorage::awayMessage(UserId user, NetworkId networkId)
     return awayMsg;
 }
 
-
-void PostgreSqlStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg)
+void PostgreSqlStorage::setAwayMessage(UserId user, NetworkId networkId, const QString& awayMsg)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_network_set_awaymsg"));
@@ -1018,7 +1093,6 @@ void PostgreSqlStorage::setAwayMessage(UserId user, NetworkId networkId, const Q
     watchQuery(query);
 }
 
-
 QString PostgreSqlStorage::userModes(UserId user, NetworkId networkId)
 {
     QSqlQuery query(logDb());
@@ -1033,8 +1107,7 @@ QString PostgreSqlStorage::userModes(UserId user, NetworkId networkId)
     return modes;
 }
 
-
-void PostgreSqlStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes)
+void PostgreSqlStorage::setUserModes(UserId user, NetworkId networkId, const QString& userModes)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_network_set_usermode"));
@@ -1045,14 +1118,13 @@ void PostgreSqlStorage::setUserModes(UserId user, NetworkId networkId, const QSt
     watchQuery(query);
 }
 
-
-BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create)
+BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId& networkId, BufferInfo::Type type, const QString& buffer, bool create)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
         qWarning() << "PostgreSqlStorage::bufferInfo(): cannot start read only transaction!";
         qWarning() << " -" << qPrintable(db.lastError().text());
-        return BufferInfo();
+        return {};
     }
 
     QSqlQuery query(db);
@@ -1080,7 +1152,7 @@ BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId &networkId
 
     if (!create) {
         db.rollback();
-        return BufferInfo();
+        return {};
     }
 
     QSqlQuery createQuery(db);
@@ -1107,8 +1179,7 @@ BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId &networkId
     return bufferInfo;
 }
 
-
-BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId &bufferId)
+BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId& bufferId)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("select_buffer_by_id"));
@@ -1116,21 +1187,24 @@ BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId &bufferI
     query.bindValue(":bufferid", bufferId.toInt());
     safeExec(query);
     if (!watchQuery(query))
-        return BufferInfo();
+        return {};
 
     if (!query.first())
-        return BufferInfo();
+        return {};
 
-    BufferInfo bufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), 0, query.value(4).toString());
+    BufferInfo bufferInfo(query.value(0).toInt(),
+                          query.value(1).toInt(),
+                          (BufferInfo::Type)query.value(2).toInt(),
+                          0,
+                          query.value(4).toString());
     Q_ASSERT(!query.next());
 
     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)) {
@@ -1146,16 +1220,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)) {
@@ -1172,14 +1249,13 @@ 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;
 }
 
-
-bool PostgreSqlStorage::removeBuffer(const UserId &user, const BufferId &bufferId)
+bool PostgreSqlStorage::removeBuffer(const UserId& user, const BufferId& bufferId)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -1207,14 +1283,14 @@ bool PostgreSqlStorage::removeBuffer(const UserId &user, const BufferId &bufferI
         return true;
     default:
         // there was more then one buffer deleted...
-        qWarning() << "PostgreSqlStorage::removeBuffer(): Userid" << user << "BufferId" << "caused deletion of" << numRows << "Buffers! Rolling back transaction...";
+        qWarning() << "PostgreSqlStorage::removeBuffer(): Userid" << user << "BufferId"
+                   << "caused deletion of" << numRows << "Buffers! Rolling back transaction...";
         db.rollback();
         return false;
     }
 }
 
-
-bool PostgreSqlStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName)
+bool PostgreSqlStorage::renameBuffer(const UserId& user, const BufferId& bufferId, const QString& newName)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -1244,14 +1320,14 @@ bool PostgreSqlStorage::renameBuffer(const UserId &user, const BufferId &bufferI
         return true;
     default:
         // there was more then one buffer deleted...
-        qWarning() << "PostgreSqlStorage::renameBuffer(): Userid" << user << "BufferId" << "affected" << numRows << "Buffers! Rolling back transaction...";
+        qWarning() << "PostgreSqlStorage::renameBuffer(): Userid" << user << "BufferId"
+                   << "affected" << numRows << "Buffers! Rolling back transaction...";
         db.rollback();
         return false;
     }
 }
 
-
-bool PostgreSqlStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2)
+bool PostgreSqlStorage::mergeBuffersPermanently(const UserId& user, const BufferId& bufferId1, const BufferId& bufferId2)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -1301,20 +1377,46 @@ bool PostgreSqlStorage::mergeBuffersPermanently(const UserId &user, const Buffer
     return true;
 }
 
+QHash<BufferId, MsgId> PostgreSqlStorage::bufferLastMsgIds(UserId user)
+{
+    QHash<BufferId, MsgId> lastMsgHash;
 
-void PostgreSqlStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
+    QSqlDatabase db = logDb();
+    if (!beginReadOnlyTransaction(db)) {
+        qWarning() << "PostgreSqlStorage::bufferLastMsgIds(): cannot start read only transaction!";
+        qWarning() << " -" << qPrintable(db.lastError().text());
+        return lastMsgHash;
+    }
+
+    QSqlQuery query(db);
+    query.prepare(queryString("select_buffer_last_messages"));
+    query.bindValue(":userid", user.toInt());
+    safeExec(query);
+    if (!watchQuery(query)) {
+        db.rollback();
+        return lastMsgHash;
+    }
+
+    while (query.next()) {
+        lastMsgHash[query.value(0).toInt()] = query.value(1).toLongLong();
+    }
+
+    db.commit();
+    return lastMsgHash;
+}
+
+void PostgreSqlStorage::setBufferLastSeenMsg(UserId user, const BufferId& bufferId, const MsgId& msgId)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_buffer_lastseen"));
 
     query.bindValue(":userid", user.toInt());
     query.bindValue(":bufferid", bufferId.toInt());
-    query.bindValue(":lastseenmsgid", msgId.toInt());
+    query.bindValue(":lastseenmsgid", msgId.toQint64());
     safeExec(query);
     watchQuery(query);
 }
 
-
 QHash<BufferId, MsgId> PostgreSqlStorage::bufferLastSeenMsgIds(UserId user)
 {
     QHash<BufferId, MsgId> lastSeenHash;
@@ -1336,27 +1438,25 @@ QHash<BufferId, MsgId> PostgreSqlStorage::bufferLastSeenMsgIds(UserId user)
     }
 
     while (query.next()) {
-        lastSeenHash[query.value(0).toInt()] = query.value(1).toInt();
+        lastSeenHash[query.value(0).toInt()] = query.value(1).toLongLong();
     }
 
     db.commit();
     return lastSeenHash;
 }
 
-
-void PostgreSqlStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
+void PostgreSqlStorage::setBufferMarkerLineMsg(UserId user, const BufferId& bufferId, const MsgId& msgId)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_buffer_markerlinemsgid"));
 
     query.bindValue(":userid", user.toInt());
     query.bindValue(":bufferid", bufferId.toInt());
-    query.bindValue(":markerlinemsgid", msgId.toInt());
+    query.bindValue(":markerlinemsgid", msgId.toQint64());
     safeExec(query);
     watchQuery(query);
 }
 
-
 QHash<BufferId, MsgId> PostgreSqlStorage::bufferMarkerLineMsgIds(UserId user)
 {
     QHash<BufferId, MsgId> markerLineHash;
@@ -1378,14 +1478,13 @@ QHash<BufferId, MsgId> PostgreSqlStorage::bufferMarkerLineMsgIds(UserId user)
     }
 
     while (query.next()) {
-        markerLineHash[query.value(0).toInt()] = query.value(1).toInt();
+        markerLineHash[query.value(0).toInt()] = query.value(1).toLongLong();
     }
 
     db.commit();
     return markerLineHash;
 }
 
-
 void PostgreSqlStorage::setBufferActivity(UserId user, BufferId bufferId, Message::Types bufferActivity)
 {
     QSqlQuery query(logDb());
@@ -1393,7 +1492,7 @@ void PostgreSqlStorage::setBufferActivity(UserId user, BufferId bufferId, Messag
 
     query.bindValue(":userid", user.toInt());
     query.bindValue(":bufferid", bufferId.toInt());
-    query.bindValue(":bufferactivity", (int) bufferActivity);
+    query.bindValue(":bufferactivity", (int)bufferActivity);
     safeExec(query);
     watchQuery(query);
 }
@@ -1431,16 +1530,16 @@ Message::Types PostgreSqlStorage::bufferActivity(BufferId bufferId, MsgId lastSe
     QSqlQuery query(logDb());
     query.prepare(queryString("select_buffer_bufferactivity"));
     query.bindValue(":bufferid", bufferId.toInt());
-    query.bindValue(":lastseenmsgid", lastSeenMsgId.toInt());
+    query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
     safeExec(query);
     watchQuery(query);
-    Message::Types result = Message::Types(0);
+    Message::Types result{};
     if (query.first())
         result = Message::Types(query.value(0).toInt());
     return result;
 }
 
-QHash<QString, QByteArray> PostgreSqlStorage::bufferCiphers(UserId user, const NetworkId &networkId)
+QHash<QString, QByteArray> PostgreSqlStorage::bufferCiphers(UserId user, const NetworkIdnetworkId)
 {
     QHash<QString, QByteArray> bufferCiphers;
 
@@ -1466,7 +1565,7 @@ QHash<QString, QByteArray> PostgreSqlStorage::bufferCiphers(UserId user, const N
     return bufferCiphers;
 }
 
-void PostgreSqlStorage::setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher)
+void PostgreSqlStorage::setBufferCipher(UserId user, const NetworkId& networkId, const QString& bufferName, const QByteArray& cipher)
 {
     QSqlQuery query(logDb());
     query.prepare(queryString("update_buffer_cipher"));
@@ -1478,7 +1577,6 @@ void PostgreSqlStorage::setBufferCipher(UserId user, const NetworkId &networkId,
     watchQuery(query);
 }
 
-
 void PostgreSqlStorage::setHighlightCount(UserId user, BufferId bufferId, int highlightcount)
 {
     QSqlQuery query(logDb());
@@ -1524,16 +1622,16 @@ int PostgreSqlStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
     QSqlQuery query(logDb());
     query.prepare(queryString("select_buffer_highlightcount"));
     query.bindValue(":bufferid", bufferId.toInt());
-    query.bindValue(":lastseenmsgid", lastSeenMsgId.toInt());
+    query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
     safeExec(query);
     watchQuery(query);
-    int result = int(0);
+    auto result = int(0);
     if (query.first())
         result = query.value(0).toInt();
     return result;
 }
 
-bool PostgreSqlStorage::logMessage(Message &msg)
+bool PostgreSqlStorage::logMessage(Messagemsg)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -1543,13 +1641,11 @@ bool PostgreSqlStorage::logMessage(Message &msg)
     }
 
     QVariantList senderParams;
-    senderParams << msg.sender()
-                 << msg.realName()
-                 << msg.avatarUrl();
+    senderParams << msg.sender() << msg.realName() << msg.avatarUrl();
     QSqlQuery getSenderIdQuery = executePreparedQuery("select_senderid", senderParams, db);
-    int senderId;
+    qint64 senderId;
     if (getSenderIdQuery.first()) {
-        senderId = getSenderIdQuery.value(0).toInt();
+        senderId = getSenderIdQuery.value(0).toLongLong();
     }
     else {
         // it's possible that the sender was already added by another thread
@@ -1562,22 +1658,19 @@ bool PostgreSqlStorage::logMessage(Message &msg)
             getSenderIdQuery = executePreparedQuery("select_senderid", senderParams, db);
             watchQuery(getSenderIdQuery);
             getSenderIdQuery.first();
-            senderId = getSenderIdQuery.value(0).toInt();
+            senderId = getSenderIdQuery.value(0).toLongLong();
         }
         else {
             releaseSavePoint("sender_sp1", db);
             addSenderQuery.first();
-            senderId = addSenderQuery.value(0).toInt();
+            senderId = addSenderQuery.value(0).toLongLong();
         }
     }
 
     QVariantList params;
-    params << msg.timestamp()
-           << msg.bufferInfo().bufferId().toInt()
-           << msg.type()
-           << (int)msg.flags()
-           << senderId
-           << msg.senderPrefixes()
+    // PostgreSQL handles QDateTime()'s serialized format by default, and QDateTime() serializes
+    // to a 64-bit time compatible format by default.
+    params << msg.timestamp() << msg.bufferInfo().bufferId().toInt() << msg.type() << (int)msg.flags() << senderId << msg.senderPrefixes()
            << msg.contents();
     QSqlQuery logMessageQuery = executePreparedQuery("insert_message", params, db);
 
@@ -1587,7 +1680,7 @@ bool PostgreSqlStorage::logMessage(Message &msg)
     }
 
     logMessageQuery.first();
-    MsgId msgId = logMessageQuery.value(0).toInt();
+    MsgId msgId = logMessageQuery.value(0).toLongLong();
     db.commit();
     if (msgId.isValid()) {
         msg.setMsgId(msgId);
@@ -1598,8 +1691,7 @@ bool PostgreSqlStorage::logMessage(Message &msg)
     }
 }
 
-
-bool PostgreSqlStorage::logMessages(MessageList &msgs)
+bool PostgreSqlStorage::logMessages(MessageList& msgs)
 {
     QSqlDatabase db = logDb();
     if (!beginTransaction(db)) {
@@ -1609,26 +1701,25 @@ bool PostgreSqlStorage::logMessages(MessageList &msgs)
     }
 
     QList<int> senderIdList;
-    QHash<SenderData, int> senderIds;
+    QHash<SenderData, qint64> senderIds;
     QSqlQuery addSenderQuery;
-    QSqlQuery selectSenderQuery;;
+    QSqlQuery selectSenderQuery;
+    ;
     for (int i = 0; i < msgs.count(); i++) {
-        auto &msg = msgs.at(i);
-        SenderData sender = { msg.sender(), msg.realName(), msg.avatarUrl() };
+        automsg = msgs.at(i);
+        SenderData sender = {msg.sender(), msg.realName(), msg.avatarUrl()};
         if (senderIds.contains(sender)) {
             senderIdList << senderIds[sender];
             continue;
         }
 
         QVariantList senderParams;
-        senderParams << sender.sender
-                     << sender.realname
-                     << sender.avatarurl;
+        senderParams << sender.sender << sender.realname << sender.avatarurl;
 
         selectSenderQuery = executePreparedQuery("select_senderid", senderParams, db);
         if (selectSenderQuery.first()) {
-            senderIdList << selectSenderQuery.value(0).toInt();
-            senderIds[sender] = selectSenderQuery.value(0).toInt();
+            senderIdList << selectSenderQuery.value(0).toLongLong();
+            senderIds[sender] = selectSenderQuery.value(0).toLongLong();
         }
         else {
             savePoint("sender_sp", db);
@@ -1639,14 +1730,14 @@ bool PostgreSqlStorage::logMessages(MessageList &msgs)
                 selectSenderQuery = executePreparedQuery("select_senderid", senderParams, db);
                 watchQuery(selectSenderQuery);
                 selectSenderQuery.first();
-                senderIdList << selectSenderQuery.value(0).toInt();
-                senderIds[sender] = selectSenderQuery.value(0).toInt();
+                senderIdList << selectSenderQuery.value(0).toLongLong();
+                senderIds[sender] = selectSenderQuery.value(0).toLongLong();
             }
             else {
                 releaseSavePoint("sender_sp", db);
                 addSenderQuery.first();
-                senderIdList << addSenderQuery.value(0).toInt();
-                senderIds[sender] = addSenderQuery.value(0).toInt();
+                senderIdList << addSenderQuery.value(0).toLongLong();
+                senderIds[sender] = addSenderQuery.value(0).toLongLong();
             }
         }
     }
@@ -1654,15 +1745,12 @@ bool PostgreSqlStorage::logMessages(MessageList &msgs)
     // yes we loop twice over the same list. This avoids alternating queries.
     bool error = false;
     for (int i = 0; i < msgs.count(); i++) {
-        Message &msg = msgs[i];
+        Messagemsg = msgs[i];
         QVariantList params;
-        params << msg.timestamp()
-               << msg.bufferInfo().bufferId().toInt()
-               << msg.type()
-               << (int)msg.flags()
-               << senderIdList.at(i)
-               << msg.senderPrefixes()
-               << msg.contents();
+        // PostgreSQL handles QDateTime()'s serialized format by default, and QDateTime() serializes
+        // to a 64-bit time compatible format by default.
+        params << msg.timestamp() << msg.bufferInfo().bufferId().toInt() << msg.type() << (int)msg.flags() << senderIdList.at(i)
+               << msg.senderPrefixes() << msg.contents();
         QSqlQuery logMessageQuery = executePreparedQuery("insert_message", params, db);
         if (!watchQuery(logMessageQuery)) {
             db.rollback();
@@ -1671,7 +1759,7 @@ bool PostgreSqlStorage::logMessages(MessageList &msgs)
         }
         else {
             logMessageQuery.first();
-            msg.setMsgId(logMessageQuery.value(0).toInt());
+            msg.setMsgId(logMessageQuery.value(0).toLongLong());
         }
     }
 
@@ -1687,10 +1775,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)) {
@@ -1712,12 +1799,12 @@ QList<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, Ms
     }
     else if (last == -1) {
         queryName = "select_messagesNewerThan";
-        params << first.toInt();
+        params << first.toQint64();
     }
     else {
         queryName = "select_messagesRange";
-        params << first.toInt();
-        params << last.toInt();
+        params << first.toQint64();
+        params << last.toQint64();
     }
     params << bufferId.toInt();
     if (limit != -1)
@@ -1735,33 +1822,178 @@ QList<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, Ms
 
     QDateTime timestamp;
     while (query.next()) {
+        // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+        // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
+        timestamp = query.value(1).toDateTime();
+        timestamp.setTimeSpec(Qt::UTC);
+        Message msg(timestamp,
+                    bufferInfo,
+                    (Message::Type)query.value(2).toInt(),
+                    query.value(8).toString(),
+                    query.value(4).toString(),
+                    query.value(5).toString(),
+                    query.value(6).toString(),
+                    query.value(7).toString(),
+                    (Message::Flags)query.value(3).toInt());
+        msg.setMsgId(query.value(0).toLongLong());
+        messagelist.push_back(std::move(msg));
+    }
+
+    db.commit();
+    return messagelist;
+}
+
+std::vector<Message> PostgreSqlStorage::requestMsgsFiltered(
+    UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+    std::vector<Message> messagelist;
+
+    QSqlDatabase db = logDb();
+    if (!beginReadOnlyTransaction(db)) {
+        qWarning() << "PostgreSqlStorage::requestMsgs(): cannot start read only transaction!";
+        qWarning() << " -" << qPrintable(db.lastError().text());
+        return messagelist;
+    }
+
+    BufferInfo bufferInfo = getBufferInfo(user, bufferId);
+    if (!bufferInfo.isValid()) {
+        db.rollback();
+        return messagelist;
+    }
+
+    QSqlQuery query(db);
+    if (last == -1 && first == -1) {
+        query.prepare(queryString("select_messagesNewestK_filtered"));
+    }
+    else if (last == -1) {
+        query.prepare(queryString("select_messagesNewerThan_filtered"));
+        query.bindValue(":first", first.toQint64());
+    }
+    else {
+        query.prepare(queryString("select_messagesRange_filtered"));
+        query.bindValue(":last", last.toQint64());
+        query.bindValue(":first", first.toQint64());
+    }
+    query.bindValue(":buffer", bufferId.toInt());
+    query.bindValue(":limit", limit);
+    int typeRaw = type;
+    query.bindValue(":type", typeRaw);
+    int flagsRaw = flags;
+    query.bindValue(":flags", flagsRaw);
+
+    safeExec(query);
+    if (!watchQuery(query)) {
+        qDebug() << "select_messages failed";
+        db.rollback();
+        return messagelist;
+    }
+
+    QDateTime timestamp;
+    while (query.next()) {
+        // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+        // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
         timestamp = query.value(1).toDateTime();
         timestamp.setTimeSpec(Qt::UTC);
         Message msg(timestamp,
-            bufferInfo,
-            (Message::Type)query.value(2).toUInt(),
-            query.value(8).toString(),
-            query.value(4).toString(),
-            query.value(5).toString(),
-            query.value(6).toString(),
-            query.value(7).toString(),
-            (Message::Flags)query.value(3).toUInt());
-        msg.setMsgId(query.value(0).toInt());
-        messagelist << msg;
+                    bufferInfo,
+                    (Message::Type)query.value(2).toInt(),
+                    query.value(8).toString(),
+                    query.value(4).toString(),
+                    query.value(5).toString(),
+                    query.value(6).toString(),
+                    query.value(7).toString(),
+                    Message::Flags{query.value(3).toInt()});
+        msg.setMsgId(query.value(0).toLongLong());
+        messagelist.push_back(std::move(msg));
     }
 
     db.commit();
     return messagelist;
 }
 
+std::vector<Message> PostgreSqlStorage::requestMsgsForward(
+    UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+    std::vector<Message> messagelist;
+
+    QSqlDatabase db = logDb();
+    if (!beginReadOnlyTransaction(db)) {
+        qWarning() << "PostgreSqlStorage::requestMsgsForward(): cannot start read only transaction!";
+        qWarning() << " -" << qPrintable(db.lastError().text());
+        return messagelist;
+    }
+
+    BufferInfo bufferInfo = getBufferInfo(user, bufferId);
+    if (!bufferInfo.isValid()) {
+        db.rollback();
+        return messagelist;
+    }
+
+    QString queryName;
+    QVariantList params;
+
+    if (first == -1) {
+        params << std::numeric_limits<qint64>::min();
+    } else {
+        params << first.toQint64();
+    }
+
+    if (last == -1) {
+        params << std::numeric_limits<qint64>::max();
+    } else {
+        params << last.toQint64();
+    }
+
+    params << bufferId.toInt();
+
+    int typeRaw = type;
+    int flagsRaw = flags;
+    params << typeRaw;
+    params << flagsRaw;
+
+    if (limit != -1)
+        params << limit;
+    else
+        params << QVariant(QVariant::Int);
+
+    QSqlQuery query = executePreparedQuery("select_messagesForward", params, db);
+
+    if (!watchQuery(query)) {
+        qDebug() << "select_messages failed";
+        db.rollback();
+        return messagelist;
+    }
+
+    QDateTime timestamp;
+    while (query.next()) {
+        // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+        // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
+        timestamp = query.value(1).toDateTime();
+        timestamp.setTimeSpec(Qt::UTC);
+        Message msg(timestamp,
+                    bufferInfo,
+                    (Message::Type)query.value(2).toInt(),
+                    query.value(8).toString(),
+                    query.value(4).toString(),
+                    query.value(5).toString(),
+                    query.value(6).toString(),
+                    query.value(7).toString(),
+                    (Message::Flags)query.value(3).toInt());
+        msg.setMsgId(query.value(0).toLongLong());
+        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;
-    foreach(BufferInfo bufferInfo, requestBuffers(user)) {
+    foreach (BufferInfo bufferInfo, requestBuffers(user)) {
         bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
     }
 
@@ -1778,10 +2010,10 @@ QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId
     }
     else {
         query.prepare(queryString("select_messagesAll"));
-        query.bindValue(":lastmsg", last.toInt());
+        query.bindValue(":lastmsg", last.toQint64());
     }
     query.bindValue(":userid", user.toInt());
-    query.bindValue(":firstmsg", first.toInt());
+    query.bindValue(":firstmsg", first.toQint64());
     safeExec(query);
     if (!watchQuery(query)) {
         db.rollback();
@@ -1790,25 +2022,90 @@ QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId
 
     QDateTime timestamp;
     for (int i = 0; i < limit && query.next(); i++) {
+        // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+        // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
         timestamp = query.value(2).toDateTime();
         timestamp.setTimeSpec(Qt::UTC);
         Message msg(timestamp,
-            bufferInfoHash[query.value(1).toInt()],
-            (Message::Type)query.value(3).toUInt(),
-            query.value(9).toString(),
-            query.value(5).toString(),
-            query.value(6).toString(),
-            query.value(7).toString(),
-            query.value(8).toString(),
-            (Message::Flags)query.value(4).toUInt());
-        msg.setMsgId(query.value(0).toInt());
-        messagelist << msg;
+                    bufferInfoHash[query.value(1).toInt()],
+                    (Message::Type)query.value(3).toInt(),
+                    query.value(9).toString(),
+                    query.value(5).toString(),
+                    query.value(6).toString(),
+                    query.value(7).toString(),
+                    query.value(8).toString(),
+                    (Message::Flags)query.value(4).toInt());
+        msg.setMsgId(query.value(0).toLongLong());
+        messagelist.push_back(std::move(msg));
     }
 
     db.commit();
     return messagelist;
 }
 
+std::vector<Message> PostgreSqlStorage::requestAllMsgsFiltered(
+    UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+    std::vector<Message> messagelist;
+
+    // requestBuffers uses it's own transaction.
+    QHash<BufferId, BufferInfo> bufferInfoHash;
+    foreach (BufferInfo bufferInfo, requestBuffers(user)) {
+        bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
+    }
+
+    QSqlDatabase db = logDb();
+    if (!beginReadOnlyTransaction(db)) {
+        qWarning() << "PostgreSqlStorage::requestAllMsgs(): cannot start read only transaction!";
+        qWarning() << " -" << qPrintable(db.lastError().text());
+        return messagelist;
+    }
+
+    QSqlQuery query(db);
+    if (last == -1) {
+        query.prepare(queryString("select_messagesAllNew_filtered"));
+    }
+    else {
+        query.prepare(queryString("select_messagesAll_filtered"));
+        query.bindValue(":lastmsg", last.toQint64());
+    }
+    query.bindValue(":userid", user.toInt());
+    query.bindValue(":firstmsg", first.toQint64());
+
+    int typeRaw = type;
+    query.bindValue(":type", typeRaw);
+
+    int flagsRaw = flags;
+    query.bindValue(":flags", flagsRaw);
+
+    safeExec(query);
+    if (!watchQuery(query)) {
+        db.rollback();
+        return messagelist;
+    }
+
+    QDateTime timestamp;
+    for (int i = 0; i < limit && query.next(); i++) {
+        // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+        // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
+        timestamp = query.value(2).toDateTime();
+        timestamp.setTimeSpec(Qt::UTC);
+        Message msg(timestamp,
+                    bufferInfoHash[query.value(1).toInt()],
+                    (Message::Type)query.value(3).toInt(),
+                    query.value(9).toString(),
+                    query.value(5).toString(),
+                    query.value(6).toString(),
+                    query.value(7).toString(),
+                    query.value(8).toString(),
+                    Message::Flags{query.value(4).toInt()});
+        msg.setMsgId(query.value(0).toLongLong());
+        messagelist.push_back(std::move(msg));
+    }
+
+    db.commit();
+    return messagelist;
+}
 
 QMap<UserId, QString> PostgreSqlStorage::getAllAuthUserNames()
 {
@@ -1824,22 +2121,6 @@ QMap<UserId, QString> PostgreSqlStorage::getAllAuthUserNames()
     return authusernames;
 }
 
-
-QString PostgreSqlStorage::getAuthUserName(UserId user)
-{
-    QString authusername;
-    QSqlQuery query(logDb());
-    query.prepare(queryString("select_authusername"));
-    query.bindValue(":userid", user.toInt());
-    safeExec(query);
-    watchQuery(query);
-
-    if (query.first()) {
-         authusername = query.value(0).toString();
-    }
-    return authusername;
-}
-
 // void PostgreSqlStorage::safeExec(QSqlQuery &query) {
 //   qDebug() << "PostgreSqlStorage::safeExec";
 //   qDebug() << "   executing:\n" << query.executedQuery();
@@ -1863,8 +2144,7 @@ QString PostgreSqlStorage::getAuthUserName(UserId user)
 //   return;
 // }
 
-
-bool PostgreSqlStorage::beginTransaction(QSqlDatabase &db)
+bool PostgreSqlStorage::beginTransaction(QSqlDatabase& db)
 {
     bool result = db.transaction();
     if (!db.isOpen()) {
@@ -1874,7 +2154,7 @@ bool PostgreSqlStorage::beginTransaction(QSqlDatabase &db)
     return result;
 }
 
-bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabase &db)
+bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabasedb)
 {
     QSqlQuery query = db.exec("BEGIN TRANSACTION READ ONLY");
     if (!db.isOpen()) {
@@ -1884,8 +2164,7 @@ bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabase &db)
     return !query.lastError().isValid();
 }
 
-
-QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString &queryname, const QString &paramstring, QSqlDatabase &db)
+QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString& queryname, const QString& paramstring, QSqlDatabase& db)
 {
     // Query preparing is done lazily. That means that instead of always checking if the query is already prepared
     // we just EXECUTE and catch the error
@@ -1904,18 +2183,21 @@ QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString &queryname, co
         if (!db.isOpen()) {
             db = logDb();
             if (!beginTransaction(db)) {
-                qWarning() << "PostgreSqlStorage::prepareAndExecuteQuery(): cannot start transaction while recovering from connection loss!";
+                qWarning()
+                    << "PostgreSqlStorage::prepareAndExecuteQuery(): cannot start transaction while recovering from connection loss!";
                 qWarning() << " -" << qPrintable(db.lastError().text());
                 return query;
             }
             db.exec("SAVEPOINT quassel_prepare_query");
-        } else {
+        }
+        else {
             db.exec("ROLLBACK TO SAVEPOINT quassel_prepare_query");
         }
 
         // and once again: Qt leaves us without error codes so we either parse (language dependent(!)) strings
         // or we just guess the error. As we're only interested in unprepared queries, this will be our guess. :)
-        QSqlQuery checkQuery = db.exec(QString("SELECT count(name) FROM pg_prepared_statements WHERE name = 'quassel_%1' AND from_sql = TRUE").arg(queryname.toLower()));
+        QSqlQuery checkQuery = db.exec(
+            QString("SELECT count(name) FROM pg_prepared_statements WHERE name = 'quassel_%1' AND from_sql = TRUE").arg(queryname.toLower()));
         checkQuery.first();
         if (checkQuery.value(0).toInt() == 0) {
             db.exec(QString("PREPARE quassel_%1 AS %2").arg(queryname).arg(queryString(queryname)));
@@ -1943,15 +2225,14 @@ QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString &queryname, co
     return query;
 }
 
-
-QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, const QVariantList &params, QSqlDatabase &db)
+QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString& queryname, const QVariantList& params, QSqlDatabase& db)
 {
-    QSqlDriver *driver = db.driver();
+    QSqlDriverdriver = db.driver();
 
     QStringList paramStrings;
     QSqlField field;
     for (int i = 0; i < params.count(); i++) {
-        const QVariant &value = params.at(i);
+        const QVariantvalue = params.at(i);
         field.setType(value.type());
         if (value.isNull())
             field.clear();
@@ -1969,8 +2250,7 @@ QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, cons
     }
 }
 
-
-QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, const QVariant &param, QSqlDatabase &db)
+QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString& queryname, const QVariant& param, QSqlDatabase& db)
 {
     QSqlField field;
     field.setType(param.type());
@@ -1983,27 +2263,23 @@ QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, cons
     return prepareAndExecuteQuery(queryname, paramString, db);
 }
 
-
-void PostgreSqlStorage::deallocateQuery(const QString &queryname, const QSqlDatabase &db)
+void PostgreSqlStorage::deallocateQuery(const QString& queryname, const QSqlDatabase& db)
 {
     db.exec(QString("DEALLOCATE quassel_%1").arg(queryname));
 }
 
-
-void PostgreSqlStorage::safeExec(QSqlQuery &query)
+void PostgreSqlStorage::safeExec(QSqlQuery& query)
 {
     // If the query fails due to the connection being gone, it seems to cause
     // exec() to return false but no lastError to be set
-    if(!query.exec() && !query.lastError().isValid())
-    {
+    if (!query.exec() && !query.lastError().isValid()) {
         QSqlDatabase db = logDb();
         QSqlQuery retryQuery(db);
         retryQuery.prepare(query.lastQuery());
         QMapIterator<QString, QVariant> i(query.boundValues());
-        while (i.hasNext())
-        {
+        while (i.hasNext()) {
             i.next();
-            retryQuery.bindValue(i.key(),i.value());
+            retryQuery.bindValue(i.key(), i.value());
         }
         query = retryQuery;
         query.exec();
@@ -2015,9 +2291,7 @@ void PostgreSqlStorage::safeExec(QSqlQuery &query)
 // ========================================
 PostgreSqlMigrationWriter::PostgreSqlMigrationWriter()
     : PostgreSqlStorage()
-{
-}
-
+{}
 
 bool PostgreSqlMigrationWriter::prepareQuery(MigrationObject mo)
 {
@@ -2051,14 +2325,16 @@ bool PostgreSqlMigrationWriter::prepareQuery(MigrationObject mo)
     case UserSetting:
         query = queryString("migrate_write_usersetting");
         break;
+    case CoreState:
+        query = queryString("migrate_write_corestate");
+        break;
     }
     newQuery(query, logDb());
     return true;
 }
 
-
-//bool PostgreSqlMigrationWriter::writeUser(const QuasselUserMO &user) {
-bool PostgreSqlMigrationWriter::writeMo(const QuasselUserMO &user)
+// bool PostgreSqlMigrationWriter::writeUser(const QuasselUserMO &user) {
+bool PostgreSqlMigrationWriter::writeMo(const QuasselUserMO& user)
 {
     bindValue(0, user.id.toInt());
     bindValue(1, user.username);
@@ -2068,9 +2344,8 @@ bool PostgreSqlMigrationWriter::writeMo(const QuasselUserMO &user)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeSender(const SenderMO &sender) {
-bool PostgreSqlMigrationWriter::writeMo(const SenderMO &sender)
+// bool PostgreSqlMigrationWriter::writeSender(const SenderMO &sender) {
+bool PostgreSqlMigrationWriter::writeMo(const SenderMO& sender)
 {
     bindValue(0, sender.senderId);
     bindValue(1, sender.sender);
@@ -2079,9 +2354,8 @@ bool PostgreSqlMigrationWriter::writeMo(const SenderMO &sender)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeIdentity(const IdentityMO &identity) {
-bool PostgreSqlMigrationWriter::writeMo(const IdentityMO &identity)
+// bool PostgreSqlMigrationWriter::writeIdentity(const IdentityMO &identity) {
+bool PostgreSqlMigrationWriter::writeMo(const IdentityMO& identity)
 {
     _validIdentities << identity.id.toInt();
     bindValue(0, identity.id.toInt());
@@ -2098,7 +2372,7 @@ bool PostgreSqlMigrationWriter::writeMo(const IdentityMO &identity)
     bindValue(11, identity.autoAwayReasonEnabled);
     bindValue(12, identity.detachAwayEnabled);
     bindValue(13, identity.detachAwayReason);
-    bindValue(14, identity.detchAwayReasonEnabled);
+    bindValue(14, identity.detachAwayReasonEnabled);
     bindValue(15, identity.ident);
     bindValue(16, identity.kickReason);
     bindValue(17, identity.partReason);
@@ -2108,9 +2382,8 @@ bool PostgreSqlMigrationWriter::writeMo(const IdentityMO &identity)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeIdentityNick(const IdentityNickMO &identityNick) {
-bool PostgreSqlMigrationWriter::writeMo(const IdentityNickMO &identityNick)
+// bool PostgreSqlMigrationWriter::writeIdentityNick(const IdentityNickMO &identityNick) {
+bool PostgreSqlMigrationWriter::writeMo(const IdentityNickMO& identityNick)
 {
     bindValue(0, identityNick.nickid);
     bindValue(1, identityNick.identityId.toInt());
@@ -2118,9 +2391,8 @@ bool PostgreSqlMigrationWriter::writeMo(const IdentityNickMO &identityNick)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeNetwork(const NetworkMO &network) {
-bool PostgreSqlMigrationWriter::writeMo(const NetworkMO &network)
+// bool PostgreSqlMigrationWriter::writeNetwork(const NetworkMO &network) {
+bool PostgreSqlMigrationWriter::writeMo(const NetworkMO& network)
 {
     bindValue(0, network.networkid.toInt());
     bindValue(1, network.userid.toInt());
@@ -2155,12 +2427,13 @@ bool PostgreSqlMigrationWriter::writeMo(const NetworkMO &network)
     bindValue(26, network.messagerateburstsize);
     bindValue(27, network.messageratedelay);
     bindValue(28, network.unlimitedmessagerate);
+    // Skipped IRCv3 caps
+    bindValue(29, network.skipcaps);
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeBuffer(const BufferMO &buffer) {
-bool PostgreSqlMigrationWriter::writeMo(const BufferMO &buffer)
+// bool PostgreSqlMigrationWriter::writeBuffer(const BufferMO &buffer) {
+bool PostgreSqlMigrationWriter::writeMo(const BufferMO& buffer)
 {
     bindValue(0, buffer.bufferid.toInt());
     bindValue(1, buffer.userid.toInt());
@@ -2180,11 +2453,10 @@ bool PostgreSqlMigrationWriter::writeMo(const BufferMO &buffer)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeBacklog(const BacklogMO &backlog) {
-bool PostgreSqlMigrationWriter::writeMo(const BacklogMO &backlog)
+// bool PostgreSqlMigrationWriter::writeBacklog(const BacklogMO &backlog) {
+bool PostgreSqlMigrationWriter::writeMo(const BacklogMO& backlog)
 {
-    bindValue(0, backlog.messageid.toInt());
+    bindValue(0, backlog.messageid.toQint64());
     bindValue(1, backlog.time);
     bindValue(2, backlog.bufferid.toInt());
     bindValue(3, backlog.type);
@@ -2195,9 +2467,8 @@ bool PostgreSqlMigrationWriter::writeMo(const BacklogMO &backlog)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeIrcServer(const IrcServerMO &ircserver) {
-bool PostgreSqlMigrationWriter::writeMo(const IrcServerMO &ircserver)
+// bool PostgreSqlMigrationWriter::writeIrcServer(const IrcServerMO &ircserver) {
+bool PostgreSqlMigrationWriter::writeMo(const IrcServerMO& ircserver)
 {
     bindValue(0, ircserver.serverid);
     bindValue(1, ircserver.userid.toInt());
@@ -2217,9 +2488,8 @@ bool PostgreSqlMigrationWriter::writeMo(const IrcServerMO &ircserver)
     return exec();
 }
 
-
-//bool PostgreSqlMigrationWriter::writeUserSetting(const UserSettingMO &userSetting) {
-bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO &userSetting)
+// bool PostgreSqlMigrationWriter::writeUserSetting(const UserSettingMO &userSetting) {
+bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO& userSetting)
 {
     bindValue(0, userSetting.userid.toInt());
     bindValue(1, userSetting.settingname);
@@ -2227,19 +2497,20 @@ bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO &userSetting)
     return exec();
 }
 
+bool PostgreSqlMigrationWriter::writeMo(const CoreStateMO& coreState)
+{
+    bindValue(0, coreState.key);
+    bindValue(1, coreState.value);
+    return exec();
+}
 
 bool PostgreSqlMigrationWriter::postProcess()
 {
     QSqlDatabase db = logDb();
     QList<Sequence> sequences;
-    sequences << Sequence("backlog", "messageid")
-              << Sequence("buffer", "bufferid")
-              << Sequence("identity", "identityid")
-              << Sequence("identity_nick", "nickid")
-              << Sequence("ircserver", "serverid")
-              << Sequence("network", "networkid")
-              << Sequence("quasseluser", "userid")
-              << Sequence("sender", "senderid");
+    sequences << Sequence("backlog", "messageid") << Sequence("buffer", "bufferid") << Sequence("identity", "identityid")
+              << Sequence("identity_nick", "nickid") << Sequence("ircserver", "serverid") << Sequence("network", "networkid")
+              << Sequence("quasseluser", "userid") << Sequence("sender", "senderid");
     QList<Sequence>::const_iterator iter;
     for (iter = sequences.constBegin(); iter != sequences.constEnd(); ++iter) {
         resetQuery();