qa: Resolve deprecation warnings in newer Qt versions
[quassel.git] / src / core / sqlitestorage.cpp
index bf6f3f7..b7a07fd 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 "sqlitestorage.h"
 
-#include <QtSql>
+#include <QByteArray>
+#include <QDataStream>
+#include <QLatin1String>
+#include <QVariant>
 
-#include "logmessage.h"
 #include "network.h"
 #include "quassel.h"
 
 int SqliteStorage::_maxRetryCount = 150;
 
-SqliteStorage::SqliteStorage(QObject *parent)
+SqliteStorage::SqliteStorage(QObjectparent)
     : AbstractSqlStorage(parent)
-{
-}
-
-
-SqliteStorage::~SqliteStorage()
-{
-}
-
+{}
 
 bool SqliteStorage::isAvailable() const
 {
-    if (!QSqlDatabase::isDriverAvailable("QSQLITE")) return false;
+    if (!QSqlDatabase::isDriverAvailable("QSQLITE"))
+        return false;
     return true;
 }
 
-
 QString SqliteStorage::backendId() const
 {
     return QString("SQLite");
 }
 
-
 QString SqliteStorage::displayName() const
 {
     // Note: Pre-0.13 clients use the displayName property for backend idenfication
@@ -61,7 +55,6 @@ QString SqliteStorage::displayName() const
     return backendId();
 }
 
-
 QString SqliteStorage::description() const
 {
     return tr("SQLite is a file-based database engine that does not require any setup. It is suitable for small and medium-sized "
@@ -69,7 +62,6 @@ QString SqliteStorage::description() const
               "it is running on, and if you only expect a few users to use your core.");
 }
 
-
 int SqliteStorage::installedSchemaVersion()
 {
     // only used when there is a singlethread (during startup)
@@ -86,24 +78,40 @@ int SqliteStorage::installedSchemaVersion()
     return AbstractSqlStorage::installedSchemaVersion();
 }
 
-
-bool SqliteStorage::updateSchemaVersion(int newVersion)
+bool SqliteStorage::updateSchemaVersion(int newVersion, bool clearUpgradeStep)
 {
     // only used when there is a singlethread (during startup)
     // so we don't need locking here
-    QSqlQuery query(logDb());
+
+    QSqlDatabase db = 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.
+    db.transaction();
+
+    QSqlQuery query(db);
     query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'");
     query.bindValue(":version", newVersion);
-    query.exec();
+    safeExec(query);
 
-    bool success = true;
-    if (query.lastError().isValid()) {
-        qCritical() << "SqliteStorage::updateSchemaVersion(int): Updating schema version failed!";
-        success = false;
+    if (!watchQuery(query)) {
+        qCritical() << "SqliteStorage::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 SqliteStorage::setupSchemaVersion(int version)
 {
@@ -122,8 +130,53 @@ bool SqliteStorage::setupSchemaVersion(int version)
     return success;
 }
 
+QString SqliteStorage::schemaVersionUpgradeStep()
+{
+    // Only used when there is a singlethread (during startup), so we don't need locking here
+    QSqlQuery query(logDb());
+    query.prepare("SELECT value FROM coreinfo WHERE key = 'schemaupgradestep'");
+    safeExec(query);
+    watchQuery(query);
+    if (query.first())
+        return query.value(0).toString();
+
+    // Fall back to the default value
+    return AbstractSqlStorage::schemaVersionUpgradeStep();
+}
 
-UserId SqliteStorage::addUser(const QString &user, const QString &password, const QString &authenticator)
+bool SqliteStorage::setSchemaVersionUpgradeStep(QString upgradeQuery)
+{
+    // Only used when there is a singlethread (during startup), so we don't need locking here
+
+    // 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);
+
+    // Don't wrap with watchQuery to avoid an alarming message in the log when the key is missing
+    // Make sure that the query didn't fail, and that some non-zero number of rows were affected
+    bool success = !query.lastError().isValid() && 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 SqliteStorage::addUser(const QString& user, const QString& password, const QString& authenticator)
 {
     QSqlDatabase db = logDb();
     UserId uid;
@@ -141,7 +194,8 @@ UserId SqliteStorage::addUser(const QString &user, const QString &password, cons
         query.bindValue(":authenticator", authenticator);
         lockForWrite();
         safeExec(query);
-        if (query.lastError().isValid() && query.lastError().number() == 19) { // user already exists - sadly 19 seems to be the general constraint violation error...
+        if (query.lastError().isValid()
+            && query.lastError().nativeErrorCode() == QLatin1String{"19"}) {  // user already exists - sadly 19 seems to be the general constraint violation error...
             db.rollback();
         }
         else {
@@ -156,8 +210,7 @@ UserId SqliteStorage::addUser(const QString &user, const QString &password, cons
     return uid;
 }
 
-
-bool SqliteStorage::updateUser(UserId user, const QString &password)
+bool SqliteStorage::updateUser(UserId user, const QString& password)
 {
     QSqlDatabase db = logDb();
     bool success = false;
@@ -178,8 +231,7 @@ bool SqliteStorage::updateUser(UserId user, const QString &password)
     return success;
 }
 
-
-void SqliteStorage::renameUser(UserId user, const QString &newName)
+void SqliteStorage::renameUser(UserId user, const QString& newName)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -196,8 +248,7 @@ void SqliteStorage::renameUser(UserId user, const QString &newName)
     emit userRenamed(user, newName);
 }
 
-
-UserId SqliteStorage::validateUser(const QString &user, const QString &password)
+UserId SqliteStorage::validateUser(const QString& user, const QString& password)
 {
     UserId userId;
     QString hashedPassword;
@@ -226,8 +277,7 @@ UserId SqliteStorage::validateUser(const QString &user, const QString &password)
     return returnUserId;
 }
 
-
-UserId SqliteStorage::getUserId(const QString &username)
+UserId SqliteStorage::getUserId(const QString& username)
 {
     UserId userId;
 
@@ -288,7 +338,6 @@ UserId SqliteStorage::internalUser()
     return userId;
 }
 
-
 void SqliteStorage::delUser(UserId user)
 {
     QSqlDatabase db = logDb();
@@ -320,8 +369,7 @@ void SqliteStorage::delUser(UserId user)
     emit userRemoved(user);
 }
 
-
-void SqliteStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data)
+void SqliteStorage::setUserSetting(UserId userId, const QString& settingName, const QVariant& data)
 {
     QByteArray rawData;
     QDataStream out(&rawData, QIODevice::WriteOnly);
@@ -352,8 +400,7 @@ void SqliteStorage::setUserSetting(UserId userId, const QString &settingName, co
     unlock();
 }
 
-
-QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData)
+QVariant SqliteStorage::getUserSetting(UserId userId, const QString& settingName, const QVariant& defaultData)
 {
     QVariant data = defaultData;
     {
@@ -375,8 +422,7 @@ QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName
     return data;
 }
 
-
-void SqliteStorage::setCoreState(const QVariantList &data)
+void SqliteStorage::setCoreState(const QVariantList& data)
 {
     QByteArray rawData;
     QDataStream out(&rawData, QIODevice::WriteOnly);
@@ -405,8 +451,7 @@ void SqliteStorage::setCoreState(const QVariantList &data)
     unlock();
 }
 
-
-QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData)
+QVariantList SqliteStorage::getCoreState(const QVariantList& defaultData)
 {
     QVariantList data;
     {
@@ -421,7 +466,8 @@ QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData)
             QDataStream in(&rawData, QIODevice::ReadOnly);
             in.setVersion(QDataStream::Qt_4_2);
             in >> data;
-        } else {
+        }
+        else {
             data = defaultData;
         }
     }
@@ -429,8 +475,7 @@ QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData)
     return data;
 }
 
-
-IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity)
+IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity& identity)
 {
     IdentityId identityId;
 
@@ -458,13 +503,8 @@ IdentityId SqliteStorage::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
 
         lockForWrite();
         safeExec(query);
@@ -481,7 +521,7 @@ IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity)
 
             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);
@@ -494,8 +534,7 @@ IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity)
     return identityId;
 }
 
-
-bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity)
+bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity& identity)
 {
     QSqlDatabase db = logDb();
     bool error = false;
@@ -537,13 +576,8 @@ bool SqliteStorage::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);
         watchQuery(query);
@@ -556,7 +590,7 @@ bool SqliteStorage::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);
@@ -568,7 +602,6 @@ bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity)
     return true;
 }
 
-
 void SqliteStorage::removeIdentity(UserId user, IdentityId identityId)
 {
     QSqlDatabase db = logDb();
@@ -607,10 +640,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();
 
@@ -645,10 +677,8 @@ QList<CoreIdentity> SqliteStorage::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;
@@ -657,8 +687,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();
     }
@@ -666,8 +696,7 @@ QList<CoreIdentity> SqliteStorage::identities(UserId user)
     return identities;
 }
 
-
-NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info)
+NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo& info)
 {
     NetworkId networkId;
 
@@ -692,13 +721,13 @@ NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info)
     }
     if (error) {
         unlock();
-        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);
@@ -714,13 +743,12 @@ NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info)
     }
     unlock();
     if (error)
-        return NetworkId();
+        return {};
     else
         return networkId;
 }
 
-
-void SqliteStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info)
+void SqliteStorage::bindNetworkInfo(QSqlQuery& query, const NetworkInfo& info)
 {
     query.bindValue(":networkname", info.networkName);
     query.bindValue(":identityid", info.identity.toInt());
@@ -745,12 +773,12 @@ void SqliteStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info)
     query.bindValue(":messagerateburstsize", info.messageRateBurstSize);
     query.bindValue(":messageratedelay", info.messageRateDelay);
     query.bindValue(":unlimitedmessagerate", info.unlimitedMessageRate ? 1 : 0);
+    query.bindValue(":skipcaps", info.skipCapsToString());
     if (info.networkId.isValid())
         query.bindValue(":networkid", info.networkId.toInt());
 }
 
-
-void SqliteStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server)
+void SqliteStorage::bindServerInfo(QSqlQuery& query, const Network::Server& server)
 {
     query.bindValue(":hostname", server.host);
     query.bindValue(":port", server.port);
@@ -766,8 +794,7 @@ void SqliteStorage::bindServerInfo(QSqlQuery &query, const Network::Server &serv
     query.bindValue(":sslverify", server.sslVerify ? 1 : 0);
 }
 
-
-bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info)
+bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo& info)
 {
     QSqlDatabase db = logDb();
     bool error = false;
@@ -809,7 +836,7 @@ bool SqliteStorage::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);
@@ -827,8 +854,7 @@ bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info)
     return !error;
 }
 
-
-bool SqliteStorage::removeNetwork(UserId user, const NetworkId &networkId)
+bool SqliteStorage::removeNetwork(UserId user, const NetworkId& networkId)
 {
     QSqlDatabase db = logDb();
     bool error = false;
@@ -901,10 +927,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();
@@ -946,6 +971,7 @@ QList<NetworkInfo> SqliteStorage::networks(UserId user)
                 net.messageRateBurstSize = networksQuery.value(20).toUInt();
                 net.messageRateDelay = networksQuery.value(21).toUInt();
                 net.unlimitedMessageRate = networksQuery.value(22).toInt() == 1 ? true : false;
+                net.skipCapsFromString(networksQuery.value(23).toString());
 
                 serversQuery.bindValue(":networkid", net.networkId.toInt());
                 safeExec(serversQuery);
@@ -972,7 +998,7 @@ QList<NetworkInfo> SqliteStorage::networks(UserId user)
                         servers << server;
                     }
                     net.serverList = servers;
-                    nets << net;
+                    nets.push_back(std::move(net));
                 }
             }
         }
@@ -982,10 +1008,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();
@@ -999,7 +1024,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();
     }
@@ -1007,8 +1032,7 @@ QList<NetworkId> SqliteStorage::connectedNetworks(UserId user)
     return connectedNets;
 }
 
-
-void SqliteStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected)
+void SqliteStorage::setNetworkConnected(UserId user, const NetworkId& networkId, bool isConnected)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1028,8 +1052,7 @@ void SqliteStorage::setNetworkConnected(UserId user, const NetworkId &networkId,
     unlock();
 }
 
-
-QHash<QString, QString> SqliteStorage::persistentChannels(UserId user, const NetworkId &networkId)
+QHash<QString, QString> SqliteStorage::persistentChannels(UserId user, const NetworkId& networkId)
 {
     QHash<QString, QString> persistentChans;
 
@@ -1052,8 +1075,7 @@ QHash<QString, QString> SqliteStorage::persistentChannels(UserId user, const Net
     return persistentChans;
 }
 
-
-void SqliteStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined)
+void SqliteStorage::setChannelPersistent(UserId user, const NetworkId& networkId, const QString& channel, bool isJoined)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1074,8 +1096,7 @@ void SqliteStorage::setChannelPersistent(UserId user, const NetworkId &networkId
     unlock();
 }
 
-
-void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key)
+void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId& networkId, const QString& channel, const QString& key)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1096,7 +1117,6 @@ void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networ
     unlock();
 }
 
-
 QString SqliteStorage::awayMessage(UserId user, NetworkId networkId)
 {
     QSqlDatabase db = logDb();
@@ -1121,8 +1141,7 @@ QString SqliteStorage::awayMessage(UserId user, NetworkId networkId)
     return awayMsg;
 }
 
-
-void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg)
+void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString& awayMsg)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1142,7 +1161,6 @@ void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QStri
     unlock();
 }
 
-
 QString SqliteStorage::userModes(UserId user, NetworkId networkId)
 {
     QSqlDatabase db = logDb();
@@ -1167,8 +1185,7 @@ QString SqliteStorage::userModes(UserId user, NetworkId networkId)
     return modes;
 }
 
-
-void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes)
+void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString& userModes)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1188,8 +1205,7 @@ void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString
     unlock();
 }
 
-
-BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create)
+BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId& networkId, BufferInfo::Type type, const QString& buffer, bool create)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1240,8 +1256,7 @@ BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, Bu
     return bufferInfo;
 }
 
-
-BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId)
+BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId& bufferId)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1257,7 +1272,11 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId)
         safeExec(query);
 
         if (watchQuery(query) && query.first()) {
-            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());
         }
         db.commit();
@@ -1266,10 +1285,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();
@@ -1283,7 +1301,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();
     }
@@ -1292,10 +1314,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();
@@ -1310,7 +1331,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();
     }
@@ -1319,8 +1340,7 @@ QList<BufferId> SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId
     return bufferList;
 }
 
-
-bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId)
+bool SqliteStorage::removeBuffer(const UserId& user, const BufferId& bufferId)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1363,8 +1383,7 @@ bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId)
     return !error;
 }
 
-
-bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName)
+bool SqliteStorage::renameBuffer(const UserId& user, const BufferId& bufferId, const QString& newName)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1383,7 +1402,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 {
@@ -1400,8 +1419,7 @@ bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, c
     return !error;
 }
 
-
-bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2)
+bool SqliteStorage::mergeBuffersPermanently(const UserId& user, const BufferId& bufferId1, const BufferId& bufferId2)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1457,8 +1475,35 @@ bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &
     return !error;
 }
 
+QHash<BufferId, MsgId> SqliteStorage::bufferLastMsgIds(UserId user)
+{
+    QHash<BufferId, MsgId> lastMsgHash;
+
+    QSqlDatabase db = logDb();
+    db.transaction();
+
+    bool error = false;
+    {
+        QSqlQuery query(db);
+        query.prepare(queryString("select_buffer_last_messages"));
+        query.bindValue(":userid", user.toInt());
+
+        lockForRead();
+        safeExec(query);
+        error = !watchQuery(query);
+        if (!error) {
+            while (query.next()) {
+                lastMsgHash[query.value(0).toInt()] = query.value(1).toLongLong();
+            }
+        }
+    }
 
-void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
+    db.commit();
+    unlock();
+    return lastMsgHash;
+}
+
+void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId& bufferId, const MsgId& msgId)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1478,7 +1523,6 @@ void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId,
     unlock();
 }
 
-
 QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user)
 {
     QHash<BufferId, MsgId> lastSeenHash;
@@ -1507,8 +1551,7 @@ QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user)
     return lastSeenHash;
 }
 
-
-void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
+void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId& bufferId, const MsgId& msgId)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1528,7 +1571,6 @@ void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId
     unlock();
 }
 
-
 QHash<BufferId, MsgId> SqliteStorage::bufferMarkerLineMsgIds(UserId user)
 {
     QHash<BufferId, MsgId> markerLineHash;
@@ -1567,7 +1609,7 @@ void SqliteStorage::setBufferActivity(UserId user, BufferId bufferId, Message::T
         query.prepare(queryString("update_buffer_bufferactivity"));
         query.bindValue(":userid", user.toInt());
         query.bindValue(":bufferid", bufferId.toInt());
-        query.bindValue(":bufferactivity", (int) bufferActivity);
+        query.bindValue(":bufferactivity", (int)bufferActivity);
 
         lockForWrite();
         safeExec(query);
@@ -1577,7 +1619,6 @@ void SqliteStorage::setBufferActivity(UserId user, BufferId bufferId, Message::T
     unlock();
 }
 
-
 QHash<BufferId, Message::Types> SqliteStorage::bufferActivities(UserId user)
 {
     QHash<BufferId, Message::Types> bufferActivityHash;
@@ -1606,13 +1647,12 @@ QHash<BufferId, Message::Types> SqliteStorage::bufferActivities(UserId user)
     return bufferActivityHash;
 }
 
-
 Message::Types SqliteStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMsgId)
 {
     QSqlDatabase db = logDb();
     db.transaction();
 
-    Message::Types result = Message::Types(nullptr);
+    Message::Types result{};
     {
         QSqlQuery query(db);
         query.prepare(queryString("select_buffer_bufferactivity"));
@@ -1630,7 +1670,7 @@ Message::Types SqliteStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMs
     return result;
 }
 
-QHash<QString, QByteArray> SqliteStorage::bufferCiphers(UserId user, const NetworkId &networkId)
+QHash<QString, QByteArray> SqliteStorage::bufferCiphers(UserId user, const NetworkIdnetworkId)
 {
     QHash<QString, QByteArray> bufferCiphers;
 
@@ -1653,7 +1693,7 @@ QHash<QString, QByteArray> SqliteStorage::bufferCiphers(UserId user, const Netwo
     return bufferCiphers;
 }
 
-void SqliteStorage::setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher)
+void SqliteStorage::setBufferCipher(UserId user, const NetworkId& networkId, const QString& bufferName, const QByteArray& cipher)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1694,7 +1734,6 @@ void SqliteStorage::setHighlightCount(UserId user, BufferId bufferId, int count)
     unlock();
 }
 
-
 QHash<BufferId, int> SqliteStorage::highlightCounts(UserId user)
 {
     QHash<BufferId, int> highlightCountHash;
@@ -1723,7 +1762,6 @@ QHash<BufferId, int> SqliteStorage::highlightCounts(UserId user)
     return highlightCountHash;
 }
 
-
 int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
 {
     QSqlDatabase db = logDb();
@@ -1747,7 +1785,7 @@ int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
     return result;
 }
 
-bool SqliteStorage::logMessage(Message &msg)
+bool SqliteStorage::logMessage(Messagemsg)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1773,7 +1811,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());
@@ -1809,8 +1847,7 @@ bool SqliteStorage::logMessage(Message &msg)
     return !error;
 }
 
-
-bool SqliteStorage::logMessages(MessageList &msgs)
+bool SqliteStorage::logMessages(MessageList& msgs)
 {
     QSqlDatabase db = logDb();
     db.transaction();
@@ -1821,8 +1858,8 @@ bool SqliteStorage::logMessages(MessageList &msgs)
         addSenderQuery.prepare(queryString("insert_sender"));
         lockForWrite();
         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 (senders.contains(sender))
                 continue;
             senders << sender;
@@ -1839,7 +1876,7 @@ bool SqliteStorage::logMessages(MessageList &msgs)
         QSqlQuery logMessageQuery(db);
         logMessageQuery.prepare(queryString("insert_message"));
         for (int i = 0; i < msgs.count(); i++) {
-            Message &msg = msgs[i];
+            Messagemsg = msgs[i];
             // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
             // seconds.  This nets us more precision as well as simplifying 64-bit time.
             logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
@@ -1878,10 +1915,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();
@@ -1900,7 +1936,11 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
         safeExec(bufferInfoQuery);
         error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first();
         if (!error) {
-            bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
+            bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(),
+                                    bufferInfoQuery.value(1).toInt(),
+                                    (BufferInfo::Type)bufferInfoQuery.value(2).toInt(),
+                                    0,
+                                    bufferInfoQuery.value(4).toString());
             error = !bufferInfo.isValid();
         }
     }
@@ -1944,7 +1984,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();
@@ -1953,10 +1993,10 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
     return messagelist;
 }
 
-
-QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+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();
@@ -1975,7 +2015,11 @@ QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId
         safeExec(bufferInfoQuery);
         error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first();
         if (!error) {
-            bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
+            bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(),
+                                    bufferInfoQuery.value(1).toInt(),
+                                    (BufferInfo::Type)bufferInfoQuery.value(2).toInt(),
+                                    0,
+                                    bufferInfoQuery.value(4).toString());
             error = !bufferInfo.isValid();
         }
     }
@@ -2011,20 +2055,20 @@ QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId
 
         while (query.next()) {
             Message msg(
-                        // As of SQLite schema version 31, timestamps are stored in milliseconds
-                        // instead of seconds.  This nets us more precision as well as simplifying
-                        // 64-bit time.
-                        QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
-                        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()});
+                // As of SQLite schema version 31, timestamps are stored in milliseconds
+                // instead of seconds.  This nets us more precision as well as simplifying
+                // 64-bit time.
+                QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
+                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 << msg;
+            messagelist.push_back(std::move(msg));
         }
     }
     db.commit();
@@ -2033,10 +2077,97 @@ QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId
     return messagelist;
 }
 
+std::vector<Message> SqliteStorage::requestMsgsForward(
+    UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+    std::vector<Message> messagelist;
+
+    QSqlDatabase db = logDb();
+    db.transaction();
+
+    bool error = false;
+    BufferInfo bufferInfo;
+    {
+        // code dupication from getBufferInfo:
+        // this is due to the impossibility of nesting transactions and recursive locking
+        QSqlQuery bufferInfoQuery(db);
+        bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
+        bufferInfoQuery.bindValue(":userid", user.toInt());
+        bufferInfoQuery.bindValue(":bufferid", bufferId.toInt());
+
+        lockForRead();
+        safeExec(bufferInfoQuery);
+        error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first();
+        if (!error) {
+            bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(),
+                                    bufferInfoQuery.value(1).toInt(),
+                                    (BufferInfo::Type)bufferInfoQuery.value(2).toInt(),
+                                    0,
+                                    bufferInfoQuery.value(4).toString());
+            error = !bufferInfo.isValid();
+        }
+    }
+    if (error) {
+        db.rollback();
+        unlock();
+        return messagelist;
+    }
+
+    {
+        QSqlQuery query(db);
+        query.prepare(queryString("select_messagesForward"));
+
+        if (first == -1) {
+            query.bindValue(":firstmsg", std::numeric_limits<qint64>::min());
+        } else {
+            query.bindValue(":firstmsg", first.toQint64());
+        }
+
+        if (last == -1) {
+            query.bindValue(":lastmsg", std::numeric_limits<qint64>::max());
+        } else {
+            query.bindValue(":lastmsg", last.toQint64());
+        }
+
+        query.bindValue(":bufferid", bufferId.toInt());
+
+        int typeRaw = type;
+        int flagsRaw = flags;
+        query.bindValue(":type", typeRaw);
+        query.bindValue(":flags", flagsRaw);
+
+        query.bindValue(":limit", limit);
+
+        safeExec(query);
+        watchQuery(query);
+
+        while (query.next()) {
+            Message msg(
+                // As of SQLite schema version 31, timestamps are stored in milliseconds
+                // instead of seconds.  This nets us more precision as well as simplifying
+                // 64-bit time.
+                QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
+                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();
+    unlock();
+
+    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();
@@ -2051,7 +2182,11 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
         safeExec(bufferInfoQuery);
         watchQuery(bufferInfoQuery);
         while (bufferInfoQuery.next()) {
-            BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString());
+            BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(),
+                                               bufferInfoQuery.value(1).toInt(),
+                                               (BufferInfo::Type)bufferInfoQuery.value(2).toInt(),
+                                               bufferInfoQuery.value(3).toInt(),
+                                               bufferInfoQuery.value(4).toString());
             bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
         }
 
@@ -2084,7 +2219,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();
@@ -2092,9 +2227,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();
@@ -2109,7 +2244,11 @@ QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M
         safeExec(bufferInfoQuery);
         watchQuery(bufferInfoQuery);
         while (bufferInfoQuery.next()) {
-            BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString());
+            BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(),
+                                               bufferInfoQuery.value(1).toInt(),
+                                               (BufferInfo::Type)bufferInfoQuery.value(2).toInt(),
+                                               bufferInfoQuery.value(3).toInt(),
+                                               bufferInfoQuery.value(4).toString());
             bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
         }
 
@@ -2134,20 +2273,20 @@ QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M
 
         while (query.next()) {
             Message msg(
-                        // As of SQLite schema version 31, timestamps are stored in milliseconds
-                        // instead of seconds.  This nets us more precision as well as simplifying
-                        // 64-bit time.
-                        QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()),
-                        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()});
+                // As of SQLite schema version 31, timestamps are stored in milliseconds
+                // instead of seconds.  This nets us more precision as well as simplifying
+                // 64-bit time.
+                QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()),
+                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 << msg;
+            messagelist.push_back(std::move(msg));
         }
     }
     db.commit();
@@ -2177,43 +2316,35 @@ QMap<UserId, QString> SqliteStorage::getAllAuthUserNames()
     return authusernames;
 }
 
-
 QString SqliteStorage::backlogFile()
 {
     return Quassel::configDirPath() + "quassel-storage.sqlite";
 }
 
-
-bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount)
+bool SqliteStorage::safeExec(QSqlQuery& query, int retryCount)
 {
     query.exec();
 
     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;
 }
 
-
 // ========================================
 //  SqliteMigration
 // ========================================
 SqliteMigrationReader::SqliteMigrationReader()
-    : SqliteStorage(),
-    _maxId(0)
-{
-}
-
+    : SqliteStorage()
+{}
 
 void SqliteMigrationReader::setMaxId(MigrationObject mo)
 {
@@ -2234,7 +2365,6 @@ void SqliteMigrationReader::setMaxId(MigrationObject mo)
     _maxId = query.value(0).toLongLong();
 }
 
-
 bool SqliteMigrationReader::prepareQuery(MigrationObject mo)
 {
     setMaxId(mo);
@@ -2278,8 +2408,7 @@ bool SqliteMigrationReader::prepareQuery(MigrationObject mo)
     return exec();
 }
 
-
-bool SqliteMigrationReader::readMo(QuasselUserMO &user)
+bool SqliteMigrationReader::readMo(QuasselUserMO& user)
 {
     if (!next())
         return false;
@@ -2292,8 +2421,7 @@ bool SqliteMigrationReader::readMo(QuasselUserMO &user)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(IdentityMO &identity)
+bool SqliteMigrationReader::readMo(IdentityMO& identity)
 {
     if (!next())
         return false;
@@ -2322,8 +2450,7 @@ bool SqliteMigrationReader::readMo(IdentityMO &identity)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick)
+bool SqliteMigrationReader::readMo(IdentityNickMO& identityNick)
 {
     if (!next())
         return false;
@@ -2334,8 +2461,7 @@ bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(NetworkMO &network)
+bool SqliteMigrationReader::readMo(NetworkMO& network)
 {
     if (!next())
         return false;
@@ -2370,11 +2496,12 @@ bool SqliteMigrationReader::readMo(NetworkMO &network)
     network.messagerateburstsize = value(26).toInt();
     network.messageratedelay = value(27).toUInt();
     network.unlimitedmessagerate = value(28).toInt() == 1 ? true : false;
+    // Skipped IRCv3 caps
+    network.skipcaps = value(29).toString();
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(BufferMO &buffer)
+bool SqliteMigrationReader::readMo(BufferMO& buffer)
 {
     if (!next())
         return false;
@@ -2397,8 +2524,7 @@ bool SqliteMigrationReader::readMo(BufferMO &buffer)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(SenderMO &sender)
+bool SqliteMigrationReader::readMo(SenderMO& sender)
 {
     int skipSteps = 0;
     while (!next()) {
@@ -2421,8 +2547,7 @@ bool SqliteMigrationReader::readMo(SenderMO &sender)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(BacklogMO &backlog)
+bool SqliteMigrationReader::readMo(BacklogMO& backlog)
 {
     qint64 skipSteps = 0;
     while (!next()) {
@@ -2451,8 +2576,7 @@ bool SqliteMigrationReader::readMo(BacklogMO &backlog)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(IrcServerMO &ircserver)
+bool SqliteMigrationReader::readMo(IrcServerMO& ircserver)
 {
     if (!next())
         return false;
@@ -2475,8 +2599,7 @@ bool SqliteMigrationReader::readMo(IrcServerMO &ircserver)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(UserSettingMO &userSetting)
+bool SqliteMigrationReader::readMo(UserSettingMO& userSetting)
 {
     if (!next())
         return false;
@@ -2488,8 +2611,7 @@ bool SqliteMigrationReader::readMo(UserSettingMO &userSetting)
     return true;
 }
 
-
-bool SqliteMigrationReader::readMo(CoreStateMO &coreState)
+bool SqliteMigrationReader::readMo(CoreStateMO& coreState)
 {
     if (!next())
         return false;