diff --git a/src/AvatarProvider.cpp b/src/AvatarProvider.cpp
index 4c3969be..1834e040 100644
--- a/src/AvatarProvider.cpp
+++ b/src/AvatarProvider.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QBuffer>
#include <QPixmapCache>
diff --git a/src/AvatarProvider.h b/src/AvatarProvider.h
index 47ed028e..0bea1a8f 100644
--- a/src/AvatarProvider.h
+++ b/src/AvatarProvider.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/BlurhashProvider.cpp b/src/BlurhashProvider.cpp
index acaef400..12a27b82 100644
--- a/src/BlurhashProvider.cpp
+++ b/src/BlurhashProvider.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "BlurhashProvider.h"
#include <algorithm>
diff --git a/src/BlurhashProvider.h b/src/BlurhashProvider.h
index 48c945de..ee89302c 100644
--- a/src/BlurhashProvider.h
+++ b/src/BlurhashProvider.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QQuickAsyncImageProvider>
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 8cf66d21..0817a2d1 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <limits>
#include <stdexcept>
@@ -50,9 +38,10 @@
static const std::string CURRENT_CACHE_FORMAT_VERSION("2020.10.20");
static const std::string SECRET("secret");
-static lmdb::val NEXT_BATCH_KEY("next_batch");
-static lmdb::val OLM_ACCOUNT_KEY("olm_account");
-static lmdb::val CACHE_FORMAT_VERSION_KEY("cache_format_version");
+//! Keys used for the DB
+static const std::string_view NEXT_BATCH_KEY("next_batch");
+static const std::string_view OLM_ACCOUNT_KEY("olm_account");
+static const std::string_view CACHE_FORMAT_VERSION_KEY("cache_format_version");
constexpr size_t MAX_RESTORED_MESSAGES = 30'000;
@@ -151,16 +140,6 @@ Cache::isHiddenEvent(lmdb::txn &txn,
Cache::Cache(const QString &userId, QObject *parent)
: QObject{parent}
, env_{nullptr}
- , syncStateDb_{0}
- , roomsDb_{0}
- , invitesDb_{0}
- , mediaDb_{0}
- , readReceiptsDb_{0}
- , notificationsDb_{0}
- , devicesDb_{0}
- , deviceKeysDb_{0}
- , inboundMegolmSessionDb_{0}
- , outboundMegolmSessionDb_{0}
, localUserId_{userId}
{
setup();
@@ -266,17 +245,17 @@ Cache::setEncryptedRoom(lmdb::txn &txn, const std::string &room_id)
nhlog::db()->info("mark room {} as encrypted", room_id);
auto db = lmdb::dbi::open(txn, ENCRYPTED_ROOMS_DB, MDB_CREATE);
- lmdb::dbi_put(txn, db, lmdb::val(room_id), lmdb::val("0"));
+ db.put(txn, room_id, "0");
}
bool
Cache::isRoomEncrypted(const std::string &room_id)
{
- lmdb::val unused;
+ std::string_view unused;
auto txn = lmdb::txn::begin(env_);
auto db = lmdb::dbi::open(txn, ENCRYPTED_ROOMS_DB, MDB_CREATE);
- auto res = lmdb::dbi_get(txn, db, lmdb::val(room_id), unused);
+ auto res = db.get(txn, room_id, unused);
txn.commit();
return res;
@@ -292,12 +271,12 @@ Cache::exportSessionKeys()
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto cursor = lmdb::cursor::open(txn, inboundMegolmSessionDb_);
- std::string key, value;
+ std::string_view key, value;
while (cursor.get(key, value, MDB_NEXT)) {
ExportedSession exported;
MegolmSessionIndex index;
- auto saved_session = unpickle<InboundSessionObject>(value, SECRET);
+ auto saved_session = unpickle<InboundSessionObject>(std::string(value), SECRET);
try {
index = nlohmann::json::parse(key).get<MegolmSessionIndex>();
@@ -349,7 +328,7 @@ Cache::saveInboundMegolmSession(const MegolmSessionIndex &index,
const auto pickled = pickle<InboundSessionObject>(session.get(), SECRET);
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(txn, inboundMegolmSessionDb_, lmdb::val(key), lmdb::val(pickled));
+ inboundMegolmSessionDb_.put(txn, key, pickled);
txn.commit();
}
@@ -361,11 +340,10 @@ Cache::getInboundMegolmSession(const MegolmSessionIndex &index)
try {
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
std::string key = json(index).dump();
- lmdb::val value;
+ std::string_view value;
- if (lmdb::dbi_get(txn, inboundMegolmSessionDb_, lmdb::val(key), value)) {
- auto session = unpickle<InboundSessionObject>(
- std::string(value.data(), value.size()), SECRET);
+ if (inboundMegolmSessionDb_.get(txn, key, value)) {
+ auto session = unpickle<InboundSessionObject>(std::string(value), SECRET);
return session;
}
} catch (std::exception &e) {
@@ -383,9 +361,9 @@ Cache::inboundMegolmSessionExists(const MegolmSessionIndex &index)
try {
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
std::string key = json(index).dump();
- lmdb::val value;
+ std::string_view value;
- return lmdb::dbi_get(txn, inboundMegolmSessionDb_, lmdb::val(key), value);
+ return inboundMegolmSessionDb_.get(txn, key, value);
} catch (std::exception &e) {
nhlog::db()->error("Failed to get inbound megolm session {}", e.what());
}
@@ -414,7 +392,7 @@ Cache::updateOutboundMegolmSession(const std::string &room_id,
j["session"] = pickle<OutboundSessionObject>(ptr.get(), SECRET);
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(txn, outboundMegolmSessionDb_, lmdb::val(room_id), lmdb::val(j.dump()));
+ outboundMegolmSessionDb_.put(txn, room_id, j.dump());
txn.commit();
}
@@ -428,7 +406,7 @@ Cache::dropOutboundMegolmSession(const std::string &room_id)
{
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_del(txn, outboundMegolmSessionDb_, lmdb::val(room_id), nullptr);
+ outboundMegolmSessionDb_.del(txn, room_id);
txn.commit();
}
}
@@ -446,7 +424,7 @@ Cache::saveOutboundMegolmSession(const std::string &room_id,
j["session"] = pickled;
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(txn, outboundMegolmSessionDb_, lmdb::val(room_id), lmdb::val(j.dump()));
+ outboundMegolmSessionDb_.put(txn, room_id, j.dump());
txn.commit();
}
@@ -455,8 +433,8 @@ Cache::outboundMegolmSessionExists(const std::string &room_id) noexcept
{
try {
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val value;
- return lmdb::dbi_get(txn, outboundMegolmSessionDb_, lmdb::val(room_id), value);
+ std::string_view value;
+ return outboundMegolmSessionDb_.get(txn, room_id, value);
} catch (std::exception &e) {
nhlog::db()->error("Failed to retrieve outbound Megolm Session: {}", e.what());
return false;
@@ -470,9 +448,9 @@ Cache::getOutboundMegolmSession(const std::string &room_id)
using namespace mtx::crypto;
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val value;
- lmdb::dbi_get(txn, outboundMegolmSessionDb_, lmdb::val(room_id), value);
- auto obj = json::parse(std::string_view(value.data(), value.size()));
+ std::string_view value;
+ outboundMegolmSessionDb_.get(txn, room_id, value);
+ auto obj = json::parse(value);
OutboundGroupSessionDataRef ref{};
ref.data = obj.at("data").get<OutboundGroupSessionData>();
@@ -505,7 +483,7 @@ Cache::saveOlmSession(const std::string &curve25519,
stored_session.pickled_session = pickled;
stored_session.last_message_ts = timestamp;
- lmdb::dbi_put(txn, db, lmdb::val(session_id), lmdb::val(json(stored_session).dump()));
+ db.put(txn, session_id, json(stored_session).dump());
txn.commit();
}
@@ -518,14 +496,13 @@ Cache::getOlmSession(const std::string &curve25519, const std::string &session_i
auto txn = lmdb::txn::begin(env_);
auto db = getOlmSessionsDb(txn, curve25519);
- lmdb::val pickled;
- bool found = lmdb::dbi_get(txn, db, lmdb::val(session_id), pickled);
+ std::string_view pickled;
+ bool found = db.get(txn, session_id, pickled);
txn.commit();
if (found) {
- std::string_view raw(pickled.data(), pickled.size());
- auto data = json::parse(raw).get<StoredOlmSession>();
+ auto data = json::parse(pickled).get<StoredOlmSession>();
return unpickle<SessionObject>(data.pickled_session, SECRET);
}
@@ -540,15 +517,13 @@ Cache::getLatestOlmSession(const std::string &curve25519)
auto txn = lmdb::txn::begin(env_);
auto db = getOlmSessionsDb(txn, curve25519);
- std::string session_id, pickled_session;
+ std::string_view session_id, pickled_session;
std::optional<StoredOlmSession> currentNewest;
auto cursor = lmdb::cursor::open(txn, db);
while (cursor.get(session_id, pickled_session, MDB_NEXT)) {
- auto data =
- json::parse(std::string_view(pickled_session.data(), pickled_session.size()))
- .get<StoredOlmSession>();
+ auto data = json::parse(pickled_session).get<StoredOlmSession>();
if (!currentNewest || currentNewest->last_message_ts < data.last_message_ts)
currentNewest = data;
}
@@ -569,7 +544,7 @@ Cache::getOlmSessions(const std::string &curve25519)
auto txn = lmdb::txn::begin(env_);
auto db = getOlmSessionsDb(txn, curve25519);
- std::string session_id, unused;
+ std::string_view session_id, unused;
std::vector<std::string> res;
auto cursor = lmdb::cursor::open(txn, db);
@@ -586,7 +561,7 @@ void
Cache::saveOlmAccount(const std::string &data)
{
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(txn, syncStateDb_, OLM_ACCOUNT_KEY, lmdb::val(data));
+ syncStateDb_.put(txn, OLM_ACCOUNT_KEY, data);
txn.commit();
}
@@ -594,8 +569,8 @@ std::string
Cache::restoreOlmAccount()
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val pickled;
- lmdb::dbi_get(txn, syncStateDb_, OLM_ACCOUNT_KEY, pickled);
+ std::string_view pickled;
+ syncStateDb_.get(txn, OLM_ACCOUNT_KEY, pickled);
txn.commit();
return std::string(pickled.data(), pickled.size());
@@ -688,10 +663,7 @@ Cache::saveImage(const std::string &url, const std::string &img_data)
try {
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(txn,
- mediaDb_,
- lmdb::val(url.data(), url.size()),
- lmdb::val(img_data.data(), img_data.size()));
+ mediaDb_.put(txn, url, img_data);
txn.commit();
} catch (const lmdb::error &e) {
@@ -706,14 +678,14 @@ Cache::saveImage(const QString &url, const QByteArray &image)
}
QByteArray
-Cache::image(lmdb::txn &txn, const std::string &url) const
+Cache::image(lmdb::txn &txn, const std::string &url)
{
if (url.empty())
return QByteArray();
try {
- lmdb::val image;
- bool res = lmdb::dbi_get(txn, mediaDb_, lmdb::val(url), image);
+ std::string_view image;
+ bool res = mediaDb_.get(txn, url, image);
if (!res)
return QByteArray();
@@ -727,19 +699,19 @@ Cache::image(lmdb::txn &txn, const std::string &url) const
}
QByteArray
-Cache::image(const QString &url) const
+Cache::image(const QString &url)
{
if (url.isEmpty())
return QByteArray();
- auto key = url.toUtf8();
+ auto key = url.toStdString();
try {
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val image;
+ std::string_view image;
- bool res = lmdb::dbi_get(txn, mediaDb_, lmdb::val(key.data(), key.size()), image);
+ bool res = mediaDb_.get(txn, key, image);
txn.commit();
@@ -757,9 +729,9 @@ Cache::image(const QString &url) const
void
Cache::removeInvite(lmdb::txn &txn, const std::string &room_id)
{
- lmdb::dbi_del(txn, invitesDb_, lmdb::val(room_id), nullptr);
- lmdb::dbi_drop(txn, getInviteStatesDb(txn, room_id), true);
- lmdb::dbi_drop(txn, getInviteMembersDb(txn, room_id), true);
+ invitesDb_.del(txn, room_id);
+ getInviteStatesDb(txn, room_id).drop(txn, true);
+ getInviteMembersDb(txn, room_id).drop(txn, true);
}
void
@@ -773,24 +745,24 @@ Cache::removeInvite(const std::string &room_id)
void
Cache::removeRoom(lmdb::txn &txn, const std::string &roomid)
{
- lmdb::dbi_del(txn, roomsDb_, lmdb::val(roomid), nullptr);
- lmdb::dbi_drop(txn, getStatesDb(txn, roomid), true);
- lmdb::dbi_drop(txn, getAccountDataDb(txn, roomid), true);
- lmdb::dbi_drop(txn, getMembersDb(txn, roomid), true);
+ roomsDb_.del(txn, roomid);
+ getStatesDb(txn, roomid).drop(txn, true);
+ getAccountDataDb(txn, roomid).drop(txn, true);
+ getMembersDb(txn, roomid).drop(txn, true);
}
void
Cache::removeRoom(const std::string &roomid)
{
auto txn = lmdb::txn::begin(env_, nullptr, 0);
- lmdb::dbi_del(txn, roomsDb_, lmdb::val(roomid), nullptr);
+ roomsDb_.del(txn, roomid);
txn.commit();
}
void
Cache::setNextBatchToken(lmdb::txn &txn, const std::string &token)
{
- lmdb::dbi_put(txn, syncStateDb_, NEXT_BATCH_KEY, lmdb::val(token.data(), token.size()));
+ syncStateDb_.put(txn, NEXT_BATCH_KEY, token);
}
void
@@ -800,12 +772,12 @@ Cache::setNextBatchToken(lmdb::txn &txn, const QString &token)
}
bool
-Cache::isInitialized() const
+Cache::isInitialized()
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val token;
+ std::string_view token;
- bool res = lmdb::dbi_get(txn, syncStateDb_, NEXT_BATCH_KEY, token);
+ bool res = syncStateDb_.get(txn, NEXT_BATCH_KEY, token);
txn.commit();
@@ -813,12 +785,15 @@ Cache::isInitialized() const
}
std::string
-Cache::nextBatchToken() const
+Cache::nextBatchToken()
{
+ if (!env_.handle())
+ throw lmdb::error("Env already closed", MDB_INVALID);
+
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val token;
+ std::string_view token;
- auto result = lmdb::dbi_get(txn, syncStateDb_, NEXT_BATCH_KEY, token);
+ bool result = syncStateDb_.get(txn, NEXT_BATCH_KEY, token);
txn.commit();
@@ -866,8 +841,8 @@ Cache::runMigrations()
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val current_version;
- bool res = lmdb::dbi_get(txn, syncStateDb_, CACHE_FORMAT_VERSION_KEY, current_version);
+ std::string_view current_version;
+ bool res = syncStateDb_.get(txn, CACHE_FORMAT_VERSION_KEY, current_version);
txn.commit();
@@ -909,7 +884,7 @@ Cache::runMigrations()
{
auto roomsCursor =
lmdb::cursor::open(txn, messagesDb);
- lmdb::val ts, stored_message;
+ std::string_view ts, stored_message;
bool start = true;
mtx::responses::Timeline oldMessages;
while (roomsCursor.get(ts,
@@ -971,7 +946,7 @@ Cache::runMigrations()
auto mainDb = lmdb::dbi::open(txn, nullptr);
- std::string dbName, ignored;
+ std::string_view dbName, ignored;
auto olmDbCursor = lmdb::cursor::open(txn, mainDb);
while (olmDbCursor.get(dbName, ignored, MDB_NEXT)) {
// skip every db but olm session dbs
@@ -981,9 +956,9 @@ Cache::runMigrations()
nhlog::db()->debug("Migrating {}", dbName);
- auto olmDb = lmdb::dbi::open(txn, dbName.c_str());
+ auto olmDb = lmdb::dbi::open(txn, std::string(dbName).c_str());
- std::string session_id, session_value;
+ std::string_view session_id, session_value;
std::vector<std::pair<std::string, StoredOlmSession>> sessions;
@@ -1011,18 +986,15 @@ Cache::runMigrations()
olmDb.drop(txn, true);
- auto newDbName = dbName;
+ auto newDbName = std::string(dbName);
newDbName.erase(0, sizeof("olm_sessions") - 1);
newDbName = "olm_sessions.v2" + newDbName;
auto newDb = lmdb::dbi::open(txn, newDbName.c_str(), MDB_CREATE);
for (const auto &[key, value] : sessions) {
- nhlog::db()->debug("{}\n{}", key, json(value).dump());
- lmdb::dbi_put(txn,
- newDb,
- lmdb::val(key),
- lmdb::val(json(value).dump()));
+ // nhlog::db()->debug("{}\n{}", key, json(value).dump());
+ newDb.put(txn, key, json(value).dump());
}
}
olmDbCursor.close();
@@ -1057,8 +1029,8 @@ Cache::formatVersion()
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val current_version;
- bool res = lmdb::dbi_get(txn, syncStateDb_, CACHE_FORMAT_VERSION_KEY, current_version);
+ std::string_view current_version;
+ bool res = syncStateDb_.get(txn, CACHE_FORMAT_VERSION_KEY, current_version);
txn.commit();
@@ -1080,11 +1052,7 @@ Cache::setCurrentFormat()
{
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(
- txn,
- syncStateDb_,
- CACHE_FORMAT_VERSION_KEY,
- lmdb::val(CURRENT_CACHE_FORMAT_VERSION.data(), CURRENT_CACHE_FORMAT_VERSION.size()));
+ syncStateDb_.put(txn, CACHE_FORMAT_VERSION_KEY, CURRENT_CACHE_FORMAT_VERSION);
txn.commit();
}
@@ -1101,10 +1069,9 @@ Cache::readReceipts(const QString &event_id, const QString &room_id)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto key = json_key.dump();
- lmdb::val value;
+ std::string_view value;
- bool res =
- lmdb::dbi_get(txn, readReceiptsDb_, lmdb::val(key.data(), key.size()), value);
+ bool res = readReceiptsDb_.get(txn, key, value);
txn.commit();
@@ -1139,10 +1106,9 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
try {
const auto key = json_key.dump();
- lmdb::val prev_value;
+ std::string_view prev_value;
- bool exists = lmdb::dbi_get(
- txn, readReceiptsDb_, lmdb::val(key.data(), key.size()), prev_value);
+ bool exists = readReceiptsDb_.get(txn, key, prev_value);
std::map<std::string, uint64_t> saved_receipts;
@@ -1169,10 +1135,7 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
nlohmann::json json_updated_value = saved_receipts;
std::string merged_receipts = json_updated_value.dump();
- lmdb::dbi_put(txn,
- readReceiptsDb_,
- lmdb::val(key.data(), key.size()),
- lmdb::val(merged_receipts.data(), merged_receipts.size()));
+ readReceiptsDb_.put(txn, key, merged_receipts);
} catch (const lmdb::error &e) {
nhlog::db()->critical("updateReadReceipts: {}", e.what());
@@ -1240,10 +1203,7 @@ Cache::saveState(const mtx::responses::Sync &res)
std::visit(
[&txn, &accountDataDb](const auto &event) {
auto j = json(event);
- lmdb::dbi_put(txn,
- accountDataDb,
- lmdb::val(j["type"].get<std::string>()),
- lmdb::val(j.dump()));
+ accountDataDb.put(txn, j["type"].get<std::string>(), j.dump());
},
ev);
}
@@ -1275,10 +1235,8 @@ Cache::saveState(const mtx::responses::Sync &res)
std::visit(
[&txn, &accountDataDb](const auto &event) {
auto j = json(event);
- lmdb::dbi_put(txn,
- accountDataDb,
- lmdb::val(j["type"].get<std::string>()),
- lmdb::val(j.dump()));
+ accountDataDb.put(
+ txn, j["type"].get<std::string>(), j.dump());
},
evt);
@@ -1300,8 +1258,8 @@ Cache::saveState(const mtx::responses::Sync &res)
}
if (!has_new_tags) {
// retrieve the old tags, they haven't changed
- lmdb::val data;
- if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), data)) {
+ std::string_view data;
+ if (roomsDb_.get(txn, room.first, data)) {
try {
RoomInfo tmp =
json::parse(std::string_view(data.data(), data.size()));
@@ -1316,8 +1274,7 @@ Cache::saveState(const mtx::responses::Sync &res)
}
}
- lmdb::dbi_put(
- txn, roomsDb_, lmdb::val(room.first), lmdb::val(json(updatedInfo).dump()));
+ roomsDb_.put(txn, room.first, json(updatedInfo).dump());
for (const auto &e : room.second.ephemeral.events) {
if (auto receiptsEv = std::get_if<
@@ -1397,8 +1354,7 @@ Cache::saveInvites(lmdb::txn &txn, const std::map<std::string, mtx::responses::I
getInviteRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
updatedInfo.is_invite = true;
- lmdb::dbi_put(
- txn, invitesDb_, lmdb::val(room.first), lmdb::val(json(updatedInfo).dump()));
+ invitesDb_.put(txn, room.first, json(updatedInfo).dump());
}
}
@@ -1419,16 +1375,13 @@ Cache::saveInvite(lmdb::txn &txn,
MemberInfo tmp{display_name, msg->content.avatar_url};
- lmdb::dbi_put(
- txn, membersdb, lmdb::val(msg->state_key), lmdb::val(json(tmp).dump()));
+ membersdb.put(txn, msg->state_key, json(tmp).dump());
} else {
std::visit(
[&txn, &statesdb](auto msg) {
- auto j = json(msg);
- bool res = lmdb::dbi_put(txn,
- statesdb,
- lmdb::val(j["type"].get<std::string>()),
- lmdb::val(j.dump()));
+ auto j = json(msg);
+ bool res =
+ statesdb.put(txn, j["type"].get<std::string>(), j.dump());
if (!res)
nhlog::db()->warn("couldn't save data: {}",
@@ -1447,10 +1400,7 @@ Cache::savePresence(
for (const auto &update : presenceUpdates) {
auto presenceDb = getPresenceDb(txn);
- lmdb::dbi_put(txn,
- presenceDb,
- lmdb::val(update.sender),
- lmdb::val(json(update.content).dump()));
+ presenceDb.put(txn, update.sender, json(update.content).dump());
}
}
@@ -1517,12 +1467,12 @@ Cache::singleRoomInfo(const std::string &room_id)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto statesdb = getStatesDb(txn, room_id);
- lmdb::val data;
+ std::string_view data;
// Check if the room is joined.
- if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room_id), data)) {
+ if (roomsDb_.get(txn, room_id, data)) {
try {
- RoomInfo tmp = json::parse(std::string_view(data.data(), data.size()));
+ RoomInfo tmp = json::parse(data);
tmp.member_count = getMembersDb(txn, room_id).size(txn);
tmp.join_rule = getRoomJoinRule(txn, statesdb);
tmp.guest_access = getRoomGuestAccess(txn, statesdb);
@@ -1552,14 +1502,13 @@ Cache::getRoomInfo(const std::vector<std::string> &rooms)
auto txn = lmdb::txn::begin(env_);
for (const auto &room : rooms) {
- lmdb::val data;
+ std::string_view data;
auto statesdb = getStatesDb(txn, room);
// Check if the room is joined.
- if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room), data)) {
+ if (roomsDb_.get(txn, room, data)) {
try {
- RoomInfo tmp =
- json::parse(std::string_view(data.data(), data.size()));
+ RoomInfo tmp = json::parse(data);
tmp.member_count = getMembersDb(txn, room).size(txn);
tmp.join_rule = getRoomJoinRule(txn, statesdb);
tmp.guest_access = getRoomGuestAccess(txn, statesdb);
@@ -1573,10 +1522,9 @@ Cache::getRoomInfo(const std::vector<std::string> &rooms)
}
} else {
// Check if the room is an invite.
- if (lmdb::dbi_get(txn, invitesDb_, lmdb::val(room), data)) {
+ if (invitesDb_.get(txn, room, data)) {
try {
- RoomInfo tmp =
- json::parse(std::string_view(data.data(), data.size()));
+ RoomInfo tmp = json::parse(std::string_view(data));
tmp.member_count = getInviteMembersDb(txn, room).size(txn);
room_info.emplace(QString::fromStdString(room),
@@ -1603,11 +1551,11 @@ Cache::roomIds()
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
std::vector<QString> rooms;
- std::string room_id, unused;
+ std::string_view room_id, unused;
auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
while (roomsCursor.get(room_id, unused, MDB_NEXT))
- rooms.push_back(QString::fromStdString(room_id));
+ rooms.push_back(QString::fromStdString(std::string(room_id)));
roomsCursor.close();
txn.commit();
@@ -1643,12 +1591,12 @@ Cache::previousBatchToken(const std::string &room_id)
auto orderDb = getEventOrderDb(txn, room_id);
auto cursor = lmdb::cursor::open(txn, orderDb);
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
if (!cursor.get(indexVal, val, MDB_FIRST)) {
return "";
}
- auto j = json::parse(std::string_view(val.data(), val.size()));
+ auto j = json::parse(val);
return j.value("prev_batch", "");
}
@@ -1662,19 +1610,19 @@ Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id, uint64_t
Messages messages{};
- lmdb::val indexVal, event_id;
+ std::string_view indexVal, event_id;
auto cursor = lmdb::cursor::open(txn, orderDb);
if (index == std::numeric_limits<uint64_t>::max()) {
if (cursor.get(indexVal, event_id, forward ? MDB_FIRST : MDB_LAST)) {
- index = *indexVal.data<uint64_t>();
+ index = lmdb::from_sv<uint64_t>(indexVal);
} else {
messages.end_of_cache = true;
return messages;
}
} else {
if (cursor.get(indexVal, event_id, MDB_SET)) {
- index = *indexVal.data<uint64_t>();
+ index = lmdb::from_sv<uint64_t>(indexVal);
} else {
messages.end_of_cache = true;
return messages;
@@ -1689,15 +1637,14 @@ Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id, uint64_t
counter == 0 ? (forward ? MDB_FIRST : MDB_LAST)
: (forward ? MDB_NEXT : MDB_PREV))) &&
counter++ < BATCH_SIZE) {
- lmdb::val event;
- bool success = lmdb::dbi_get(txn, eventsDb, event_id, event);
+ std::string_view event;
+ bool success = eventsDb.get(txn, event_id, event);
if (!success)
continue;
mtx::events::collections::TimelineEvent te;
try {
- mtx::events::collections::from_json(
- json::parse(std::string_view(event.data(), event.size())), te);
+ mtx::events::collections::from_json(json::parse(event), te);
} catch (std::exception &e) {
nhlog::db()->error("Failed to parse message from cache {}", e.what());
continue;
@@ -1708,7 +1655,7 @@ Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id, uint64_t
cursor.close();
// std::reverse(timeline.events.begin(), timeline.events.end());
- messages.next_index = *indexVal.data<uint64_t>();
+ messages.next_index = lmdb::from_sv<uint64_t>(indexVal);
messages.end_of_cache = !ret;
return messages;
@@ -1720,15 +1667,14 @@ Cache::getEvent(const std::string &room_id, const std::string &event_id)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto eventsDb = getEventsDb(txn, room_id);
- lmdb::val event{};
- bool success = lmdb::dbi_get(txn, eventsDb, lmdb::val(event_id), event);
+ std::string_view event{};
+ bool success = eventsDb.get(txn, event_id, event);
if (!success)
return {};
mtx::events::collections::TimelineEvent te;
try {
- mtx::events::collections::from_json(
- json::parse(std::string_view(event.data(), event.size())), te);
+ mtx::events::collections::from_json(json::parse(event), te);
} catch (std::exception &e) {
nhlog::db()->error("Failed to parse message from cache {}", e.what());
return std::nullopt;
@@ -1744,7 +1690,7 @@ Cache::storeEvent(const std::string &room_id,
auto txn = lmdb::txn::begin(env_);
auto eventsDb = getEventsDb(txn, room_id);
auto event_json = mtx::accessors::serialize_event(event.data);
- lmdb::dbi_put(txn, eventsDb, lmdb::val(event_id), lmdb::val(event_json.dump()));
+ eventsDb.put(txn, event_id, event_json.dump());
txn.commit();
}
@@ -1756,9 +1702,9 @@ Cache::relatedEvents(const std::string &room_id, const std::string &event_id)
std::vector<std::string> related_ids;
- auto related_cursor = lmdb::cursor::open(txn, relationsDb);
- lmdb::val related_to = event_id, related_event;
- bool first = true;
+ auto related_cursor = lmdb::cursor::open(txn, relationsDb);
+ std::string_view related_to = event_id, related_event;
+ bool first = true;
try {
if (!related_cursor.get(related_to, related_event, MDB_SET))
@@ -1786,17 +1732,17 @@ Cache::roomInfo(bool withInvites)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- std::string room_id;
- std::string room_data;
+ std::string_view room_id;
+ std::string_view room_data;
// Gather info about the joined rooms.
auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
while (roomsCursor.get(room_id, room_data, MDB_NEXT)) {
RoomInfo tmp = json::parse(std::move(room_data));
- tmp.member_count = getMembersDb(txn, room_id).size(txn);
- tmp.msgInfo = getLastMessageInfo(txn, room_id);
+ tmp.member_count = getMembersDb(txn, std::string(room_id)).size(txn);
+ tmp.msgInfo = getLastMessageInfo(txn, std::string(room_id));
- result.insert(QString::fromStdString(std::move(room_id)), std::move(tmp));
+ result.insert(QString::fromStdString(std::string(room_id)), std::move(tmp));
}
roomsCursor.close();
@@ -1805,8 +1751,8 @@ Cache::roomInfo(bool withInvites)
auto invitesCursor = lmdb::cursor::open(txn, invitesDb_);
while (invitesCursor.get(room_id, room_data, MDB_NEXT)) {
RoomInfo tmp = json::parse(room_data);
- tmp.member_count = getInviteMembersDb(txn, room_id).size(txn);
- result.insert(QString::fromStdString(std::move(room_id)), std::move(tmp));
+ tmp.member_count = getInviteMembersDb(txn, std::string(room_id)).size(txn);
+ result.insert(QString::fromStdString(std::string(room_id)), std::move(tmp));
}
invitesCursor.close();
}
@@ -1819,7 +1765,7 @@ Cache::roomInfo(bool withInvites)
std::string
Cache::getLastEventId(lmdb::txn &txn, const std::string &room_id)
{
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getOrderToMessageDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -1829,7 +1775,7 @@ Cache::getLastEventId(lmdb::txn &txn, const std::string &room_id)
return {};
}
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
auto cursor = lmdb::cursor::open(txn, orderDb);
if (!cursor.get(indexVal, val, MDB_LAST)) {
@@ -1843,7 +1789,7 @@ std::optional<Cache::TimelineRange>
Cache::getTimelineRange(const std::string &room_id)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getOrderToMessageDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -1853,7 +1799,7 @@ Cache::getTimelineRange(const std::string &room_id)
return {};
}
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
auto cursor = lmdb::cursor::open(txn, orderDb);
if (!cursor.get(indexVal, val, MDB_LAST)) {
@@ -1861,21 +1807,24 @@ Cache::getTimelineRange(const std::string &room_id)
}
TimelineRange range{};
- range.last = *indexVal.data<uint64_t>();
+ range.last = lmdb::from_sv<uint64_t>(indexVal);
if (!cursor.get(indexVal, val, MDB_FIRST)) {
return {};
}
- range.first = *indexVal.data<uint64_t>();
+ range.first = lmdb::from_sv<uint64_t>(indexVal);
return range;
}
std::optional<uint64_t>
Cache::getTimelineIndex(const std::string &room_id, std::string_view event_id)
{
+ if (event_id.empty() || room_id.empty())
+ return {};
+
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getMessageToOrderDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -1885,14 +1834,14 @@ Cache::getTimelineIndex(const std::string &room_id, std::string_view event_id)
return {};
}
- lmdb::val indexVal{event_id.data(), event_id.size()}, val;
+ std::string_view indexVal{event_id.data(), event_id.size()}, val;
- bool success = lmdb::dbi_get(txn, orderDb, indexVal, val);
+ bool success = orderDb.get(txn, indexVal, val);
if (!success) {
return {};
}
- return *val.data<uint64_t>();
+ return lmdb::from_sv<uint64_t>(val);
}
std::optional<uint64_t>
@@ -1903,7 +1852,7 @@ Cache::getEventIndex(const std::string &room_id, std::string_view event_id)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getEventToOrderDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -1913,14 +1862,14 @@ Cache::getEventIndex(const std::string &room_id, std::string_view event_id)
return {};
}
- lmdb::val indexVal{event_id.data(), event_id.size()}, val;
+ std::string_view val;
- bool success = lmdb::dbi_get(txn, orderDb, indexVal, val);
+ bool success = orderDb.get(txn, event_id, val);
if (!success) {
return {};
}
- return *val.data<uint64_t>();
+ return lmdb::from_sv<uint64_t>(val);
}
std::optional<std::pair<uint64_t, std::string>>
@@ -1931,9 +1880,9 @@ Cache::lastInvisibleEventAfter(const std::string &room_id, std::string_view even
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::dbi orderDb{0};
- lmdb::dbi eventOrderDb{0};
- lmdb::dbi timelineDb{0};
+ lmdb::dbi orderDb;
+ lmdb::dbi eventOrderDb;
+ lmdb::dbi timelineDb;
try {
orderDb = getEventToOrderDb(txn, room_id);
eventOrderDb = getEventOrderDb(txn, room_id);
@@ -1945,26 +1894,24 @@ Cache::lastInvisibleEventAfter(const std::string &room_id, std::string_view even
return {};
}
- lmdb::val eventIdVal{event_id.data(), event_id.size()}, indexVal;
+ std::string_view indexVal;
- bool success = lmdb::dbi_get(txn, orderDb, eventIdVal, indexVal);
+ bool success = orderDb.get(txn, event_id, indexVal);
if (!success) {
return {};
}
- uint64_t prevIdx = *indexVal.data<uint64_t>();
- std::string prevId{eventIdVal.data(), eventIdVal.size()};
+ uint64_t prevIdx = lmdb::from_sv<uint64_t>(indexVal);
+ std::string prevId{event_id};
auto cursor = lmdb::cursor::open(txn, eventOrderDb);
cursor.get(indexVal, MDB_SET);
- while (cursor.get(indexVal, eventIdVal, MDB_NEXT)) {
- std::string evId =
- json::parse(std::string_view(eventIdVal.data(), eventIdVal.size()))["event_id"]
- .get<std::string>();
- lmdb::val temp;
- if (lmdb::dbi_get(txn, timelineDb, lmdb::val(evId.data(), evId.size()), temp)) {
+ while (cursor.get(indexVal, event_id, MDB_NEXT)) {
+ std::string evId = json::parse(event_id)["event_id"].get<std::string>();
+ std::string_view temp;
+ if (timelineDb.get(txn, evId, temp)) {
return std::pair{prevIdx, std::string(prevId)};
} else {
- prevIdx = *indexVal.data<uint64_t>();
+ prevIdx = lmdb::from_sv<uint64_t>(indexVal);
prevId = std::move(evId);
}
}
@@ -1977,7 +1924,7 @@ Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getEventToOrderDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -1987,21 +1934,21 @@ Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id)
return {};
}
- lmdb::val indexVal{event_id.data(), event_id.size()}, val;
+ std::string_view val;
- bool success = lmdb::dbi_get(txn, orderDb, indexVal, val);
+ bool success = orderDb.get(txn, event_id, val);
if (!success) {
return {};
}
- return *val.data<uint64_t>();
+ return lmdb::from_sv<uint64_t>(val);
}
std::optional<std::string>
Cache::getTimelineEventId(const std::string &room_id, uint64_t index)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getOrderToMessageDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -2011,20 +1958,20 @@ Cache::getTimelineEventId(const std::string &room_id, uint64_t index)
return {};
}
- lmdb::val indexVal{&index, sizeof(index)}, val;
+ std::string_view val;
- bool success = lmdb::dbi_get(txn, orderDb, indexVal, val);
+ bool success = orderDb.get(txn, lmdb::to_sv(index), val);
if (!success) {
return {};
}
- return std::string(val.data(), val.size());
+ return std::string(val);
}
DescInfo
Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
{
- lmdb::dbi orderDb{0};
+ lmdb::dbi orderDb;
try {
orderDb = getOrderToMessageDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -2033,7 +1980,8 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
e.what());
return {};
}
- lmdb::dbi eventsDb{0};
+
+ lmdb::dbi eventsDb;
try {
eventsDb = getEventsDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -2042,8 +1990,8 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
e.what());
return {};
}
- auto membersdb{0};
+ lmdb::dbi membersdb;
try {
membersdb = getMembersDb(txn, room_id);
} catch (lmdb::runtime_error &e) {
@@ -2060,19 +2008,19 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
DescInfo fallbackDesc{};
- lmdb::val indexVal, event_id;
+ std::string_view indexVal, event_id;
auto cursor = lmdb::cursor::open(txn, orderDb);
bool first = true;
while (cursor.get(indexVal, event_id, first ? MDB_LAST : MDB_PREV)) {
first = false;
- lmdb::val event;
- bool success = lmdb::dbi_get(txn, eventsDb, event_id, event);
+ std::string_view event;
+ bool success = eventsDb.get(txn, event_id, event);
if (!success)
continue;
- auto obj = json::parse(std::string_view(event.data(), event.size()));
+ auto obj = json::parse(event);
if (fallbackDesc.event_id.isEmpty() && obj["type"] == "m.room.member" &&
obj["state_key"] == local_user.toStdString() &&
@@ -2095,10 +2043,9 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
mtx::events::collections::TimelineEvent te;
mtx::events::collections::from_json(obj, te);
- lmdb::val info;
+ std::string_view info;
MemberInfo m;
- if (lmdb::dbi_get(
- txn, membersdb, lmdb::val(obj["sender"].get<std::string>()), info)) {
+ if (membersdb.get(txn, obj["sender"].get<std::string>(), info)) {
m = json::parse(std::string_view(info.data(), info.size()));
}
@@ -2119,10 +2066,10 @@ Cache::invites()
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto cursor = lmdb::cursor::open(txn, invitesDb_);
- std::string room_id, unused;
+ std::string_view room_id, unused;
while (cursor.get(room_id, unused, MDB_NEXT))
- result.emplace(QString::fromStdString(std::move(room_id)), true);
+ result.emplace(QString::fromStdString(std::string(room_id)), true);
cursor.close();
txn.commit();
@@ -2136,9 +2083,8 @@ Cache::getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersd
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomAvatar)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomAvatar), event);
if (res) {
try {
@@ -2157,8 +2103,8 @@ Cache::getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersd
return QString();
auto cursor = lmdb::cursor::open(txn, membersdb);
- std::string user_id;
- std::string member_data;
+ std::string_view user_id;
+ std::string_view member_data;
std::string fallback_url;
// Resolve avatar for 1-1 chats.
@@ -2189,9 +2135,8 @@ Cache::getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb)
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomName)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomName), event);
if (res) {
try {
@@ -2205,8 +2150,7 @@ Cache::getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb)
}
}
- res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomCanonicalAlias)), event);
+ res = statesdb.get(txn, to_string(mtx::events::EventType::RoomCanonicalAlias), event);
if (res) {
try {
@@ -2225,8 +2169,8 @@ Cache::getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb)
const auto total = membersdb.size(txn);
std::size_t ii = 0;
- std::string user_id;
- std::string member_data;
+ std::string_view user_id;
+ std::string_view member_data;
std::map<std::string, MemberInfo> members;
while (cursor.get(user_id, member_data, MDB_NEXT) && ii < 3) {
@@ -2267,14 +2211,12 @@ Cache::getRoomJoinRule(lmdb::txn &txn, lmdb::dbi &statesdb)
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomJoinRules)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomJoinRules), event);
if (res) {
try {
- StateEvent<state::JoinRules> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StateEvent<state::JoinRules> msg = json::parse(event);
return msg.content.join_rule;
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse m.room.join_rule event: {}", e.what());
@@ -2289,14 +2231,12 @@ Cache::getRoomGuestAccess(lmdb::txn &txn, lmdb::dbi &statesdb)
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomGuestAccess)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomGuestAccess), event);
if (res) {
try {
- StateEvent<GuestAccess> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StateEvent<GuestAccess> msg = json::parse(event);
return msg.content.guest_access == AccessState::CanJoin;
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse m.room.guest_access event: {}",
@@ -2312,14 +2252,12 @@ Cache::getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb)
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomTopic)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomTopic), event);
if (res) {
try {
- StateEvent<Topic> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StateEvent<Topic> msg = json::parse(event);
if (!msg.content.topic.empty())
return QString::fromStdString(msg.content.topic);
@@ -2337,14 +2275,12 @@ Cache::getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb)
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomCreate)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomCreate), event);
if (res) {
try {
- StateEvent<Create> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StateEvent<Create> msg = json::parse(event);
if (!msg.content.room_version.empty())
return QString::fromStdString(msg.content.room_version);
@@ -2366,14 +2302,12 @@ Cache::getRoomAliases(const std::string &roomid)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto statesdb = getStatesDb(txn, roomid);
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomCanonicalAlias)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomCanonicalAlias), event);
if (res) {
try {
- StateEvent<CanonicalAlias> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StateEvent<CanonicalAlias> msg = json::parse(event);
return msg.content;
} catch (const json::exception &e) {
@@ -2391,14 +2325,12 @@ Cache::getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &members
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomName)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomName), event);
if (res) {
try {
- StrippedEvent<state::Name> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StrippedEvent<state::Name> msg = json::parse(event);
return QString::fromStdString(msg.content.name);
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse m.room.name event: {}", e.what());
@@ -2406,7 +2338,7 @@ Cache::getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &members
}
auto cursor = lmdb::cursor::open(txn, membersdb);
- std::string user_id, member_data;
+ std::string_view user_id, member_data;
while (cursor.get(user_id, member_data, MDB_NEXT)) {
if (user_id == localUserId_.toStdString())
@@ -2433,14 +2365,12 @@ Cache::getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &me
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res = lmdb::dbi_get(
- txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomAvatar)), event);
+ std::string_view event;
+ bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomAvatar), event);
if (res) {
try {
- StrippedEvent<state::Avatar> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StrippedEvent<state::Avatar> msg = json::parse(event);
return QString::fromStdString(msg.content.url);
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse m.room.avatar event: {}", e.what());
@@ -2448,7 +2378,7 @@ Cache::getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &me
}
auto cursor = lmdb::cursor::open(txn, membersdb);
- std::string user_id, member_data;
+ std::string_view user_id, member_data;
while (cursor.get(user_id, member_data, MDB_NEXT)) {
if (user_id == localUserId_.toStdString())
@@ -2475,14 +2405,12 @@ Cache::getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &db)
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val event;
- bool res =
- lmdb::dbi_get(txn, db, lmdb::val(to_string(mtx::events::EventType::RoomTopic)), event);
+ std::string_view event;
+ bool res = db.get(txn, to_string(mtx::events::EventType::RoomTopic), event);
if (res) {
try {
- StrippedEvent<Topic> msg =
- json::parse(std::string_view(event.data(), event.size()));
+ StrippedEvent<Topic> msg = json::parse(event);
return QString::fromStdString(msg.content.topic);
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse m.room.topic event: {}", e.what());
@@ -2503,9 +2431,9 @@ Cache::getRoomAvatar(const std::string &room_id)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val response;
+ std::string_view response;
- if (!lmdb::dbi_get(txn, roomsDb_, lmdb::val(room_id), response)) {
+ if (!roomsDb_.get(txn, room_id, response)) {
txn.commit();
return QImage();
}
@@ -2513,7 +2441,7 @@ Cache::getRoomAvatar(const std::string &room_id)
std::string media_url;
try {
- RoomInfo info = json::parse(std::string_view(response.data(), response.size()));
+ RoomInfo info = json::parse(response);
media_url = std::move(info.avatar_url);
if (media_url.empty()) {
@@ -2526,7 +2454,7 @@ Cache::getRoomAvatar(const std::string &room_id)
std::string(response.data(), response.size()));
}
- if (!lmdb::dbi_get(txn, mediaDb_, lmdb::val(media_url), response)) {
+ if (!mediaDb_.get(txn, media_url, response)) {
txn.commit();
return QImage();
}
@@ -2542,7 +2470,7 @@ Cache::joinedRooms()
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
- std::string id, data;
+ std::string_view id, data;
std::vector<std::string> room_ids;
// Gather the room ids for the joined rooms.
@@ -2563,9 +2491,9 @@ Cache::getMember(const std::string &room_id, const std::string &user_id)
auto membersdb = getMembersDb(txn, room_id);
- lmdb::val info;
- if (lmdb::dbi_get(txn, membersdb, lmdb::val(user_id), info)) {
- MemberInfo m = json::parse(std::string_view(info.data(), info.size()));
+ std::string_view info;
+ if (membersdb.get(txn, user_id, info)) {
+ MemberInfo m = json::parse(info);
return m;
}
} catch (std::exception &e) {
@@ -2582,9 +2510,9 @@ Cache::searchRooms(const std::string &query, std::uint8_t max_items)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto cursor = lmdb::cursor::open(txn, roomsDb_);
- std::string room_id, room_data;
+ std::string_view room_id, room_data;
while (cursor.get(room_id, room_data, MDB_NEXT)) {
- RoomInfo tmp = json::parse(std::move(room_data));
+ RoomInfo tmp = json::parse(room_data);
const int score = utils::levenshtein_distance(
query, QString::fromStdString(tmp.name).toLower().toStdString());
@@ -2623,7 +2551,7 @@ Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_
std::vector<RoomMember> members;
- std::string user_id, user_data;
+ std::string_view user_id, user_data;
while (cursor.get(user_id, user_data, MDB_NEXT)) {
if (currentIndex < startIndex) {
currentIndex += 1;
@@ -2636,7 +2564,7 @@ Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_
try {
MemberInfo tmp = json::parse(user_data);
members.emplace_back(
- RoomMember{QString::fromStdString(user_id),
+ RoomMember{QString::fromStdString(std::string(user_id)),
QString::fromStdString(tmp.name),
QImage::fromData(image(txn, tmp.avatar_url))});
} catch (const json::exception &e) {
@@ -2658,8 +2586,8 @@ Cache::isRoomMember(const std::string &user_id, const std::string &room_id)
auto txn = lmdb::txn::begin(env_);
auto db = getMembersDb(txn, room_id);
- lmdb::val value;
- bool res = lmdb::dbi_get(txn, db, lmdb::val(user_id), value);
+ std::string_view value;
+ bool res = db.get(txn, user_id, value);
txn.commit();
return res;
@@ -2678,10 +2606,7 @@ Cache::savePendingMessage(const std::string &room_id,
auto pending = getPendingMessagesDb(txn, room_id);
int64_t now = QDateTime::currentMSecsSinceEpoch();
- lmdb::dbi_put(txn,
- pending,
- lmdb::val(&now, sizeof(now)),
- lmdb::val(mtx::accessors::event_id(message.data)));
+ pending.put(txn, lmdb::to_sv(now), mtx::accessors::event_id(message.data));
txn.commit();
}
@@ -2694,19 +2619,18 @@ Cache::firstPendingMessage(const std::string &room_id)
{
auto pendingCursor = lmdb::cursor::open(txn, pending);
- lmdb::val tsIgnored, pendingTxn;
+ std::string_view tsIgnored, pendingTxn;
while (pendingCursor.get(tsIgnored, pendingTxn, MDB_NEXT)) {
auto eventsDb = getEventsDb(txn, room_id);
- lmdb::val event;
- if (!lmdb::dbi_get(txn, eventsDb, pendingTxn, event)) {
- lmdb::dbi_del(txn, pending, tsIgnored, pendingTxn);
+ std::string_view event;
+ if (!eventsDb.get(txn, pendingTxn, event)) {
+ pending.del(txn, tsIgnored, pendingTxn);
continue;
}
try {
mtx::events::collections::TimelineEvent te;
- mtx::events::collections::from_json(
- json::parse(std::string_view(event.data(), event.size())), te);
+ mtx::events::collections::from_json(json::parse(event), te);
pendingCursor.close();
txn.commit();
@@ -2714,7 +2638,7 @@ Cache::firstPendingMessage(const std::string &room_id)
} catch (std::exception &e) {
nhlog::db()->error("Failed to parse message from cache {}",
e.what());
- lmdb::dbi_del(txn, pending, tsIgnored, pendingTxn);
+ pending.del(txn, tsIgnored, pendingTxn);
continue;
}
}
@@ -2733,7 +2657,7 @@ Cache::removePendingStatus(const std::string &room_id, const std::string &txn_id
{
auto pendingCursor = lmdb::cursor::open(txn, pending);
- lmdb::val tsIgnored, pendingTxn;
+ std::string_view tsIgnored, pendingTxn;
while (pendingCursor.get(tsIgnored, pendingTxn, MDB_NEXT)) {
if (std::string_view(pendingTxn.data(), pendingTxn.size()) == txn_id)
lmdb::cursor_del(pendingCursor);
@@ -2771,17 +2695,17 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
using namespace mtx::events;
using namespace mtx::events::state;
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
uint64_t index = std::numeric_limits<uint64_t>::max() / 2;
auto cursor = lmdb::cursor::open(txn, orderDb);
if (cursor.get(indexVal, val, MDB_LAST)) {
- index = *indexVal.data<int64_t>();
+ index = lmdb::from_sv<uint64_t>(indexVal);
}
uint64_t msgIndex = std::numeric_limits<uint64_t>::max() / 2;
auto msgCursor = lmdb::cursor::open(txn, order2msgDb);
if (msgCursor.get(indexVal, val, MDB_LAST)) {
- msgIndex = *indexVal.data<uint64_t>();
+ msgIndex = lmdb::from_sv<uint64_t>(indexVal);
}
bool first = true;
@@ -2795,48 +2719,41 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
continue;
}
- lmdb::val event_id = event_id_val;
+ std::string_view event_id = event_id_val;
json orderEntry = json::object();
orderEntry["event_id"] = event_id_val;
if (first && !res.prev_batch.empty())
orderEntry["prev_batch"] = res.prev_batch;
- lmdb::val txn_order;
- if (!txn_id.empty() &&
- lmdb::dbi_get(txn, evToOrderDb, lmdb::val(txn_id), txn_order)) {
- lmdb::dbi_put(txn, eventsDb, event_id, lmdb::val(event.dump()));
- lmdb::dbi_del(txn, eventsDb, lmdb::val(txn_id));
-
- lmdb::val msg_txn_order;
- if (lmdb::dbi_get(txn, msg2orderDb, lmdb::val(txn_id), msg_txn_order)) {
- lmdb::dbi_put(txn, order2msgDb, msg_txn_order, event_id);
- lmdb::dbi_put(txn, msg2orderDb, event_id, msg_txn_order);
- lmdb::dbi_del(txn, msg2orderDb, lmdb::val(txn_id));
+ std::string_view txn_order;
+ if (!txn_id.empty() && evToOrderDb.get(txn, txn_id, txn_order)) {
+ eventsDb.put(txn, event_id, event.dump());
+ eventsDb.del(txn, txn_id);
+
+ std::string_view msg_txn_order;
+ if (msg2orderDb.get(txn, txn_id, msg_txn_order)) {
+ order2msgDb.put(txn, msg_txn_order, event_id);
+ msg2orderDb.put(txn, event_id, msg_txn_order);
+ msg2orderDb.del(txn, txn_id);
}
- lmdb::dbi_put(txn, orderDb, txn_order, lmdb::val(orderEntry.dump()));
- lmdb::dbi_put(txn, evToOrderDb, event_id, txn_order);
- lmdb::dbi_del(txn, evToOrderDb, lmdb::val(txn_id));
+ orderDb.put(txn, txn_order, orderEntry.dump());
+ evToOrderDb.put(txn, event_id, txn_order);
+ evToOrderDb.del(txn, txn_id);
auto relations = mtx::accessors::relations(e);
if (!relations.relations.empty()) {
for (const auto &r : relations.relations) {
if (!r.event_id.empty()) {
- lmdb::dbi_del(txn,
- relationsDb,
- lmdb::val(r.event_id),
- lmdb::val(txn_id));
- lmdb::dbi_put(txn,
- relationsDb,
- lmdb::val(r.event_id),
- event_id);
+ relationsDb.del(txn, r.event_id, txn_id);
+ relationsDb.put(txn, r.event_id, event_id);
}
}
}
auto pendingCursor = lmdb::cursor::open(txn, pending);
- lmdb::val tsIgnored, pendingTxn;
+ std::string_view tsIgnored, pendingTxn;
while (pendingCursor.get(tsIgnored, pendingTxn, MDB_NEXT)) {
if (std::string_view(pendingTxn.data(), pendingTxn.size()) ==
txn_id)
@@ -2848,9 +2765,8 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
if (redaction->redacts.empty())
continue;
- lmdb::val oldEvent;
- bool success =
- lmdb::dbi_get(txn, eventsDb, lmdb::val(redaction->redacts), oldEvent);
+ std::string_view oldEvent;
+ bool success = eventsDb.get(txn, redaction->redacts, oldEvent);
if (!success)
continue;
@@ -2875,14 +2791,10 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
continue;
}
- lmdb::dbi_put(
- txn, eventsDb, lmdb::val(redaction->redacts), lmdb::val(event.dump()));
- lmdb::dbi_put(txn,
- eventsDb,
- lmdb::val(redaction->event_id),
- lmdb::val(json(*redaction).dump()));
+ eventsDb.put(txn, redaction->redacts, event.dump());
+ eventsDb.put(txn, redaction->event_id, json(*redaction).dump());
} else {
- lmdb::dbi_put(txn, eventsDb, event_id, lmdb::val(event.dump()));
+ eventsDb.put(txn, event_id, event.dump());
++index;
@@ -2890,34 +2802,22 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
nhlog::db()->debug("saving '{}'", orderEntry.dump());
- lmdb::cursor_put(cursor.handle(),
- lmdb::val(&index, sizeof(index)),
- lmdb::val(orderEntry.dump()),
- MDB_APPEND);
- lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index)));
+ cursor.put(lmdb::to_sv(index), orderEntry.dump(), MDB_APPEND);
+ evToOrderDb.put(txn, event_id, lmdb::to_sv(index));
// TODO(Nico): Allow blacklisting more event types in UI
if (!isHiddenEvent(txn, e, room_id)) {
++msgIndex;
- lmdb::cursor_put(msgCursor.handle(),
- lmdb::val(&msgIndex, sizeof(msgIndex)),
- event_id,
- MDB_APPEND);
-
- lmdb::dbi_put(txn,
- msg2orderDb,
- event_id,
- lmdb::val(&msgIndex, sizeof(msgIndex)));
+ msgCursor.put(lmdb::to_sv(msgIndex), event_id, MDB_APPEND);
+
+ msg2orderDb.put(txn, event_id, lmdb::to_sv(msgIndex));
}
auto relations = mtx::accessors::relations(e);
if (!relations.relations.empty()) {
for (const auto &r : relations.relations) {
if (!r.event_id.empty()) {
- lmdb::dbi_put(txn,
- relationsDb,
- lmdb::val(r.event_id),
- event_id);
+ relationsDb.put(txn, r.event_id, event_id);
}
}
}
@@ -2937,12 +2837,12 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
auto msg2orderDb = getMessageToOrderDb(txn, room_id);
auto order2msgDb = getOrderToMessageDb(txn, room_id);
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
uint64_t index = std::numeric_limits<uint64_t>::max() / 2;
{
auto cursor = lmdb::cursor::open(txn, orderDb);
if (cursor.get(indexVal, val, MDB_FIRST)) {
- index = *indexVal.data<uint64_t>();
+ index = lmdb::from_sv<uint64_t>(indexVal);
}
}
@@ -2950,19 +2850,15 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
{
auto msgCursor = lmdb::cursor::open(txn, order2msgDb);
if (msgCursor.get(indexVal, val, MDB_FIRST)) {
- msgIndex = *indexVal.data<uint64_t>();
+ msgIndex = lmdb::from_sv<uint64_t>(indexVal);
}
}
if (res.chunk.empty()) {
- if (lmdb::dbi_get(txn, orderDb, lmdb::val(&index, sizeof(index)), val)) {
- auto orderEntry = json::parse(std::string_view(val.data(), val.size()));
+ if (orderDb.get(txn, lmdb::to_sv(index), val)) {
+ auto orderEntry = json::parse(val);
orderEntry["prev_batch"] = res.end;
- lmdb::dbi_put(txn,
- orderDb,
- lmdb::val(&index, sizeof(index)),
- lmdb::val(orderEntry.dump()));
- nhlog::db()->debug("saving '{}'", orderEntry.dump());
+ orderDb.put(txn, lmdb::to_sv(index), orderEntry.dump());
txn.commit();
}
return index;
@@ -2974,38 +2870,32 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
mtx::events::RedactionEvent<mtx::events::msg::Redaction>>(e))
continue;
- auto event = mtx::accessors::serialize_event(e);
- event_id_val = event["event_id"].get<std::string>();
- lmdb::val event_id = event_id_val;
- lmdb::dbi_put(txn, eventsDb, event_id, lmdb::val(event.dump()));
+ auto event = mtx::accessors::serialize_event(e);
+ event_id_val = event["event_id"].get<std::string>();
+ std::string_view event_id = event_id_val;
+ eventsDb.put(txn, event_id, event.dump());
--index;
json orderEntry = json::object();
orderEntry["event_id"] = event_id_val;
- nhlog::db()->debug("saving '{}'", orderEntry.dump());
-
- lmdb::dbi_put(
- txn, orderDb, lmdb::val(&index, sizeof(index)), lmdb::val(orderEntry.dump()));
- lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index)));
+ orderDb.put(txn, lmdb::to_sv(index), orderEntry.dump());
+ evToOrderDb.put(txn, event_id, lmdb::to_sv(index));
// TODO(Nico): Allow blacklisting more event types in UI
if (!isHiddenEvent(txn, e, room_id)) {
--msgIndex;
- lmdb::dbi_put(
- txn, order2msgDb, lmdb::val(&msgIndex, sizeof(msgIndex)), event_id);
+ order2msgDb.put(txn, lmdb::to_sv(msgIndex), event_id);
- lmdb::dbi_put(
- txn, msg2orderDb, event_id, lmdb::val(&msgIndex, sizeof(msgIndex)));
+ msg2orderDb.put(txn, event_id, lmdb::to_sv(msgIndex));
}
auto relations = mtx::accessors::relations(e);
if (!relations.relations.empty()) {
for (const auto &r : relations.relations) {
if (!r.event_id.empty()) {
- lmdb::dbi_put(
- txn, relationsDb, lmdb::val(r.event_id), event_id);
+ relationsDb.put(txn, r.event_id, event_id);
}
}
}
@@ -3014,8 +2904,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
json orderEntry = json::object();
orderEntry["event_id"] = event_id_val;
orderEntry["prev_batch"] = res.end;
- lmdb::dbi_put(txn, orderDb, lmdb::val(&index, sizeof(index)), lmdb::val(orderEntry.dump()));
- nhlog::db()->debug("saving '{}'", orderEntry.dump());
+ orderDb.put(txn, lmdb::to_sv(index), orderEntry.dump());
txn.commit();
@@ -3034,7 +2923,7 @@ Cache::clearTimeline(const std::string &room_id)
auto msg2orderDb = getMessageToOrderDb(txn, room_id);
auto order2msgDb = getOrderToMessageDb(txn, room_id);
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
auto cursor = lmdb::cursor::open(txn, orderDb);
bool start = true;
@@ -3053,17 +2942,16 @@ Cache::clearTimeline(const std::string &room_id)
if (passed_pagination_token) {
if (obj.count("event_id") != 0) {
- lmdb::val event_id = obj["event_id"].get<std::string>();
- lmdb::dbi_del(txn, evToOrderDb, event_id);
- lmdb::dbi_del(txn, eventsDb, event_id);
-
- lmdb::dbi_del(txn, relationsDb, event_id);
+ std::string event_id = obj["event_id"].get<std::string>();
+ evToOrderDb.del(txn, event_id);
+ eventsDb.del(txn, event_id);
+ relationsDb.del(txn, event_id);
- lmdb::val order{};
- bool exists = lmdb::dbi_get(txn, msg2orderDb, event_id, order);
+ std::string_view order{};
+ bool exists = msg2orderDb.get(txn, event_id, order);
if (exists) {
- lmdb::dbi_del(txn, order2msgDb, order);
- lmdb::dbi_del(txn, msg2orderDb, event_id);
+ order2msgDb.del(txn, order);
+ msg2orderDb.del(txn, event_id);
}
}
lmdb::cursor_del(cursor);
@@ -3078,7 +2966,7 @@ Cache::clearTimeline(const std::string &room_id)
while (msgCursor.get(indexVal, val, start ? MDB_LAST : MDB_PREV)) {
start = false;
- lmdb::val eventId;
+ std::string_view eventId;
bool innerStart = true;
bool found = false;
while (cursor.get(indexVal, eventId, innerStart ? MDB_LAST : MDB_PREV)) {
@@ -3120,7 +3008,7 @@ Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
}
mtx::responses::Notifications notif;
- std::string event_id, msg;
+ std::string_view event_id, msg;
auto cursor = lmdb::cursor::open(txn, db);
@@ -3188,7 +3076,7 @@ Cache::saveTimelineMentions(lmdb::txn &txn,
json obj = notif;
- lmdb::dbi_put(txn, db, lmdb::val(event_id), lmdb::val(obj.dump()));
+ db.put(txn, event_id, obj.dump());
}
}
@@ -3196,7 +3084,7 @@ void
Cache::markSentNotification(const std::string &event_id)
{
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_put(txn, notificationsDb_, lmdb::val(event_id), lmdb::val(std::string("")));
+ notificationsDb_.put(txn, event_id, "");
txn.commit();
}
@@ -3205,7 +3093,7 @@ Cache::removeReadNotification(const std::string &event_id)
{
auto txn = lmdb::txn::begin(env_);
- lmdb::dbi_del(txn, notificationsDb_, lmdb::val(event_id), nullptr);
+ notificationsDb_.del(txn, event_id);
txn.commit();
}
@@ -3215,8 +3103,8 @@ Cache::isNotificationSent(const std::string &event_id)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
- lmdb::val value;
- bool res = lmdb::dbi_get(txn, notificationsDb_, lmdb::val(event_id), value);
+ std::string_view value;
+ bool res = notificationsDb_.get(txn, event_id, value);
txn.commit();
return res;
@@ -3230,7 +3118,7 @@ Cache::getRoomIds(lmdb::txn &txn)
std::vector<std::string> rooms;
- std::string room_id, _unused;
+ std::string_view room_id, _unused;
while (cursor.get(room_id, _unused, MDB_NEXT))
rooms.emplace_back(room_id);
@@ -3242,7 +3130,7 @@ Cache::getRoomIds(lmdb::txn &txn)
void
Cache::deleteOldMessages()
{
- lmdb::val indexVal, val;
+ std::string_view indexVal, val;
auto txn = lmdb::txn::begin(env_);
auto room_ids = getRoomIds(txn);
@@ -3258,12 +3146,12 @@ Cache::deleteOldMessages()
uint64_t first, last;
if (cursor.get(indexVal, val, MDB_LAST)) {
- last = *indexVal.data<uint64_t>();
+ last = lmdb::from_sv<uint64_t>(indexVal);
} else {
continue;
}
if (cursor.get(indexVal, val, MDB_FIRST)) {
- first = *indexVal.data<uint64_t>();
+ first = lmdb::from_sv<uint64_t>(indexVal);
} else {
continue;
}
@@ -3279,20 +3167,20 @@ Cache::deleteOldMessages()
auto obj = json::parse(std::string_view(val.data(), val.size()));
if (obj.count("event_id") != 0) {
- lmdb::val event_id = obj["event_id"].get<std::string>();
- lmdb::dbi_del(txn, evToOrderDb, event_id);
- lmdb::dbi_del(txn, eventsDb, event_id);
+ std::string event_id = obj["event_id"].get<std::string>();
+ evToOrderDb.del(txn, event_id);
+ eventsDb.del(txn, event_id);
- lmdb::dbi_del(txn, relationsDb, event_id);
+ relationsDb.del(txn, event_id);
- lmdb::val order{};
- bool exists = lmdb::dbi_get(txn, m2o, event_id, order);
+ std::string_view order{};
+ bool exists = m2o.get(txn, event_id, order);
if (exists) {
- lmdb::dbi_del(txn, o2m, order);
- lmdb::dbi_del(txn, m2o, event_id);
+ o2m.del(txn, order);
+ m2o.del(txn, event_id);
}
}
- lmdb::cursor_del(cursor);
+ cursor.del();
}
cursor.close();
}
@@ -3315,11 +3203,11 @@ Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::st
try {
auto db = getAccountDataDb(txn, room_id);
- lmdb::val data;
- if (lmdb::dbi_get(txn, db, lmdb::val(to_string(type)), data)) {
+ std::string_view data;
+ if (db.get(txn, to_string(type), data)) {
mtx::responses::utils::RoomAccountDataEvents events;
json j = json::array({
- json::parse(std::string_view(data.data(), data.size())),
+ json::parse(data),
});
mtx::responses::utils::parse_room_account_data_events(j, events);
if (events.size() == 1)
@@ -3341,11 +3229,11 @@ Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes
auto txn = lmdb::txn::begin(env_);
auto db = getStatesDb(txn, room_id);
- uint16_t min_event_level = std::numeric_limits<uint16_t>::max();
- uint16_t user_level = std::numeric_limits<uint16_t>::min();
+ int64_t min_event_level = std::numeric_limits<int64_t>::max();
+ int64_t user_level = std::numeric_limits<int64_t>::min();
- lmdb::val event;
- bool res = lmdb::dbi_get(txn, db, lmdb::val(to_string(EventType::RoomPowerLevels)), event);
+ std::string_view event;
+ bool res = db.get(txn, to_string(EventType::RoomPowerLevels), event);
if (res) {
try {
@@ -3356,8 +3244,7 @@ Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes
for (const auto &ty : eventTypes)
min_event_level =
- std::min(min_event_level,
- (uint16_t)msg.content.state_level(to_string(ty)));
+ std::min(min_event_level, msg.content.state_level(to_string(ty)));
} catch (const json::exception &e) {
nhlog::db()->warn("failed to parse m.room.power_levels event: {}",
e.what());
@@ -3375,13 +3262,13 @@ Cache::roomMembers(const std::string &room_id)
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
std::vector<std::string> members;
- std::string user_id, unused;
+ std::string_view user_id, unused;
auto db = getMembersDb(txn, room_id);
auto cursor = lmdb::cursor::open(txn, db);
while (cursor.get(user_id, unused, MDB_NEXT))
- members.emplace_back(std::move(user_id));
+ members.emplace_back(user_id);
cursor.close();
txn.commit();
@@ -3392,7 +3279,7 @@ Cache::roomMembers(const std::string &room_id)
std::map<std::string, std::optional<UserKeyCache>>
Cache::getMembersWithKeys(const std::string &room_id)
{
- lmdb::val keys;
+ std::string_view keys;
try {
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
@@ -3401,17 +3288,16 @@ Cache::getMembersWithKeys(const std::string &room_id)
auto db = getMembersDb(txn, room_id);
auto keysDb = getUserKeysDb(txn);
- std::string user_id, unused;
+ std::string_view user_id, unused;
auto cursor = lmdb::cursor::open(txn, db);
while (cursor.get(user_id, unused, MDB_NEXT)) {
- auto res = lmdb::dbi_get(txn, keysDb, lmdb::val(user_id), keys);
+ auto res = keysDb.get(txn, user_id, keys);
if (res) {
- members[user_id] =
- json::parse(std::string_view(keys.data(), keys.size()))
- .get<UserKeyCache>();
+ members[std::string(user_id)] =
+ json::parse(keys).get<UserKeyCache>();
} else {
- members[user_id] = {};
+ members[std::string(user_id)] = {};
}
}
cursor.close();
@@ -3457,11 +3343,11 @@ Cache::presenceState(const std::string &user_id)
if (user_id.empty())
return {};
- lmdb::val presenceVal;
+ std::string_view presenceVal;
auto txn = lmdb::txn::begin(env_);
auto db = getPresenceDb(txn);
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), presenceVal);
+ auto res = db.get(txn, user_id, presenceVal);
mtx::presence::PresenceState state = mtx::presence::offline;
@@ -3482,18 +3368,17 @@ Cache::statusMessage(const std::string &user_id)
if (user_id.empty())
return {};
- lmdb::val presenceVal;
+ std::string_view presenceVal;
auto txn = lmdb::txn::begin(env_);
auto db = getPresenceDb(txn);
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), presenceVal);
+ auto res = db.get(txn, user_id, presenceVal);
std::string status_msg;
if (res) {
- mtx::events::presence::Presence presence =
- json::parse(std::string_view(presenceVal.data(), presenceVal.size()));
- status_msg = presence.status_msg;
+ mtx::events::presence::Presence presence = json::parse(presenceVal);
+ status_msg = presence.status_msg;
}
txn.commit();
@@ -3526,16 +3411,15 @@ from_json(const json &j, UserKeyCache &info)
std::optional<UserKeyCache>
Cache::userKeys(const std::string &user_id)
{
- lmdb::val keys;
+ std::string_view keys;
try {
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto db = getUserKeysDb(txn);
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), keys);
+ auto res = db.get(txn, user_id, keys);
if (res) {
- return json::parse(std::string_view(keys.data(), keys.size()))
- .get<UserKeyCache>();
+ return json::parse(keys).get<UserKeyCache>();
} else {
return {};
}
@@ -3564,20 +3448,17 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query
for (auto &[user, update] : updates) {
nhlog::db()->debug("Updated user keys: {}", user);
- lmdb::val oldKeys;
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user), oldKeys);
+ std::string_view oldKeys;
+ auto res = db.get(txn, user, oldKeys);
if (res) {
- auto last_changed =
- json::parse(std::string_view(oldKeys.data(), oldKeys.size()))
- .get<UserKeyCache>()
- .last_changed;
+ auto last_changed = json::parse(oldKeys).get<UserKeyCache>().last_changed;
// skip if we are tracking this and expect it to be up to date with the last
// sync token
if (!last_changed.empty() && last_changed != sync_token)
continue;
}
- lmdb::dbi_put(txn, db, lmdb::val(user), lmdb::val(json(update).dump()));
+ db.put(txn, user, json(update).dump());
}
txn.commit();
@@ -3613,7 +3494,7 @@ void
Cache::deleteUserKeys(lmdb::txn &txn, lmdb::dbi &db, const std::vector<std::string> &user_ids)
{
for (const auto &user_id : user_ids)
- lmdb::dbi_del(txn, db, lmdb::val(user_id), nullptr);
+ db.del(txn, user_id);
}
void
@@ -3628,8 +3509,8 @@ Cache::markUserKeysOutOfDate(lmdb::txn &txn,
for (const auto &user : user_ids) {
nhlog::db()->debug("Marking user keys out of date: {}", user);
- lmdb::val oldKeys;
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user), oldKeys);
+ std::string_view oldKeys;
+ auto res = db.get(txn, user, oldKeys);
if (!res)
continue;
@@ -3637,7 +3518,7 @@ Cache::markUserKeysOutOfDate(lmdb::txn &txn,
auto cacheEntry =
json::parse(std::string_view(oldKeys.data(), oldKeys.size())).get<UserKeyCache>();
cacheEntry.last_changed = sync_token;
- lmdb::dbi_put(txn, db, lmdb::val(user), lmdb::val(json(cacheEntry).dump()));
+ db.put(txn, user, json(cacheEntry).dump());
query.device_keys[user] = {};
}
@@ -3679,23 +3560,23 @@ Cache::query_keys(const std::string &user_id,
last_changed = cache_->last_changed;
req.token = last_changed;
- http::client()->query_keys(req,
- [cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
- mtx::http::RequestErr err) {
- if (err) {
- nhlog::net()->warn(
- "failed to query device keys: {},{}",
- err->matrix_error.errcode,
- static_cast<int>(err->status_code));
- cb({}, err);
- return;
- }
+ http::client()->query_keys(
+ req,
+ [cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
+ mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn("failed to query device keys: {},{}",
+ mtx::errors::to_string(err->matrix_error.errcode),
+ static_cast<int>(err->status_code));
+ cb({}, err);
+ return;
+ }
- cache::updateUserKeys(last_changed, res);
+ cache::updateUserKeys(last_changed, res);
- auto keys = cache::userKeys(user_id);
- cb(keys.value_or(UserKeyCache{}), err);
- });
+ auto keys = cache::userKeys(user_id);
+ cb(keys.value_or(UserKeyCache{}), err);
+ });
}
void
@@ -3715,17 +3596,16 @@ from_json(const json &j, VerificationCache &info)
std::optional<VerificationCache>
Cache::verificationCache(const std::string &user_id)
{
- lmdb::val verifiedVal;
+ std::string_view verifiedVal;
auto txn = lmdb::txn::begin(env_);
auto db = getVerificationDb(txn);
try {
VerificationCache verified_state;
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), verifiedVal);
+ auto res = db.get(txn, user_id, verifiedVal);
if (res) {
- verified_state =
- json::parse(std::string_view(verifiedVal.data(), verifiedVal.size()));
+ verified_state = json::parse(verifiedVal);
return verified_state;
} else {
return {};
@@ -3738,16 +3618,16 @@ Cache::verificationCache(const std::string &user_id)
void
Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
{
- lmdb::val val;
+ std::string_view val;
auto txn = lmdb::txn::begin(env_);
auto db = getVerificationDb(txn);
try {
VerificationCache verified_state;
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), val);
+ auto res = db.get(txn, user_id, val);
if (res) {
- verified_state = json::parse(std::string_view(val.data(), val.size()));
+ verified_state = json::parse(val);
}
for (const auto &device : verified_state.device_verified)
@@ -3755,7 +3635,7 @@ Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
return;
verified_state.device_verified.push_back(key);
- lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(verified_state).dump()));
+ db.put(txn, user_id, json(verified_state).dump());
txn.commit();
} catch (std::exception &) {
}
@@ -3783,16 +3663,16 @@ Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
void
Cache::markDeviceUnverified(const std::string &user_id, const std::string &key)
{
- lmdb::val val;
+ std::string_view val;
auto txn = lmdb::txn::begin(env_);
auto db = getVerificationDb(txn);
try {
VerificationCache verified_state;
- auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), val);
+ auto res = db.get(txn, user_id, val);
if (res) {
- verified_state = json::parse(std::string_view(val.data(), val.size()));
+ verified_state = json::parse(val);
}
verified_state.device_verified.erase(
@@ -3801,7 +3681,7 @@ Cache::markDeviceUnverified(const std::string &user_id, const std::string &key)
key),
verified_state.device_verified.end());
- lmdb::dbi_put(txn, db, lmdb::val(user_id), lmdb::val(json(verified_state).dump()));
+ db.put(txn, user_id, json(verified_state).dump());
txn.commit();
} catch (std::exception &) {
}
diff --git a/src/Cache.h b/src/Cache.h
index e60fc970..f7e5f749 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h
index eb2cc445..383d7b05 100644
--- a/src/CacheCryptoStructs.h
+++ b/src/CacheCryptoStructs.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <map>
diff --git a/src/CacheStructs.h b/src/CacheStructs.h
index 10f8cc54..ad9aab98 100644
--- a/src/CacheStructs.h
+++ b/src/CacheStructs.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QDateTime>
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 431e7bc3..09fc277d 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -1,20 +1,8 @@
-/*
- * nheko Copyright (C) 2019 The nheko authors
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2019 The nheko authors
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -102,9 +90,9 @@ public:
std::size_t len = 30);
void saveState(const mtx::responses::Sync &res);
- bool isInitialized() const;
+ bool isInitialized();
- std::string nextBatchToken() const;
+ std::string nextBatchToken();
void deleteData();
@@ -149,8 +137,8 @@ public:
using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
UserReceipts readReceipts(const QString &event_id, const QString &room_id);
- QByteArray image(const QString &url) const;
- QByteArray image(lmdb::txn &txn, const std::string &url) const;
+ QByteArray image(const QString &url);
+ QByteArray image(lmdb::txn &txn, const std::string &url);
void saveImage(const std::string &url, const std::string &data);
void saveImage(const QString &url, const QByteArray &data);
@@ -330,8 +318,8 @@ private:
// void removeLeftRoom(lmdb::txn &txn, const std::string &room_id);
template<class T>
void saveStateEvents(lmdb::txn &txn,
- const lmdb::dbi &statesdb,
- const lmdb::dbi &membersdb,
+ lmdb::dbi &statesdb,
+ lmdb::dbi &membersdb,
const std::string &room_id,
const std::vector<T> &events)
{
@@ -341,8 +329,8 @@ private:
template<class T>
void saveStateEvent(lmdb::txn &txn,
- const lmdb::dbi &statesdb,
- const lmdb::dbi &membersdb,
+ lmdb::dbi &statesdb,
+ lmdb::dbi &membersdb,
const std::string &room_id,
const T &event)
{
@@ -363,17 +351,11 @@ private:
// Lightweight representation of a member.
MemberInfo tmp{display_name, e->content.avatar_url};
- lmdb::dbi_put(txn,
- membersdb,
- lmdb::val(e->state_key),
- lmdb::val(json(tmp).dump()));
-
+ membersdb.put(txn, e->state_key, json(tmp).dump());
break;
}
default: {
- lmdb::dbi_del(
- txn, membersdb, lmdb::val(e->state_key), lmdb::val(""));
-
+ membersdb.del(txn, e->state_key, "");
break;
}
}
@@ -387,12 +369,9 @@ private:
if (!isStateEvent(event))
return;
- std::visit(
- [&txn, &statesdb](auto e) {
- lmdb::dbi_put(
- txn, statesdb, lmdb::val(to_string(e.type)), lmdb::val(json(e).dump()));
- },
- event);
+ std::visit([&txn, &statesdb](
+ auto e) { statesdb.put(txn, to_string(e.type), json(e).dump()); },
+ event);
}
template<class T>
diff --git a/src/CallDevices.cpp b/src/CallDevices.cpp
index 0b9809e5..917b86b8 100644
--- a/src/CallDevices.cpp
+++ b/src/CallDevices.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <cstring>
#include <optional>
#include <string_view>
@@ -152,7 +156,6 @@ addDevice(GstDevice *device)
setDefaultDevice(true);
}
-#if GST_CHECK_VERSION(1, 18, 0)
template<typename T>
bool
removeDevice(T &sources, GstDevice *device, bool changed)
@@ -212,7 +215,6 @@ newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data G_G
}
return TRUE;
}
-#endif
template<typename T>
std::vector<std::string>
@@ -251,13 +253,11 @@ tokenise(std::string_view str, char delim)
ret.second = std::atoi(str.data() + pos + 1);
return ret;
}
-
}
void
CallDevices::init()
{
-#if GST_CHECK_VERSION(1, 18, 0)
static GstDeviceMonitor *monitor = nullptr;
if (!monitor) {
monitor = gst_device_monitor_new();
@@ -278,43 +278,6 @@ CallDevices::init()
return;
}
}
-#endif
-}
-
-void
-CallDevices::refresh()
-{
-#if !GST_CHECK_VERSION(1, 18, 0)
-
- static GstDeviceMonitor *monitor = nullptr;
- if (!monitor) {
- monitor = gst_device_monitor_new();
- GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw");
- gst_device_monitor_add_filter(monitor, "Audio/Source", caps);
- gst_device_monitor_add_filter(monitor, "Audio/Duplex", caps);
- gst_caps_unref(caps);
- caps = gst_caps_new_empty_simple("video/x-raw");
- gst_device_monitor_add_filter(monitor, "Video/Source", caps);
- gst_device_monitor_add_filter(monitor, "Video/Duplex", caps);
- gst_caps_unref(caps);
- }
-
- auto clearDevices = [](auto &sources) {
- std::for_each(
- sources.begin(), sources.end(), [](auto &s) { gst_object_unref(s.device); });
- sources.clear();
- };
- clearDevices(audioSources_);
- clearDevices(videoSources_);
-
- GList *devices = gst_device_monitor_get_devices(monitor);
- if (devices) {
- for (GList *l = devices; l != nullptr; l = l->next)
- addDevice(GST_DEVICE_CAST(l->data));
- g_list_free(devices);
- }
- emit devicesChanged();
-#endif
}
bool
@@ -400,10 +363,6 @@ CallDevices::videoDevice(std::pair<int, int> &resolution, std::pair<int, int> &f
#else
-void
-CallDevices::refresh()
-{}
-
bool
CallDevices::haveMic() const
{
diff --git a/src/CallDevices.h b/src/CallDevices.h
index 2b4129f1..69325f97 100644
--- a/src/CallDevices.h
+++ b/src/CallDevices.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <string>
@@ -19,7 +23,6 @@ public:
return instance;
}
- void refresh();
bool haveMic() const;
bool haveCamera() const;
std::vector<std::string> names(bool isVideo, const std::string &defaultDevice) const;
diff --git a/src/CallManager.cpp b/src/CallManager.cpp
index 7acd9592..6d41f1c6 100644
--- a/src/CallManager.cpp
+++ b/src/CallManager.cpp
@@ -1,7 +1,13 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <algorithm>
#include <cctype>
#include <chrono>
#include <cstdint>
+#include <cstdlib>
+#include <memory>
#include <QMediaPlaylist>
#include <QUrl>
@@ -17,6 +23,18 @@
#include "mtx/responses/turn_server.hpp"
+#ifdef XCB_AVAILABLE
+#include <xcb/xcb.h>
+#include <xcb/xcb_ewmh.h>
+#endif
+
+#ifdef GSTREAMER_AVAILABLE
+extern "C"
+{
+#include "gst/gst.h"
+}
+#endif
+
Q_DECLARE_METATYPE(std::vector<mtx::events::msg::CallCandidates::Candidate>)
Q_DECLARE_METATYPE(mtx::events::msg::CallCandidates::Candidate)
Q_DECLARE_METATYPE(mtx::responses::TurnServer)
@@ -24,6 +42,8 @@ Q_DECLARE_METATYPE(mtx::responses::TurnServer)
using namespace mtx::events;
using namespace mtx::events::msg;
+using webrtc::CallType;
+
namespace {
std::vector<std::string>
getTurnURIs(const mtx::responses::TurnServer &turnServer);
@@ -44,8 +64,8 @@ CallManager::CallManager(QObject *parent)
this,
[this](const std::string &sdp, const std::vector<CallCandidates::Candidate> &candidates) {
nhlog::ui()->debug("WebRTC: call id: {} - sending offer", callid_);
- emit newMessage(roomid_, CallInvite{callid_, sdp, 0, timeoutms_});
- emit newMessage(roomid_, CallCandidates{callid_, candidates, 0});
+ emit newMessage(roomid_, CallInvite{callid_, sdp, "0", timeoutms_});
+ emit newMessage(roomid_, CallCandidates{callid_, candidates, "0"});
std::string callid(callid_);
QTimer::singleShot(timeoutms_, this, [this, callid]() {
if (session_.state() == webrtc::State::OFFERSENT && callid == callid_) {
@@ -62,8 +82,8 @@ CallManager::CallManager(QObject *parent)
this,
[this](const std::string &sdp, const std::vector<CallCandidates::Candidate> &candidates) {
nhlog::ui()->debug("WebRTC: call id: {} - sending answer", callid_);
- emit newMessage(roomid_, CallAnswer{callid_, sdp, 0});
- emit newMessage(roomid_, CallCandidates{callid_, candidates, 0});
+ emit newMessage(roomid_, CallAnswer{callid_, sdp, "0"});
+ emit newMessage(roomid_, CallCandidates{callid_, candidates, "0"});
});
connect(&session_,
@@ -71,7 +91,7 @@ CallManager::CallManager(QObject *parent)
this,
[this](const CallCandidates::Candidate &candidate) {
nhlog::ui()->debug("WebRTC: call id: {} - sending ice candidate", callid_);
- emit newMessage(roomid_, CallCandidates{callid_, {candidate}, 0});
+ emit newMessage(roomid_, CallCandidates{callid_, {candidate}, "0"});
});
connect(&turnServerTimer_, &QTimer::timeout, this, &CallManager::retrieveTurnServer);
@@ -148,10 +168,18 @@ CallManager::CallManager(QObject *parent)
}
void
-CallManager::sendInvite(const QString &roomid, bool isVideo)
+CallManager::sendInvite(const QString &roomid, CallType callType, unsigned int windowIndex)
{
if (isOnCall())
return;
+ if (callType == CallType::SCREEN) {
+ if (!screenShareSupported())
+ return;
+ if (windows_.empty() || windowIndex >= windows_.size()) {
+ nhlog::ui()->error("WebRTC: window index out of range");
+ return;
+ }
+ }
auto roomInfo = cache::singleRoomInfo(roomid.toStdString());
if (roomInfo.member_count != 2) {
@@ -161,17 +189,20 @@ CallManager::sendInvite(const QString &roomid, bool isVideo)
std::string errorMessage;
if (!session_.havePlugins(false, &errorMessage) ||
- (isVideo && !session_.havePlugins(true, &errorMessage))) {
+ ((callType == CallType::VIDEO || callType == CallType::SCREEN) &&
+ !session_.havePlugins(true, &errorMessage))) {
emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
return;
}
- isVideo_ = isVideo;
- roomid_ = roomid;
+ callType_ = callType;
+ roomid_ = roomid;
session_.setTurnServers(turnURIs_);
generateCallID();
- nhlog::ui()->debug(
- "WebRTC: call id: {} - creating {} invite", callid_, isVideo ? "video" : "voice");
+ std::string strCallType = callType_ == CallType::VOICE
+ ? "voice"
+ : (callType_ == CallType::VIDEO ? "video" : "screen");
+ nhlog::ui()->debug("WebRTC: call id: {} - creating {} invite", callid_, strCallType);
std::vector<RoomMember> members(cache::getMembers(roomid.toStdString()));
const RoomMember &callee =
members.front().user_id == utils::localUser() ? members.back() : members.front();
@@ -179,7 +210,8 @@ CallManager::sendInvite(const QString &roomid, bool isVideo)
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
emit newInviteState();
playRingtone(QUrl("qrc:/media/media/ringback.ogg"), true);
- if (!session_.createOffer(isVideo)) {
+ if (!session_.createOffer(
+ callType, callType == CallType::SCREEN ? windows_[windowIndex].second : 0)) {
emit ChatPage::instance()->showNotification("Problem setting up call.");
endCall();
}
@@ -206,7 +238,7 @@ CallManager::hangUp(CallHangUp::Reason reason)
if (!callid_.empty()) {
nhlog::ui()->debug(
"WebRTC: call id: {} - hanging up ({})", callid_, callHangUpReasonString(reason));
- emit newMessage(roomid_, CallHangUp{callid_, 0, reason});
+ emit newMessage(roomid_, CallHangUp{callid_, "0", reason});
endCall();
}
}
@@ -215,8 +247,8 @@ void
CallManager::syncEvent(const mtx::events::collections::TimelineEvents &event)
{
#ifdef GSTREAMER_AVAILABLE
- if (handleEvent_<CallInvite>(event) || handleEvent_<CallCandidates>(event) ||
- handleEvent_<CallAnswer>(event) || handleEvent_<CallHangUp>(event))
+ if (handleEvent<CallInvite>(event) || handleEvent<CallCandidates>(event) ||
+ handleEvent<CallAnswer>(event) || handleEvent<CallHangUp>(event))
return;
#else
(void)event;
@@ -225,7 +257,7 @@ CallManager::syncEvent(const mtx::events::collections::TimelineEvents &event)
template<typename T>
bool
-CallManager::handleEvent_(const mtx::events::collections::TimelineEvents &event)
+CallManager::handleEvent(const mtx::events::collections::TimelineEvents &event)
{
if (std::holds_alternative<RoomEvent<T>>(event)) {
handleEvent(std::get<RoomEvent<T>>(event));
@@ -259,7 +291,7 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
if (isOnCall() || roomInfo.member_count != 2) {
emit newMessage(QString::fromStdString(callInviteEvent.room_id),
CallHangUp{callInviteEvent.content.call_id,
- 0,
+ "0",
CallHangUp::Reason::InviteTimeOut});
return;
}
@@ -280,9 +312,8 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
haveCallInvite_ = true;
- isVideo_ = isVideo;
+ callType_ = isVideo ? CallType::VIDEO : CallType::VOICE;
inviteSDP_ = callInviteEvent.content.sdp;
- CallDevices::instance().refresh();
emit newInviteState();
}
@@ -295,7 +326,7 @@ CallManager::acceptInvite()
stopRingtone();
std::string errorMessage;
if (!session_.havePlugins(false, &errorMessage) ||
- (isVideo_ && !session_.havePlugins(true, &errorMessage))) {
+ (callType_ == CallType::VIDEO && !session_.havePlugins(true, &errorMessage))) {
emit ChatPage::instance()->showNotification(QString::fromStdString(errorMessage));
hangUp();
return;
@@ -383,7 +414,7 @@ CallManager::toggleMicMute()
}
bool
-CallManager::callsSupported() const
+CallManager::callsSupported()
{
#ifdef GSTREAMER_AVAILABLE
return true;
@@ -392,6 +423,12 @@ CallManager::callsSupported() const
#endif
}
+bool
+CallManager::screenShareSupported()
+{
+ return std::getenv("DISPLAY") && !std::getenv("WAYLAND_DISPLAY");
+}
+
QStringList
CallManager::devices(bool isVideo) const
{
@@ -424,7 +461,7 @@ CallManager::clear()
callParty_.clear();
callPartyAvatarUrl_.clear();
callid_.clear();
- isVideo_ = false;
+ callType_ = CallType::VOICE;
haveCallInvite_ = false;
emit newInviteState();
inviteSDP_.clear();
@@ -477,6 +514,149 @@ CallManager::stopRingtone()
player_.setPlaylist(nullptr);
}
+QStringList
+CallManager::windowList()
+{
+ windows_.clear();
+ windows_.push_back({tr("Entire screen"), 0});
+
+#ifdef XCB_AVAILABLE
+ std::unique_ptr<xcb_connection_t, std::function<void(xcb_connection_t *)>> connection(
+ xcb_connect(nullptr, nullptr), [](xcb_connection_t *c) { xcb_disconnect(c); });
+ if (xcb_connection_has_error(connection.get())) {
+ nhlog::ui()->error("Failed to connect to X server");
+ return {};
+ }
+
+ xcb_ewmh_connection_t ewmh;
+ if (!xcb_ewmh_init_atoms_replies(
+ &ewmh, xcb_ewmh_init_atoms(connection.get(), &ewmh), nullptr)) {
+ nhlog::ui()->error("Failed to connect to EWMH server");
+ return {};
+ }
+ std::unique_ptr<xcb_ewmh_connection_t, std::function<void(xcb_ewmh_connection_t *)>>
+ ewmhconnection(&ewmh, [](xcb_ewmh_connection_t *c) { xcb_ewmh_connection_wipe(c); });
+
+ for (int i = 0; i < ewmh.nb_screens; i++) {
+ xcb_ewmh_get_windows_reply_t clients;
+ if (!xcb_ewmh_get_client_list_reply(
+ &ewmh, xcb_ewmh_get_client_list(&ewmh, i), &clients, nullptr)) {
+ nhlog::ui()->error("Failed to request window list");
+ return {};
+ }
+
+ for (uint32_t w = 0; w < clients.windows_len; w++) {
+ xcb_window_t window = clients.windows[w];
+
+ std::string name;
+ xcb_ewmh_get_utf8_strings_reply_t data;
+ auto getName = [](xcb_ewmh_get_utf8_strings_reply_t *r) {
+ std::string name(r->strings, r->strings_len);
+ xcb_ewmh_get_utf8_strings_reply_wipe(r);
+ return name;
+ };
+
+ xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_name(&ewmh, window);
+ if (xcb_ewmh_get_wm_name_reply(&ewmh, cookie, &data, nullptr))
+ name = getName(&data);
+
+ cookie = xcb_ewmh_get_wm_visible_name(&ewmh, window);
+ if (xcb_ewmh_get_wm_visible_name_reply(&ewmh, cookie, &data, nullptr))
+ name = getName(&data);
+
+ windows_.push_back({QString::fromStdString(name), window});
+ }
+ xcb_ewmh_get_windows_reply_wipe(&clients);
+ }
+#endif
+ QStringList ret;
+ ret.reserve(windows_.size());
+ for (const auto &w : windows_)
+ ret.append(w.first);
+
+ return ret;
+}
+
+#ifdef GSTREAMER_AVAILABLE
+namespace {
+
+GstElement *pipe_ = nullptr;
+unsigned int busWatchId_ = 0;
+
+gboolean
+newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer G_GNUC_UNUSED)
+{
+ switch (GST_MESSAGE_TYPE(msg)) {
+ case GST_MESSAGE_EOS:
+ if (pipe_) {
+ gst_element_set_state(GST_ELEMENT(pipe_), GST_STATE_NULL);
+ gst_object_unref(pipe_);
+ pipe_ = nullptr;
+ }
+ if (busWatchId_) {
+ g_source_remove(busWatchId_);
+ busWatchId_ = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+}
+#endif
+
+void
+CallManager::previewWindow(unsigned int index) const
+{
+#ifdef GSTREAMER_AVAILABLE
+ if (windows_.empty() || index >= windows_.size() || !gst_is_initialized())
+ return;
+
+ GstElement *ximagesrc = gst_element_factory_make("ximagesrc", nullptr);
+ if (!ximagesrc) {
+ nhlog::ui()->error("Failed to create ximagesrc");
+ return;
+ }
+ GstElement *videoconvert = gst_element_factory_make("videoconvert", nullptr);
+ GstElement *videoscale = gst_element_factory_make("videoscale", nullptr);
+ GstElement *capsfilter = gst_element_factory_make("capsfilter", nullptr);
+ GstElement *ximagesink = gst_element_factory_make("ximagesink", nullptr);
+
+ g_object_set(ximagesrc, "use-damage", FALSE, nullptr);
+ g_object_set(ximagesrc, "show-pointer", FALSE, nullptr);
+ g_object_set(ximagesrc, "xid", windows_[index].second, nullptr);
+
+ GstCaps *caps = gst_caps_new_simple(
+ "video/x-raw", "width", G_TYPE_INT, 480, "height", G_TYPE_INT, 360, nullptr);
+ g_object_set(capsfilter, "caps", caps, nullptr);
+ gst_caps_unref(caps);
+
+ pipe_ = gst_pipeline_new(nullptr);
+ gst_bin_add_many(
+ GST_BIN(pipe_), ximagesrc, videoconvert, videoscale, capsfilter, ximagesink, nullptr);
+ if (!gst_element_link_many(
+ ximagesrc, videoconvert, videoscale, capsfilter, ximagesink, nullptr)) {
+ nhlog::ui()->error("Failed to link preview window elements");
+ gst_object_unref(pipe_);
+ pipe_ = nullptr;
+ return;
+ }
+ if (gst_element_set_state(pipe_, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ nhlog::ui()->error("Unable to start preview pipeline");
+ gst_object_unref(pipe_);
+ pipe_ = nullptr;
+ return;
+ }
+
+ GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipe_));
+ busWatchId_ = gst_bus_add_watch(bus, newBusMessage, nullptr);
+ gst_object_unref(bus);
+#else
+ (void)index;
+#endif
+}
+
namespace {
std::vector<std::string>
getTurnURIs(const mtx::responses::TurnServer &turnServer)
diff --git a/src/CallManager.h b/src/CallManager.h
index 97cffbc8..1d973191 100644
--- a/src/CallManager.h
+++ b/src/CallManager.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <string>
@@ -25,41 +29,45 @@ class CallManager : public QObject
Q_OBJECT
Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState)
Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState)
- Q_PROPERTY(bool isVideo READ isVideo NOTIFY newInviteState)
- Q_PROPERTY(bool haveLocalVideo READ haveLocalVideo NOTIFY newCallState)
+ Q_PROPERTY(webrtc::CallType callType READ callType NOTIFY newInviteState)
Q_PROPERTY(webrtc::State callState READ callState NOTIFY newCallState)
Q_PROPERTY(QString callParty READ callParty NOTIFY newInviteState)
Q_PROPERTY(QString callPartyAvatarUrl READ callPartyAvatarUrl NOTIFY newInviteState)
Q_PROPERTY(bool isMicMuted READ isMicMuted NOTIFY micMuteChanged)
- Q_PROPERTY(bool callsSupported READ callsSupported CONSTANT)
+ Q_PROPERTY(bool haveLocalPiP READ haveLocalPiP NOTIFY newCallState)
Q_PROPERTY(QStringList mics READ mics NOTIFY devicesChanged)
Q_PROPERTY(QStringList cameras READ cameras NOTIFY devicesChanged)
+ Q_PROPERTY(bool callsSupported READ callsSupported CONSTANT)
+ Q_PROPERTY(bool screenShareSupported READ screenShareSupported CONSTANT)
public:
CallManager(QObject *);
bool haveCallInvite() const { return haveCallInvite_; }
bool isOnCall() const { return session_.state() != webrtc::State::DISCONNECTED; }
- bool isVideo() const { return isVideo_; }
- bool haveLocalVideo() const { return session_.haveLocalVideo(); }
+ webrtc::CallType callType() const { return callType_; }
webrtc::State callState() const { return session_.state(); }
QString callParty() const { return callParty_; }
QString callPartyAvatarUrl() const { return callPartyAvatarUrl_; }
bool isMicMuted() const { return session_.isMicMuted(); }
- bool callsSupported() const;
+ bool haveLocalPiP() const { return session_.haveLocalPiP(); }
QStringList mics() const { return devices(false); }
QStringList cameras() const { return devices(true); }
void refreshTurnServer();
+ static bool callsSupported();
+ static bool screenShareSupported();
+
public slots:
- void sendInvite(const QString &roomid, bool isVideo);
+ void sendInvite(const QString &roomid, webrtc::CallType, unsigned int windowIndex = 0);
void syncEvent(const mtx::events::collections::TimelineEvents &event);
- void refreshDevices() { CallDevices::instance().refresh(); }
void toggleMicMute();
- void toggleCameraView() { session_.toggleCameraView(); }
+ void toggleLocalPiP() { session_.toggleLocalPiP(); }
void acceptInvite();
void hangUp(
mtx::events::msg::CallHangUp::Reason = mtx::events::msg::CallHangUp::Reason::User);
+ QStringList windowList();
+ void previewWindow(unsigned int windowIndex) const;
signals:
void newMessage(const QString &roomid, const mtx::events::msg::CallInvite &);
@@ -81,17 +89,18 @@ private:
QString callParty_;
QString callPartyAvatarUrl_;
std::string callid_;
- const uint32_t timeoutms_ = 120000;
- bool isVideo_ = false;
- bool haveCallInvite_ = false;
+ const uint32_t timeoutms_ = 120000;
+ webrtc::CallType callType_ = webrtc::CallType::VOICE;
+ bool haveCallInvite_ = false;
std::string inviteSDP_;
std::vector<mtx::events::msg::CallCandidates::Candidate> remoteICECandidates_;
std::vector<std::string> turnURIs_;
QTimer turnServerTimer_;
QMediaPlayer player_;
+ std::vector<std::pair<QString, uint32_t>> windows_;
template<typename T>
- bool handleEvent_(const mtx::events::collections::TimelineEvents &event);
+ bool handleEvent(const mtx::events::collections::TimelineEvents &event);
void handleEvent(const mtx::events::RoomEvent<mtx::events::msg::CallInvite> &);
void handleEvent(const mtx::events::RoomEvent<mtx::events::msg::CallCandidates> &);
void handleEvent(const mtx::events::RoomEvent<mtx::events::msg::CallAnswer> &);
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index dbd93d1f..7c018aff 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QApplication>
#include <QImageReader>
@@ -252,6 +240,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
this, &ChatPage::updateGroupsInfo, communitiesList_, &CommunitiesList::setCommunities);
connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom);
+ connect(this, &ChatPage::newRoom, this, &ChatPage::changeRoom, Qt::QueuedConnection);
connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendNotifications);
connect(this,
&ChatPage::highlightedNotifsRetrieved,
@@ -474,6 +463,8 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
http::client()->set_server(homeserver.toStdString());
http::client()->set_access_token(token.toStdString());
+ http::client()->verify_certificates(
+ !UserSettings::instance()->disableCertificateValidation());
// The Olm client needs the user_id & device_id that will be included
// in the generated payloads & keys.
@@ -762,7 +753,11 @@ ChatPage::startInitialSync()
const auto err_code = mtx::errors::to_string(err->matrix_error.errcode);
const int status_code = static_cast<int>(err->status_code);
- nhlog::net()->error("initial sync error: {} {}", status_code, err_code);
+ nhlog::net()->error("initial sync error: {} {} {} {}",
+ err->parse_error,
+ status_code,
+ err->error_code.message(),
+ err_code);
// non http related errors
if (status_code <= 0 || status_code >= 600) {
@@ -865,11 +860,14 @@ ChatPage::trySync()
http::client()->sync(
opts,
- [this, since = cache::nextBatchToken()](const mtx::responses::Sync &res,
- mtx::http::RequestErr err) {
- if (since != cache::nextBatchToken()) {
- nhlog::net()->warn("Duplicate sync, dropping");
- return;
+ [this, since = opts.since](const mtx::responses::Sync &res, mtx::http::RequestErr err) {
+ try {
+ if (since != cache::nextBatchToken()) {
+ nhlog::net()->warn("Duplicate sync, dropping");
+ return;
+ }
+ } catch (const lmdb::error &e) {
+ nhlog::db()->warn("Logged out in the mean time, dropping sync");
}
if (err) {
@@ -888,7 +886,11 @@ ChatPage::trySync()
return;
}
- nhlog::net()->error("sync error: {} {}", status_code, err_code);
+ nhlog::net()->error("initial sync error: {} {} {} {}",
+ err->parse_error,
+ status_code,
+ err->error_code.message(),
+ err_code);
emit tryDelayedSyncCb();
return;
}
@@ -901,12 +903,22 @@ void
ChatPage::joinRoom(const QString &room)
{
const auto room_id = room.toStdString();
- joinRoomVia(room_id, {});
+ joinRoomVia(room_id, {}, false);
}
void
-ChatPage::joinRoomVia(const std::string &room_id, const std::vector<std::string> &via)
+ChatPage::joinRoomVia(const std::string &room_id,
+ const std::vector<std::string> &via,
+ bool promptForConfirmation)
{
+ if (promptForConfirmation &&
+ QMessageBox::Yes !=
+ QMessageBox::question(
+ this,
+ tr("Confirm join"),
+ tr("Do you really want to join %1?").arg(QString::fromStdString(room_id))))
+ return;
+
http::client()->join_room(
room_id, via, [this, room_id](const mtx::responses::RoomId &, mtx::http::RequestErr err) {
if (err) {
@@ -947,8 +959,9 @@ ChatPage::createRoom(const mtx::requests::CreateRoom &req)
return;
}
- emit showNotification(
- tr("Room %1 created.").arg(QString::fromStdString(res.room_id.to_string())));
+ QString newRoomId = QString::fromStdString(res.room_id.to_string());
+ emit showNotification(tr("Room %1 created.").arg(newRoomId));
+ emit newRoom(newRoomId);
});
}
@@ -970,6 +983,13 @@ ChatPage::leaveRoom(const QString &room_id)
}
void
+ChatPage::changeRoom(const QString &room_id)
+{
+ view_manager_->setHistoryView(room_id);
+ room_list_->highlightSelectedRoom(room_id);
+}
+
+void
ChatPage::inviteUser(QString userid, QString reason)
{
auto room = current_room_;
@@ -1295,6 +1315,13 @@ ChatPage::startChat(QString userid)
}
}
+ if (QMessageBox::Yes !=
+ QMessageBox::question(
+ this,
+ tr("Confirm invite"),
+ tr("Do you really want to start a private chat with %1?").arg(userid)))
+ return;
+
mtx::requests::CreateRoom req;
req.preset = mtx::requests::Preset::PrivateChat;
req.visibility = mtx::common::RoomVisibility::Private;
@@ -1349,7 +1376,7 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
return;
QString mxid2;
- if (segments.size() == 4 && segments[2] == "e") {
+ if (segments.size() == 4 && segments[2] == "event") {
if (segments[3].isEmpty())
return;
else
@@ -1383,11 +1410,11 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
for (auto roomid : joined_rooms) {
if (roomid == targetRoomId) {
room_list_->highlightSelectedRoom(mxid1);
- break;
+ return;
}
}
- if (action == "join") {
+ if (action == "join" || action.isEmpty()) {
joinRoomVia(targetRoomId, vias);
}
} else if (sigil1 == "r") {
@@ -1400,12 +1427,12 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
if (aliases->alias == targetRoomAlias) {
room_list_->highlightSelectedRoom(
QString::fromStdString(roomid));
- break;
+ return;
}
}
}
- if (action == "join") {
+ if (action == "join" || action.isEmpty()) {
joinRoomVia(mxid1.toStdString(), vias);
}
}
diff --git a/src/ChatPage.h b/src/ChatPage.h
index 316ca9ae..17a4827f 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -116,7 +104,9 @@ public slots:
void createRoom(const mtx::requests::CreateRoom &req);
void highlightRoom(const QString &room_id);
void joinRoom(const QString &room);
- void joinRoomVia(const std::string &room_id, const std::vector<std::string> &via);
+ void joinRoomVia(const std::string &room_id,
+ const std::vector<std::string> &via,
+ bool promptForConfirmation = true);
void inviteUser(QString userid, QString reason);
void kickUser(QString userid, QString reason);
@@ -153,6 +143,7 @@ signals:
void tryInitialSyncCb();
void newSyncResponse(const mtx::responses::Sync &res);
void leftRoom(const QString &room_id);
+ void newRoom(const QString &room_id);
void initializeRoomList(QMap<QString, RoomInfo>);
void initializeViews(const mtx::responses::Rooms &rooms);
@@ -200,6 +191,7 @@ signals:
private slots:
void logout();
void removeRoom(const QString &room_id);
+ void changeRoom(const QString &room_id);
void dropToLoginPage(const QString &msg);
void handleSyncResponse(const mtx::responses::Sync &res);
diff --git a/src/ColorImageProvider.cpp b/src/ColorImageProvider.cpp
index c580c394..41fd5d8f 100644
--- a/src/ColorImageProvider.cpp
+++ b/src/ColorImageProvider.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "ColorImageProvider.h"
#include <QPainter>
diff --git a/src/ColorImageProvider.h b/src/ColorImageProvider.h
index 21f36c12..9ae8c85e 100644
--- a/src/ColorImageProvider.h
+++ b/src/ColorImageProvider.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QQuickImageProvider>
class ColorImageProvider : public QQuickImageProvider
diff --git a/src/CommunitiesList.cpp b/src/CommunitiesList.cpp
index 8bc71d91..f644ebee 100644
--- a/src/CommunitiesList.cpp
+++ b/src/CommunitiesList.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "CommunitiesList.h"
#include "Cache.h"
#include "Logging.h"
diff --git a/src/CommunitiesList.h b/src/CommunitiesList.h
index 5113e7ed..2586f6f5 100644
--- a/src/CommunitiesList.h
+++ b/src/CommunitiesList.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QScrollArea>
diff --git a/src/CommunitiesListItem.cpp b/src/CommunitiesListItem.cpp
index 01c39fdc..3a121dc0 100644
--- a/src/CommunitiesListItem.cpp
+++ b/src/CommunitiesListItem.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "CommunitiesListItem.h"
#include <QMenu>
diff --git a/src/CommunitiesListItem.h b/src/CommunitiesListItem.h
index a80e3200..006511c8 100644
--- a/src/CommunitiesListItem.h
+++ b/src/CommunitiesListItem.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QSharedPointer>
diff --git a/src/CompletionModelRoles.h b/src/CompletionModelRoles.h
index 7c7307d3..8505e761 100644
--- a/src/CompletionModelRoles.h
+++ b/src/CompletionModelRoles.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAbstractItemModel>
diff --git a/src/CompletionProxyModel.cpp b/src/CompletionProxyModel.cpp
index 35b8d0a9..a6759978 100644
--- a/src/CompletionProxyModel.cpp
+++ b/src/CompletionProxyModel.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "CompletionProxyModel.h"
#include <QRegularExpression>
diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h
index fc419702..214845b7 100644
--- a/src/CompletionProxyModel.h
+++ b/src/CompletionProxyModel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
// Class for showing a limited amount of completions at a time
diff --git a/src/Config.h b/src/Config.h
index c0624709..d3fee836 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QRegularExpression>
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index c6277a9d..f7fb6c35 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "DeviceVerificationFlow.h"
#include "Cache.h"
@@ -45,7 +49,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
- err->matrix_error.errcode,
+ mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
@@ -64,7 +68,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
[this](const UserKeyCache &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
- err->matrix_error.errcode,
+ mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
@@ -345,7 +349,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
if (err) {
nhlog::net()->error(
"failed to upload signatures: {},{}",
- err->matrix_error.errcode,
+ mtx::errors::to_string(
+ err->matrix_error.errcode),
static_cast<int>(err->status_code));
}
@@ -356,7 +361,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
"id {}: {}, {}",
user_id,
key_id,
- e.errcode,
+ mtx::errors::to_string(e.errcode),
e.error);
});
}
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index 6c613545..4685a450 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QObject>
diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index e6bc61b0..cfc41a98 100644
--- a/src/EventAccessors.cpp
+++ b/src/EventAccessors.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "EventAccessors.h"
#include <nlohmann/json.hpp>
diff --git a/src/EventAccessors.h b/src/EventAccessors.h
index 7bf695fc..ced159c1 100644
--- a/src/EventAccessors.h
+++ b/src/EventAccessors.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <string>
diff --git a/src/InviteeItem.cpp b/src/InviteeItem.cpp
index a6b471dc..27f02560 100644
--- a/src/InviteeItem.cpp
+++ b/src/InviteeItem.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
diff --git a/src/InviteeItem.h b/src/InviteeItem.h
index 54c61938..014541ea 100644
--- a/src/InviteeItem.h
+++ b/src/InviteeItem.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QWidget>
diff --git a/src/Logging.cpp b/src/Logging.cpp
index e537ef7a..436de811 100644
--- a/src/Logging.cpp
+++ b/src/Logging.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "Logging.h"
#include "config/nheko.h"
diff --git a/src/Logging.h b/src/Logging.h
index f572afae..e09705d1 100644
--- a/src/Logging.h
+++ b/src/Logging.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <memory>
diff --git a/src/LoginPage.cpp b/src/LoginPage.cpp
index 26a170c5..0108a9f4 100644
--- a/src/LoginPage.cpp
+++ b/src/LoginPage.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QDesktopServices>
#include <QFontMetrics>
@@ -31,6 +19,7 @@
#include "LoginPage.h"
#include "MatrixClient.h"
#include "SSOHandler.h"
+#include "UserSettingsPage.h"
#include "ui/FlatButton.h"
#include "ui/LoadingIndicator.h"
#include "ui/OverlayModal.h"
@@ -192,6 +181,11 @@ LoginPage::LoginPage(QWidget *parent)
connect(sso_login_button_, &RaisedButton::clicked, this, [this]() {
onLoginButtonClicked(LoginMethod::SSO);
});
+ connect(this,
+ &LoginPage::showErrorMessage,
+ this,
+ static_cast<void (LoginPage::*)(QLabel *, const QString &)>(&LoginPage::showError),
+ Qt::QueuedConnection);
connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(deviceName_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
@@ -263,6 +257,9 @@ LoginPage::onMatrixIdEntered()
serverInput_->setText(homeServer);
http::client()->set_server(user.hostname());
+ http::client()->verify_certificates(
+ !UserSettings::instance()->disableCertificateValidation());
+
http::client()->well_known([this](const mtx::responses::WellKnown &res,
mtx::http::RequestErr err) {
if (err) {
@@ -347,6 +344,8 @@ void
LoginPage::onServerAddressEntered()
{
error_label_->setText("");
+ http::client()->verify_certificates(
+ !UserSettings::instance()->disableCertificateValidation());
http::client()->set_server(serverInput_->text().toStdString());
checkHomeserverVersion();
@@ -390,7 +389,6 @@ void
LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
{
error_label_->setText("");
-
User user;
if (!matrixid_input_->isValid()) {
@@ -422,8 +420,8 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
: deviceName_->text().toStdString(),
[this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
if (err) {
- showError(error_label_,
- QString::fromStdString(err->matrix_error.error));
+ showErrorMessage(error_label_,
+ QString::fromStdString(err->matrix_error.error));
emit errorOccurred();
return;
}
@@ -448,7 +446,7 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
http::client()->login(
req, [this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
if (err) {
- showError(
+ showErrorMessage(
error_label_,
QString::fromStdString(err->matrix_error.error));
emit errorOccurred();
@@ -467,7 +465,7 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
sso->deleteLater();
});
connect(sso, &SSOHandler::ssoFailed, this, [this, sso]() {
- showError(error_label_, tr("SSO login failed"));
+ showErrorMessage(error_label_, tr("SSO login failed"));
emit errorOccurred();
sso->deleteLater();
});
diff --git a/src/LoginPage.h b/src/LoginPage.h
index 2341c0ce..2e1eb9b9 100644
--- a/src/LoginPage.h
+++ b/src/LoginPage.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -59,6 +47,7 @@ signals:
void versionOkCb(bool passwordSupported, bool ssoSupported);
void loginOk(const mtx::responses::Login &res);
+ void showErrorMessage(QLabel *label, const QString &msg);
protected:
void paintEvent(QPaintEvent *event) override;
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 3555c363..92f43e03 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QApplication>
#include <QLayout>
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 4a8ea642..4122e4c1 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/MatrixClient.cpp b/src/MatrixClient.cpp
index 669dc270..196a9322 100644
--- a/src/MatrixClient.cpp
+++ b/src/MatrixClient.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "MatrixClient.h"
#include <memory>
diff --git a/src/MatrixClient.h b/src/MatrixClient.h
index 4db51095..605ba5e0 100644
--- a/src/MatrixClient.h
+++ b/src/MatrixClient.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <mtxclient/http/client.hpp>
diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp
index b48fe011..e4f629a5 100644
--- a/src/MxcImageProvider.cpp
+++ b/src/MxcImageProvider.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "MxcImageProvider.h"
#include <mtxclient/crypto/client.hpp>
diff --git a/src/MxcImageProvider.h b/src/MxcImageProvider.h
index 2c197a13..f7580bca 100644
--- a/src/MxcImageProvider.h
+++ b/src/MxcImageProvider.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QQuickAsyncImageProvider>
diff --git a/src/Olm.cpp b/src/Olm.cpp
index 54be4751..311aeb7f 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "Olm.h"
#include <QObject>
diff --git a/src/Olm.h b/src/Olm.h
index 7058782b..bcb486a3 100644
--- a/src/Olm.h
+++ b/src/Olm.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <boost/optional.hpp>
diff --git a/src/RegisterPage.cpp b/src/RegisterPage.cpp
index 44ad7a3d..5c5545ec 100644
--- a/src/RegisterPage.cpp
+++ b/src/RegisterPage.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QLabel>
#include <QMetaType>
@@ -277,6 +265,7 @@ RegisterPage::RegisterPage(QWidget *parent)
if (!err) {
http::client()->set_user(res.user_id);
http::client()->set_access_token(res.access_token);
+ http::client()->set_device_id(res.device_id);
emit registerOk();
return;
@@ -415,6 +404,8 @@ RegisterPage::onRegisterButtonClicked()
auto server = server_input_->text().toStdString();
http::client()->set_server(server);
+ http::client()->verify_certificates(
+ !UserSettings::instance()->disableCertificateValidation());
http::client()->registration(
username,
password,
diff --git a/src/RegisterPage.h b/src/RegisterPage.h
index 6d212955..2f05d04c 100644
--- a/src/RegisterPage.h
+++ b/src/RegisterPage.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp
index b5ba5af1..d74f9dc9 100644
--- a/src/RoomInfoListItem.cpp
+++ b/src/RoomInfoListItem.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QDateTime>
#include <QInputDialog>
diff --git a/src/RoomInfoListItem.h b/src/RoomInfoListItem.h
index c2826f6f..a5e0009e 100644
--- a/src/RoomInfoListItem.h
+++ b/src/RoomInfoListItem.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index 10042c94..8a807e71 100644
--- a/src/RoomList.cpp
+++ b/src/RoomList.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <limits>
#include <set>
diff --git a/src/RoomList.h b/src/RoomList.h
index 5350a2ab..74152c55 100644
--- a/src/RoomList.h
+++ b/src/RoomList.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/RoomsModel.cpp b/src/RoomsModel.cpp
index 4286f87b..1c3085ea 100644
--- a/src/RoomsModel.cpp
+++ b/src/RoomsModel.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "RoomsModel.h"
#include <QUrl>
diff --git a/src/RoomsModel.h b/src/RoomsModel.h
index 0e006448..255f207c 100644
--- a/src/RoomsModel.h
+++ b/src/RoomsModel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include "Cache.h"
diff --git a/src/SSOHandler.cpp b/src/SSOHandler.cpp
index cacbbaa9..8fd0828c 100644
--- a/src/SSOHandler.cpp
+++ b/src/SSOHandler.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "SSOHandler.h"
#include <QTimer>
diff --git a/src/SSOHandler.h b/src/SSOHandler.h
index 325b7a58..bd0d424d 100644
--- a/src/SSOHandler.h
+++ b/src/SSOHandler.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "httplib.h"
#include <QObject>
diff --git a/src/SideBarActions.cpp b/src/SideBarActions.cpp
index 5af01cc2..0b7756f0 100644
--- a/src/SideBarActions.cpp
+++ b/src/SideBarActions.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QIcon>
#include <QPainter>
#include <QResizeEvent>
diff --git a/src/SideBarActions.h b/src/SideBarActions.h
index 662750b3..566aa76b 100644
--- a/src/SideBarActions.h
+++ b/src/SideBarActions.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAction>
diff --git a/src/Splitter.cpp b/src/Splitter.cpp
index a2757d8e..15e3f5c5 100644
--- a/src/Splitter.cpp
+++ b/src/Splitter.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QSettings>
diff --git a/src/Splitter.h b/src/Splitter.h
index 7bde89de..94622f89 100644
--- a/src/Splitter.h
+++ b/src/Splitter.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/TrayIcon.cpp b/src/TrayIcon.cpp
index 6ab011d1..f2a01432 100644
--- a/src/TrayIcon.cpp
+++ b/src/TrayIcon.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QAction>
#include <QApplication>
diff --git a/src/TrayIcon.h b/src/TrayIcon.h
index 24ac81da..10dfafc5 100644
--- a/src/TrayIcon.h
+++ b/src/TrayIcon.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/UserInfoWidget.cpp b/src/UserInfoWidget.cpp
index 5bcb44a9..3d526b8b 100644
--- a/src/UserInfoWidget.cpp
+++ b/src/UserInfoWidget.cpp
@@ -1,20 +1,7 @@
-
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QInputDialog>
#include <QLabel>
diff --git a/src/UserInfoWidget.h b/src/UserInfoWidget.h
index bfcfbc0b..5aec1cda 100644
--- a/src/UserInfoWidget.h
+++ b/src/UserInfoWidget.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index b6fdf504..0edc1288 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QApplication>
#include <QComboBox>
@@ -107,13 +95,17 @@ UserSettings::load(std::optional<QString> profile)
auto presenceValue = QMetaEnum::fromType<Presence>().keyToValue(tempPresence.c_str());
if (presenceValue < 0)
presenceValue = 0;
- presence_ = static_cast<Presence>(presenceValue);
- ringtone_ = settings.value("user/ringtone", "Default").toString();
- microphone_ = settings.value("user/microphone", QString()).toString();
- camera_ = settings.value("user/camera", QString()).toString();
- cameraResolution_ = settings.value("user/camera_resolution", QString()).toString();
- cameraFrameRate_ = settings.value("user/camera_frame_rate", QString()).toString();
- useStunServer_ = settings.value("user/use_stun_server", false).toBool();
+ presence_ = static_cast<Presence>(presenceValue);
+ ringtone_ = settings.value("user/ringtone", "Default").toString();
+ microphone_ = settings.value("user/microphone", QString()).toString();
+ camera_ = settings.value("user/camera", QString()).toString();
+ cameraResolution_ = settings.value("user/camera_resolution", QString()).toString();
+ cameraFrameRate_ = settings.value("user/camera_frame_rate", QString()).toString();
+ screenShareFrameRate_ = settings.value("user/screen_share_frame_rate", 5).toInt();
+ screenSharePiP_ = settings.value("user/screen_share_pip", true).toBool();
+ screenShareRemoteVideo_ = settings.value("user/screen_share_remote_video", false).toBool();
+ screenShareHideCursor_ = settings.value("user/screen_share_hide_cursor", false).toBool();
+ useStunServer_ = settings.value("user/use_stun_server", false).toBool();
if (profile) // set to "" if it's the default to maintain compatibility
profile_ = (*profile == "default") ? "" : *profile;
@@ -127,6 +119,9 @@ UserSettings::load(std::optional<QString> profile)
userId_ = settings.value(prefix + "auth/user_id", "").toString();
deviceId_ = settings.value(prefix + "auth/device_id", "").toString();
+ disableCertificateValidation_ =
+ settings.value("disable_certificate_validation", false).toBool();
+
applyTheme();
}
void
@@ -445,6 +440,46 @@ UserSettings::setCameraFrameRate(QString frameRate)
}
void
+UserSettings::setScreenShareFrameRate(int frameRate)
+{
+ if (frameRate == screenShareFrameRate_)
+ return;
+ screenShareFrameRate_ = frameRate;
+ emit screenShareFrameRateChanged(frameRate);
+ save();
+}
+
+void
+UserSettings::setScreenSharePiP(bool state)
+{
+ if (state == screenSharePiP_)
+ return;
+ screenSharePiP_ = state;
+ emit screenSharePiPChanged(state);
+ save();
+}
+
+void
+UserSettings::setScreenShareRemoteVideo(bool state)
+{
+ if (state == screenShareRemoteVideo_)
+ return;
+ screenShareRemoteVideo_ = state;
+ emit screenShareRemoteVideoChanged(state);
+ save();
+}
+
+void
+UserSettings::setScreenShareHideCursor(bool state)
+{
+ if (state == screenShareHideCursor_)
+ return;
+ screenShareHideCursor_ = state;
+ emit screenShareHideCursorChanged(state);
+ save();
+}
+
+void
UserSettings::setProfile(QString profile)
{
if (profile == profile_)
@@ -495,6 +530,17 @@ UserSettings::setHomeserver(QString homeserver)
}
void
+UserSettings::setDisableCertificateValidation(bool disabled)
+{
+ if (disabled == disableCertificateValidation_)
+ return;
+ disableCertificateValidation_ = disabled;
+ http::client()->verify_certificates(!disabled);
+ emit disableCertificateValidationChanged(disabled);
+ save();
+}
+
+void
UserSettings::applyTheme()
{
QFile stylefile;
@@ -593,6 +639,10 @@ UserSettings::save()
settings.setValue("camera", camera_);
settings.setValue("camera_resolution", cameraResolution_);
settings.setValue("camera_frame_rate", cameraFrameRate_);
+ settings.setValue("screen_share_frame_rate", screenShareFrameRate_);
+ settings.setValue("screen_share_pip", screenSharePiP_);
+ settings.setValue("screen_share_remote_video", screenShareRemoteVideo_);
+ settings.setValue("screen_share_hide_cursor", screenShareHideCursor_);
settings.setValue("use_stun_server", useStunServer_);
settings.setValue("currentProfile", profile_);
@@ -605,6 +655,8 @@ UserSettings::save()
settings.setValue(prefix + "auth/user_id", userId_);
settings.setValue(prefix + "auth/device_id", deviceId_);
+ settings.setValue("disable_certificate_validation", disableCertificateValidation_);
+
settings.sync();
}
@@ -1240,7 +1292,6 @@ UserSettingsPage::showEvent(QShowEvent *)
timelineMaxWidthSpin_->setValue(settings_->timelineMaxWidth());
privacyScreenTimeout_->setValue(settings_->privacyScreenTimeout());
- CallDevices::instance().refresh();
auto mics = CallDevices::instance().names(false, settings_->microphone().toStdString());
microphoneCombo_->clear();
for (const auto &m : mics)
diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index 49de94b3..3ad0293b 100644
--- a/src/UserSettingsPage.h
+++ b/src/UserSettingsPage.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -86,6 +74,14 @@ class UserSettings : public QObject
cameraResolutionChanged)
Q_PROPERTY(QString cameraFrameRate READ cameraFrameRate WRITE setCameraFrameRate NOTIFY
cameraFrameRateChanged)
+ Q_PROPERTY(int screenShareFrameRate READ screenShareFrameRate WRITE setScreenShareFrameRate
+ NOTIFY screenShareFrameRateChanged)
+ Q_PROPERTY(bool screenSharePiP READ screenSharePiP WRITE setScreenSharePiP NOTIFY
+ screenSharePiPChanged)
+ Q_PROPERTY(bool screenShareRemoteVideo READ screenShareRemoteVideo WRITE
+ setScreenShareRemoteVideo NOTIFY screenShareRemoteVideoChanged)
+ Q_PROPERTY(bool screenShareHideCursor READ screenShareHideCursor WRITE
+ setScreenShareHideCursor NOTIFY screenShareHideCursorChanged)
Q_PROPERTY(
bool useStunServer READ useStunServer WRITE setUseStunServer NOTIFY useStunServerChanged)
Q_PROPERTY(bool shareKeysWithTrustedUsers READ shareKeysWithTrustedUsers WRITE
@@ -96,6 +92,8 @@ class UserSettings : public QObject
QString accessToken READ accessToken WRITE setAccessToken NOTIFY accessTokenChanged)
Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
+ Q_PROPERTY(bool disableCertificateValidation READ disableCertificateValidation WRITE
+ setDisableCertificateValidation NOTIFY disableCertificateValidationChanged)
UserSettings();
@@ -143,6 +141,10 @@ public:
void setCamera(QString camera);
void setCameraResolution(QString resolution);
void setCameraFrameRate(QString frameRate);
+ void setScreenShareFrameRate(int frameRate);
+ void setScreenSharePiP(bool state);
+ void setScreenShareRemoteVideo(bool state);
+ void setScreenShareHideCursor(bool state);
void setUseStunServer(bool state);
void setShareKeysWithTrustedUsers(bool state);
void setProfile(QString profile);
@@ -150,6 +152,7 @@ public:
void setAccessToken(QString accessToken);
void setDeviceId(QString deviceId);
void setHomeserver(QString homeserver);
+ void setDisableCertificateValidation(bool disabled);
void setHiddenTags(QStringList hiddenTags);
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
@@ -191,6 +194,10 @@ public:
QString camera() const { return camera_; }
QString cameraResolution() const { return cameraResolution_; }
QString cameraFrameRate() const { return cameraFrameRate_; }
+ int screenShareFrameRate() const { return screenShareFrameRate_; }
+ bool screenSharePiP() const { return screenSharePiP_; }
+ bool screenShareRemoteVideo() const { return screenShareRemoteVideo_; }
+ bool screenShareHideCursor() const { return screenShareHideCursor_; }
bool useStunServer() const { return useStunServer_; }
bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; }
QString profile() const { return profile_; }
@@ -198,6 +205,7 @@ public:
QString accessToken() const { return accessToken_; }
QString deviceId() const { return deviceId_; }
QString homeserver() const { return homeserver_; }
+ bool disableCertificateValidation() const { return disableCertificateValidation_; }
QStringList hiddenTags() const { return hiddenTags_; }
signals:
@@ -229,6 +237,10 @@ signals:
void cameraChanged(QString camera);
void cameraResolutionChanged(QString resolution);
void cameraFrameRateChanged(QString frameRate);
+ void screenShareFrameRateChanged(int frameRate);
+ void screenSharePiPChanged(bool state);
+ void screenShareRemoteVideoChanged(bool state);
+ void screenShareHideCursorChanged(bool state);
void useStunServerChanged(bool state);
void shareKeysWithTrustedUsersChanged(bool state);
void profileChanged(QString profile);
@@ -236,6 +248,7 @@ signals:
void accessTokenChanged(QString accessToken);
void deviceIdChanged(QString deviceId);
void homeserverChanged(QString homeserver);
+ void disableCertificateValidationChanged(bool disabled);
private:
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
@@ -272,7 +285,12 @@ private:
QString camera_;
QString cameraResolution_;
QString cameraFrameRate_;
+ int screenShareFrameRate_;
+ bool screenSharePiP_;
+ bool screenShareRemoteVideo_;
+ bool screenShareHideCursor_;
bool useStunServer_;
+ bool disableCertificateValidation_ = false;
QString profile_;
QString userId_;
QString accessToken_;
diff --git a/src/UsersModel.cpp b/src/UsersModel.cpp
index 4be37503..dd77e512 100644
--- a/src/UsersModel.cpp
+++ b/src/UsersModel.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "UsersModel.h"
#include "Cache.h"
diff --git a/src/UsersModel.h b/src/UsersModel.h
index cd9b780c..5bc94b0f 100644
--- a/src/UsersModel.h
+++ b/src/UsersModel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAbstractListModel>
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 991fa550..7106d865 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "Utils.h"
#include <QApplication>
@@ -347,11 +351,15 @@ utils::humanReadableFingerprint(const std::string &ed25519)
QString
utils::humanReadableFingerprint(const QString &ed25519)
{
- QStringList fingerprintList;
+ QString fingerprint;
for (int i = 0; i < ed25519.length(); i = i + 4) {
- fingerprintList << ed25519.mid(i, 4);
+ fingerprint.append(ed25519.midRef(i, 4));
+ if (i > 0 && i % 16 == 12)
+ fingerprint.append('\n');
+ else if (i < ed25519.length())
+ fingerprint.append(' ');
}
- return fingerprintList.join(" ");
+ return fingerprint;
}
QString
diff --git a/src/Utils.h b/src/Utils.h
index 6de3d458..373bed01 100644
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <variant>
diff --git a/src/WebRTCSession.cpp b/src/WebRTCSession.cpp
index b6d98058..880a14a2 100644
--- a/src/WebRTCSession.cpp
+++ b/src/WebRTCSession.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QQmlEngine>
#include <QQuickItem>
#include <algorithm>
@@ -10,6 +14,7 @@
#include <thread>
#include <utility>
+#include "CallDevices.h"
#include "ChatPage.h"
#include "Logging.h"
#include "UserSettingsPage.h"
@@ -29,14 +34,20 @@ extern "C"
// https://github.com/vector-im/riot-web/issues/10173
#define STUN_SERVER "stun://turn.matrix.org:3478"
+Q_DECLARE_METATYPE(webrtc::CallType)
Q_DECLARE_METATYPE(webrtc::State)
+using webrtc::CallType;
using webrtc::State;
WebRTCSession::WebRTCSession()
: QObject()
, devices_(CallDevices::instance())
{
+ qRegisterMetaType<webrtc::CallType>();
+ qmlRegisterUncreatableMetaObject(
+ webrtc::staticMetaObject, "im.nheko", 1, 0, "CallType", "Can't instantiate enum");
+
qRegisterMetaType<webrtc::State>();
qmlRegisterUncreatableMetaObject(
webrtc::staticMetaObject, "im.nheko", 1, 0, "WebRTCState", "Can't instantiate enum");
@@ -82,9 +93,10 @@ namespace {
std::string localsdp_;
std::vector<mtx::events::msg::CallCandidates::Candidate> localcandidates_;
-bool haveAudioStream_;
-bool haveVideoStream_;
-GstPad *insetSinkPad_ = nullptr;
+bool haveAudioStream_ = false;
+bool haveVideoStream_ = false;
+GstPad *localPiPSinkPad_ = nullptr;
+GstPad *remotePiPSinkPad_ = nullptr;
gboolean
newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data)
@@ -166,7 +178,6 @@ createAnswer(GstPromise *promise, gpointer webrtc)
g_signal_emit_by_name(webrtc, "create-answer", nullptr, promise);
}
-#if GST_CHECK_VERSION(1, 18, 0)
void
iceGatheringStateChanged(GstElement *webrtc,
GParamSpec *pspec G_GNUC_UNUSED,
@@ -186,23 +197,6 @@ iceGatheringStateChanged(GstElement *webrtc,
}
}
-#else
-
-gboolean
-onICEGatheringCompletion(gpointer timerid)
-{
- *(guint *)(timerid) = 0;
- if (WebRTCSession::instance().isOffering()) {
- emit WebRTCSession::instance().offerCreated(localsdp_, localcandidates_);
- emit WebRTCSession::instance().stateChanged(State::OFFERSENT);
- } else {
- emit WebRTCSession::instance().answerCreated(localsdp_, localcandidates_);
- emit WebRTCSession::instance().stateChanged(State::ANSWERSENT);
- }
- return FALSE;
-}
-#endif
-
void
addLocalICECandidate(GstElement *webrtc G_GNUC_UNUSED,
guint mlineIndex,
@@ -210,28 +204,7 @@ addLocalICECandidate(GstElement *webrtc G_GNUC_UNUSED,
gpointer G_GNUC_UNUSED)
{
nhlog::ui()->debug("WebRTC: local candidate: (m-line:{}):{}", mlineIndex, candidate);
-
-#if GST_CHECK_VERSION(1, 18, 0)
- localcandidates_.push_back({std::string() /*max-bundle*/, (uint16_t)mlineIndex, candidate});
- return;
-#else
- if (WebRTCSession::instance().state() >= State::OFFERSENT) {
- emit WebRTCSession::instance().newICECandidate(
- {std::string() /*max-bundle*/, (uint16_t)mlineIndex, candidate});
- return;
- }
-
localcandidates_.push_back({std::string() /*max-bundle*/, (uint16_t)mlineIndex, candidate});
-
- // GStreamer v1.16: webrtcbin's notify::ice-gathering-state triggers
- // GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE too early. Fixed in v1.18.
- // Use a 1s timeout in the meantime
- static guint timerid = 0;
- if (timerid)
- g_source_remove(timerid);
-
- timerid = g_timeout_add(1000, onICEGatheringCompletion, &timerid);
-#endif
}
void
@@ -320,7 +293,6 @@ testPacketLoss(gpointer G_GNUC_UNUSED)
return FALSE;
}
-#if GST_CHECK_VERSION(1, 18, 0)
void
setWaitForKeyFrame(GstBin *decodebin G_GNUC_UNUSED, GstElement *element, gpointer G_GNUC_UNUSED)
{
@@ -329,7 +301,6 @@ setWaitForKeyFrame(GstBin *decodebin G_GNUC_UNUSED, GstElement *element, gpointe
"rtpvp8depay"))
g_object_set(element, "wait-for-keyframe", TRUE, nullptr);
}
-#endif
GstElement *
newAudioSinkChain(GstElement *pipe)
@@ -357,6 +328,7 @@ newVideoSinkChain(GstElement *pipe)
GstElement *glcolorconvert = gst_element_factory_make("glcolorconvert", nullptr);
GstElement *qmlglsink = gst_element_factory_make("qmlglsink", nullptr);
GstElement *glsinkbin = gst_element_factory_make("glsinkbin", nullptr);
+ g_object_set(compositor, "background", 1, nullptr);
g_object_set(qmlglsink, "widget", WebRTCSession::instance().getVideoItem(), nullptr);
g_object_set(glsinkbin, "sink", qmlglsink, nullptr);
gst_bin_add_many(
@@ -382,45 +354,99 @@ getResolution(GstPad *pad)
return ret;
}
+std::pair<int, int>
+getResolution(GstElement *pipe, const gchar *elementName, const gchar *padName)
+{
+ GstElement *element = gst_bin_get_by_name(GST_BIN(pipe), elementName);
+ GstPad *pad = gst_element_get_static_pad(element, padName);
+ auto ret = getResolution(pad);
+ gst_object_unref(pad);
+ gst_object_unref(element);
+ return ret;
+}
+
+std::pair<int, int>
+getPiPDimensions(const std::pair<int, int> &resolution, int fullWidth, double scaleFactor)
+{
+ int pipWidth = fullWidth * scaleFactor;
+ int pipHeight = static_cast<double>(resolution.second) / resolution.first * pipWidth;
+ return {pipWidth, pipHeight};
+}
+
void
-addCameraView(GstElement *pipe, const std::pair<int, int> &videoCallSize)
+addLocalPiP(GstElement *pipe, const std::pair<int, int> &videoCallSize)
{
+ // embed localUser's camera into received video (CallType::VIDEO)
+ // OR embed screen share into received video (CallType::SCREEN)
GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe), "videosrctee");
if (!tee)
return;
- GstElement *queue = gst_element_factory_make("queue", nullptr);
- GstElement *videorate = gst_element_factory_make("videorate", nullptr);
- gst_bin_add_many(GST_BIN(pipe), queue, videorate, nullptr);
- gst_element_link_many(tee, queue, videorate, nullptr);
+ GstElement *queue = gst_element_factory_make("queue", nullptr);
+ gst_bin_add(GST_BIN(pipe), queue);
+ gst_element_link(tee, queue);
gst_element_sync_state_with_parent(queue);
- gst_element_sync_state_with_parent(videorate);
gst_object_unref(tee);
- GstElement *camerafilter = gst_bin_get_by_name(GST_BIN(pipe), "camerafilter");
- GstPad *filtersinkpad = gst_element_get_static_pad(camerafilter, "sink");
- auto cameraResolution = getResolution(filtersinkpad);
- int insetWidth = videoCallSize.first / 4;
- int insetHeight =
- static_cast<double>(cameraResolution.second) / cameraResolution.first * insetWidth;
- nhlog::ui()->debug("WebRTC: picture-in-picture size: {}x{}", insetWidth, insetHeight);
- gst_object_unref(filtersinkpad);
- gst_object_unref(camerafilter);
-
- GstPad *camerapad = gst_element_get_static_pad(videorate, "src");
GstElement *compositor = gst_bin_get_by_name(GST_BIN(pipe), "compositor");
- insetSinkPad_ = gst_element_get_request_pad(compositor, "sink_%u");
- g_object_set(insetSinkPad_, "zorder", 2, nullptr);
- g_object_set(insetSinkPad_, "width", insetWidth, "height", insetHeight, nullptr);
+ localPiPSinkPad_ = gst_element_get_request_pad(compositor, "sink_%u");
+ g_object_set(localPiPSinkPad_, "zorder", 2, nullptr);
+
+ bool isVideo = WebRTCSession::instance().callType() == CallType::VIDEO;
+ const gchar *element = isVideo ? "camerafilter" : "screenshare";
+ const gchar *pad = isVideo ? "sink" : "src";
+ auto resolution = getResolution(pipe, element, pad);
+ auto pipSize = getPiPDimensions(resolution, videoCallSize.first, 0.25);
+ nhlog::ui()->debug(
+ "WebRTC: local picture-in-picture: {}x{}", pipSize.first, pipSize.second);
+ g_object_set(localPiPSinkPad_, "width", pipSize.first, "height", pipSize.second, nullptr);
gint offset = videoCallSize.first / 80;
- g_object_set(insetSinkPad_, "xpos", offset, "ypos", offset, nullptr);
- if (GST_PAD_LINK_FAILED(gst_pad_link(camerapad, insetSinkPad_)))
- nhlog::ui()->error("WebRTC: failed to link camera view chain");
- gst_object_unref(camerapad);
+ g_object_set(localPiPSinkPad_, "xpos", offset, "ypos", offset, nullptr);
+
+ GstPad *srcpad = gst_element_get_static_pad(queue, "src");
+ if (GST_PAD_LINK_FAILED(gst_pad_link(srcpad, localPiPSinkPad_)))
+ nhlog::ui()->error("WebRTC: failed to link local PiP elements");
+ gst_object_unref(srcpad);
gst_object_unref(compositor);
}
void
+addRemotePiP(GstElement *pipe)
+{
+ // embed localUser's camera into screen image being shared
+ if (remotePiPSinkPad_) {
+ auto camRes = getResolution(pipe, "camerafilter", "sink");
+ auto shareRes = getResolution(pipe, "screenshare", "src");
+ auto pipSize = getPiPDimensions(camRes, shareRes.first, 0.2);
+ nhlog::ui()->debug(
+ "WebRTC: screen share picture-in-picture: {}x{}", pipSize.first, pipSize.second);
+
+ gint offset = shareRes.first / 100;
+ g_object_set(remotePiPSinkPad_, "zorder", 2, nullptr);
+ g_object_set(
+ remotePiPSinkPad_, "width", pipSize.first, "height", pipSize.second, nullptr);
+ g_object_set(remotePiPSinkPad_,
+ "xpos",
+ shareRes.first - pipSize.first - offset,
+ "ypos",
+ shareRes.second - pipSize.second - offset,
+ nullptr);
+ }
+}
+
+void
+addLocalVideo(GstElement *pipe)
+{
+ GstElement *queue = newVideoSinkChain(pipe);
+ GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe), "videosrctee");
+ GstPad *srcpad = gst_element_get_request_pad(tee, "src_%u");
+ GstPad *sinkpad = gst_element_get_static_pad(queue, "sink");
+ if (GST_PAD_LINK_FAILED(gst_pad_link(srcpad, sinkpad)))
+ nhlog::ui()->error("WebRTC: failed to link videosrctee -> video sink chain");
+ gst_object_unref(srcpad);
+}
+
+void
linkNewPad(GstElement *decodebin, GstPad *newpad, GstElement *pipe)
{
GstPad *sinkpad = gst_element_get_static_pad(decodebin, "sink");
@@ -455,7 +481,7 @@ linkNewPad(GstElement *decodebin, GstPad *newpad, GstElement *pipe)
nhlog::ui()->info("WebRTC: incoming video resolution: {}x{}",
videoCallSize.first,
videoCallSize.second);
- addCameraView(pipe, videoCallSize);
+ addLocalPiP(pipe, videoCallSize);
} else {
g_free(mediaType);
nhlog::ui()->error("WebRTC: unknown pad type: {}", GST_PAD_NAME(newpad));
@@ -467,7 +493,7 @@ linkNewPad(GstElement *decodebin, GstPad *newpad, GstElement *pipe)
if (GST_PAD_LINK_FAILED(gst_pad_link(newpad, queuepad)))
nhlog::ui()->error("WebRTC: unable to link new pad");
else {
- if (!session->isVideo() ||
+ if (session->callType() == CallType::VOICE ||
(haveAudioStream_ &&
(haveVideoStream_ || session->isRemoteVideoRecvOnly()))) {
emit session->stateChanged(State::CONNECTED);
@@ -477,6 +503,9 @@ linkNewPad(GstElement *decodebin, GstPad *newpad, GstElement *pipe)
keyFrameRequestData_.timerid =
g_timeout_add_seconds(3, testPacketLoss, nullptr);
}
+ addRemotePiP(pipe);
+ if (session->isRemoteVideoRecvOnly())
+ addLocalVideo(pipe);
}
}
gst_object_unref(queuepad);
@@ -495,9 +524,7 @@ addDecodeBin(GstElement *webrtc G_GNUC_UNUSED, GstPad *newpad, GstElement *pipe)
// hardware decoding needs investigation; eg rendering fails if vaapi plugin installed
g_object_set(decodebin, "force-sw-decoders", TRUE, nullptr);
g_signal_connect(decodebin, "pad-added", G_CALLBACK(linkNewPad), pipe);
-#if GST_CHECK_VERSION(1, 18, 0)
g_signal_connect(decodebin, "element-added", G_CALLBACK(setWaitForKeyFrame), nullptr);
-#endif
gst_bin_add(GST_BIN(pipe), decodebin);
gst_element_sync_state_with_parent(decodebin);
GstPad *sinkpad = gst_element_get_static_pad(decodebin, "sink");
@@ -523,14 +550,17 @@ getMediaAttributes(const GstSDPMessage *sdp,
const char *mediaType,
const char *encoding,
int &payloadType,
- bool &recvOnly)
+ bool &recvOnly,
+ bool &sendOnly)
{
payloadType = -1;
recvOnly = false;
+ sendOnly = false;
for (guint mlineIndex = 0; mlineIndex < gst_sdp_message_medias_len(sdp); ++mlineIndex) {
const GstSDPMedia *media = gst_sdp_message_get_media(sdp, mlineIndex);
if (!std::strcmp(gst_sdp_media_get_media(media), mediaType)) {
recvOnly = gst_sdp_media_get_attribute_val(media, "recvonly") != nullptr;
+ sendOnly = gst_sdp_media_get_attribute_val(media, "sendonly") != nullptr;
const gchar *rtpval = nullptr;
for (guint n = 0; n == 0 || rtpval; ++n) {
rtpval = gst_sdp_media_get_attribute_val_n(media, "rtpmap", n);
@@ -544,7 +574,6 @@ getMediaAttributes(const GstSDPMessage *sdp,
}
return false;
}
-
}
bool
@@ -603,17 +632,12 @@ WebRTCSession::havePlugins(bool isVideo, std::string *errorMessage)
}
bool
-WebRTCSession::createOffer(bool isVideo)
+WebRTCSession::createOffer(CallType callType, uint32_t shareWindowId)
{
- isOffering_ = true;
- isVideo_ = isVideo;
- isRemoteVideoRecvOnly_ = false;
- videoItem_ = nullptr;
- haveAudioStream_ = false;
- haveVideoStream_ = false;
- insetSinkPad_ = nullptr;
- localsdp_.clear();
- localcandidates_.clear();
+ clear();
+ isOffering_ = true;
+ callType_ = callType;
+ shareWindowId_ = shareWindowId;
// opus and vp8 rtp payload types must be defined dynamically
// therefore from the range [96-127]
@@ -630,22 +654,15 @@ WebRTCSession::acceptOffer(const std::string &sdp)
if (state_ != State::DISCONNECTED)
return false;
- isOffering_ = false;
- isRemoteVideoRecvOnly_ = false;
- videoItem_ = nullptr;
- haveAudioStream_ = false;
- haveVideoStream_ = false;
- insetSinkPad_ = nullptr;
- localsdp_.clear();
- localcandidates_.clear();
-
+ clear();
GstWebRTCSessionDescription *offer = parseSDP(sdp, GST_WEBRTC_SDP_TYPE_OFFER);
if (!offer)
return false;
int opusPayloadType;
bool recvOnly;
- if (getMediaAttributes(offer->sdp, "audio", "opus", opusPayloadType, recvOnly)) {
+ bool sendOnly;
+ if (getMediaAttributes(offer->sdp, "audio", "opus", opusPayloadType, recvOnly, sendOnly)) {
if (opusPayloadType == -1) {
nhlog::ui()->error("WebRTC: remote audio offer - no opus encoding");
gst_webrtc_session_description_free(offer);
@@ -658,13 +675,18 @@ WebRTCSession::acceptOffer(const std::string &sdp)
}
int vp8PayloadType;
- isVideo_ =
- getMediaAttributes(offer->sdp, "video", "vp8", vp8PayloadType, isRemoteVideoRecvOnly_);
- if (isVideo_ && vp8PayloadType == -1) {
+ bool isVideo = getMediaAttributes(offer->sdp,
+ "video",
+ "vp8",
+ vp8PayloadType,
+ isRemoteVideoRecvOnly_,
+ isRemoteVideoSendOnly_);
+ if (isVideo && vp8PayloadType == -1) {
nhlog::ui()->error("WebRTC: remote video offer - no vp8 encoding");
gst_webrtc_session_description_free(offer);
return false;
}
+ callType_ = isVideo ? CallType::VIDEO : CallType::VOICE;
if (!startPipeline(opusPayloadType, vp8PayloadType)) {
gst_webrtc_session_description_free(offer);
@@ -695,10 +717,14 @@ WebRTCSession::acceptAnswer(const std::string &sdp)
return false;
}
- if (isVideo_) {
+ if (callType_ != CallType::VOICE) {
int unused;
- if (!getMediaAttributes(
- answer->sdp, "video", "vp8", unused, isRemoteVideoRecvOnly_))
+ if (!getMediaAttributes(answer->sdp,
+ "video",
+ "vp8",
+ unused,
+ isRemoteVideoRecvOnly_,
+ isRemoteVideoSendOnly_))
isRemoteVideoRecvOnly_ = true;
}
@@ -769,11 +795,10 @@ WebRTCSession::startPipeline(int opusPayloadType, int vp8PayloadType)
gst_element_set_state(pipe_, GST_STATE_READY);
g_signal_connect(webrtc_, "pad-added", G_CALLBACK(addDecodeBin), pipe_);
-#if GST_CHECK_VERSION(1, 18, 0)
// capture ICE gathering completion
g_signal_connect(
webrtc_, "notify::ice-gathering-state", G_CALLBACK(iceGatheringStateChanged), nullptr);
-#endif
+
// webrtcbin lifetime is the same as that of the pipeline
gst_object_unref(webrtc_);
@@ -855,40 +880,115 @@ WebRTCSession::createPipeline(int opusPayloadType, int vp8PayloadType)
return false;
}
- return isVideo_ ? addVideoPipeline(vp8PayloadType) : true;
+ return callType_ == CallType::VOICE || isRemoteVideoSendOnly_
+ ? true
+ : addVideoPipeline(vp8PayloadType);
}
bool
WebRTCSession::addVideoPipeline(int vp8PayloadType)
{
// allow incoming video calls despite localUser having no webcam
- if (!devices_.haveCamera())
+ if (callType_ == CallType::VIDEO && !devices_.haveCamera())
return !isOffering_;
- std::pair<int, int> resolution;
- std::pair<int, int> frameRate;
- GstDevice *device = devices_.videoDevice(resolution, frameRate);
- if (!device)
- return false;
-
- GstElement *source = gst_device_create_element(device, nullptr);
+ auto settings = ChatPage::instance()->userSettings();
+ GstElement *camerafilter = nullptr;
GstElement *videoconvert = gst_element_factory_make("videoconvert", nullptr);
- GstElement *capsfilter = gst_element_factory_make("capsfilter", "camerafilter");
- GstCaps *caps = gst_caps_new_simple("video/x-raw",
- "width",
- G_TYPE_INT,
- resolution.first,
- "height",
- G_TYPE_INT,
- resolution.second,
- "framerate",
- GST_TYPE_FRACTION,
- frameRate.first,
- frameRate.second,
- nullptr);
- g_object_set(capsfilter, "caps", caps, nullptr);
- gst_caps_unref(caps);
- GstElement *tee = gst_element_factory_make("tee", "videosrctee");
+ GstElement *tee = gst_element_factory_make("tee", "videosrctee");
+ gst_bin_add_many(GST_BIN(pipe_), videoconvert, tee, nullptr);
+ if (callType_ == CallType::VIDEO || (settings->screenSharePiP() && devices_.haveCamera())) {
+ std::pair<int, int> resolution;
+ std::pair<int, int> frameRate;
+ GstDevice *device = devices_.videoDevice(resolution, frameRate);
+ if (!device)
+ return false;
+
+ GstElement *camera = gst_device_create_element(device, nullptr);
+ GstCaps *caps = gst_caps_new_simple("video/x-raw",
+ "width",
+ G_TYPE_INT,
+ resolution.first,
+ "height",
+ G_TYPE_INT,
+ resolution.second,
+ "framerate",
+ GST_TYPE_FRACTION,
+ frameRate.first,
+ frameRate.second,
+ nullptr);
+ camerafilter = gst_element_factory_make("capsfilter", "camerafilter");
+ g_object_set(camerafilter, "caps", caps, nullptr);
+ gst_caps_unref(caps);
+
+ gst_bin_add_many(GST_BIN(pipe_), camera, camerafilter, nullptr);
+ if (!gst_element_link_many(camera, videoconvert, camerafilter, nullptr)) {
+ nhlog::ui()->error("WebRTC: failed to link camera elements");
+ return false;
+ }
+ if (callType_ == CallType::VIDEO && !gst_element_link(camerafilter, tee)) {
+ nhlog::ui()->error("WebRTC: failed to link camerafilter -> tee");
+ return false;
+ }
+ }
+
+ if (callType_ == CallType::SCREEN) {
+ nhlog::ui()->debug("WebRTC: screen share frame rate: {} fps",
+ settings->screenShareFrameRate());
+ nhlog::ui()->debug("WebRTC: screen share picture-in-picture: {}",
+ settings->screenSharePiP());
+ nhlog::ui()->debug("WebRTC: screen share request remote camera: {}",
+ settings->screenShareRemoteVideo());
+ nhlog::ui()->debug("WebRTC: screen share hide mouse cursor: {}",
+ settings->screenShareHideCursor());
+
+ GstElement *ximagesrc = gst_element_factory_make("ximagesrc", "screenshare");
+ if (!ximagesrc) {
+ nhlog::ui()->error("WebRTC: failed to create ximagesrc");
+ return false;
+ }
+ g_object_set(ximagesrc, "use-damage", FALSE, nullptr);
+ g_object_set(ximagesrc, "xid", shareWindowId_, nullptr);
+ g_object_set(
+ ximagesrc, "show-pointer", !settings->screenShareHideCursor(), nullptr);
+
+ GstCaps *caps = gst_caps_new_simple("video/x-raw",
+ "framerate",
+ GST_TYPE_FRACTION,
+ settings->screenShareFrameRate(),
+ 1,
+ nullptr);
+ GstElement *capsfilter = gst_element_factory_make("capsfilter", nullptr);
+ g_object_set(capsfilter, "caps", caps, nullptr);
+ gst_caps_unref(caps);
+ gst_bin_add_many(GST_BIN(pipe_), ximagesrc, capsfilter, nullptr);
+
+ if (settings->screenSharePiP() && devices_.haveCamera()) {
+ GstElement *compositor = gst_element_factory_make("compositor", nullptr);
+ g_object_set(compositor, "background", 1, nullptr);
+ gst_bin_add(GST_BIN(pipe_), compositor);
+ if (!gst_element_link_many(
+ ximagesrc, compositor, capsfilter, tee, nullptr)) {
+ nhlog::ui()->error("WebRTC: failed to link screen share elements");
+ return false;
+ }
+
+ GstPad *srcpad = gst_element_get_static_pad(camerafilter, "src");
+ remotePiPSinkPad_ = gst_element_get_request_pad(compositor, "sink_%u");
+ if (GST_PAD_LINK_FAILED(gst_pad_link(srcpad, remotePiPSinkPad_))) {
+ nhlog::ui()->error(
+ "WebRTC: failed to link camerafilter -> compositor");
+ gst_object_unref(srcpad);
+ return false;
+ }
+ gst_object_unref(srcpad);
+ } else if (!gst_element_link_many(
+ ximagesrc, videoconvert, capsfilter, tee, nullptr)) {
+ nhlog::ui()->error("WebRTC: failed to link screen share elements");
+ return false;
+ }
+ }
+
GstElement *queue = gst_element_factory_make("queue", nullptr);
GstElement *vp8enc = gst_element_factory_make("vp8enc", nullptr);
g_object_set(vp8enc, "deadline", 1, nullptr);
@@ -910,46 +1010,45 @@ WebRTCSession::addVideoPipeline(int vp8PayloadType)
g_object_set(rtpcapsfilter, "caps", rtpcaps, nullptr);
gst_caps_unref(rtpcaps);
- gst_bin_add_many(GST_BIN(pipe_),
- source,
- videoconvert,
- capsfilter,
- tee,
- queue,
- vp8enc,
- rtpvp8pay,
- rtpqueue,
- rtpcapsfilter,
- nullptr);
+ gst_bin_add_many(
+ GST_BIN(pipe_), queue, vp8enc, rtpvp8pay, rtpqueue, rtpcapsfilter, nullptr);
GstElement *webrtcbin = gst_bin_get_by_name(GST_BIN(pipe_), "webrtcbin");
- if (!gst_element_link_many(source,
- videoconvert,
- capsfilter,
- tee,
- queue,
- vp8enc,
- rtpvp8pay,
- rtpqueue,
- rtpcapsfilter,
- webrtcbin,
- nullptr)) {
- nhlog::ui()->error("WebRTC: failed to link video pipeline elements");
+ if (!gst_element_link_many(
+ tee, queue, vp8enc, rtpvp8pay, rtpqueue, rtpcapsfilter, webrtcbin, nullptr)) {
+ nhlog::ui()->error("WebRTC: failed to link rtp video elements");
gst_object_unref(webrtcbin);
return false;
}
+
+ if (callType_ == CallType::SCREEN &&
+ !ChatPage::instance()->userSettings()->screenShareRemoteVideo()) {
+ GArray *transceivers;
+ g_signal_emit_by_name(webrtcbin, "get-transceivers", &transceivers);
+ GstWebRTCRTPTransceiver *transceiver =
+ g_array_index(transceivers, GstWebRTCRTPTransceiver *, 1);
+ transceiver->direction = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
+ g_array_unref(transceivers);
+ }
+
gst_object_unref(webrtcbin);
return true;
}
bool
-WebRTCSession::haveLocalVideo() const
+WebRTCSession::haveLocalPiP() const
{
- if (isVideo_ && state_ >= State::INITIATED) {
- GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe_), "videosrctee");
- if (tee) {
- gst_object_unref(tee);
+ if (state_ >= State::INITIATED) {
+ if (callType_ == CallType::VOICE || isRemoteVideoRecvOnly_)
+ return false;
+ else if (callType_ == CallType::SCREEN)
return true;
+ else {
+ GstElement *tee = gst_bin_get_by_name(GST_BIN(pipe_), "videosrctee");
+ if (tee) {
+ gst_object_unref(tee);
+ return true;
+ }
}
}
return false;
@@ -983,16 +1082,36 @@ WebRTCSession::toggleMicMute()
}
void
-WebRTCSession::toggleCameraView()
+WebRTCSession::toggleLocalPiP()
{
- if (insetSinkPad_) {
+ if (localPiPSinkPad_) {
guint zorder;
- g_object_get(insetSinkPad_, "zorder", &zorder, nullptr);
- g_object_set(insetSinkPad_, "zorder", zorder ? 0 : 2, nullptr);
+ g_object_get(localPiPSinkPad_, "zorder", &zorder, nullptr);
+ g_object_set(localPiPSinkPad_, "zorder", zorder ? 0 : 2, nullptr);
}
}
void
+WebRTCSession::clear()
+{
+ callType_ = webrtc::CallType::VOICE;
+ isOffering_ = false;
+ isRemoteVideoRecvOnly_ = false;
+ isRemoteVideoSendOnly_ = false;
+ videoItem_ = nullptr;
+ pipe_ = nullptr;
+ webrtc_ = nullptr;
+ busWatchId_ = 0;
+ shareWindowId_ = 0;
+ haveAudioStream_ = false;
+ haveVideoStream_ = false;
+ localPiPSinkPad_ = nullptr;
+ remotePiPSinkPad_ = nullptr;
+ localsdp_.clear();
+ localcandidates_.clear();
+}
+
+void
WebRTCSession::end()
{
nhlog::ui()->debug("WebRTC: ending session");
@@ -1007,12 +1126,7 @@ WebRTCSession::end()
}
}
- webrtc_ = nullptr;
- isVideo_ = false;
- isOffering_ = false;
- isRemoteVideoRecvOnly_ = false;
- videoItem_ = nullptr;
- insetSinkPad_ = nullptr;
+ clear();
if (state_ != State::DISCONNECTED)
emit stateChanged(State::DISCONNECTED);
}
@@ -1026,16 +1140,12 @@ WebRTCSession::havePlugins(bool, std::string *)
}
bool
-WebRTCSession::haveLocalVideo() const
+WebRTCSession::haveLocalPiP() const
{
return false;
}
-bool
-WebRTCSession::createOffer(bool)
-{
- return false;
-}
+bool WebRTCSession::createOffer(webrtc::CallType, uint32_t) { return false; }
bool
WebRTCSession::acceptOffer(const std::string &)
@@ -1066,7 +1176,7 @@ WebRTCSession::toggleMicMute()
}
void
-WebRTCSession::toggleCameraView()
+WebRTCSession::toggleLocalPiP()
{}
void
diff --git a/src/WebRTCSession.h b/src/WebRTCSession.h
index 0fe8a864..97487c5c 100644
--- a/src/WebRTCSession.h
+++ b/src/WebRTCSession.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <string>
@@ -5,15 +9,23 @@
#include <QObject>
-#include "CallDevices.h"
#include "mtx/events/voip.hpp"
typedef struct _GstElement GstElement;
+class CallDevices;
class QQuickItem;
namespace webrtc {
Q_NAMESPACE
+enum class CallType
+{
+ VOICE,
+ VIDEO,
+ SCREEN // localUser is sharing screen
+};
+Q_ENUM_NS(CallType)
+
enum class State
{
DISCONNECTED,
@@ -27,7 +39,6 @@ enum class State
};
Q_ENUM_NS(State)
-
}
class WebRTCSession : public QObject
@@ -42,20 +53,21 @@ public:
}
bool havePlugins(bool isVideo, std::string *errorMessage = nullptr);
+ webrtc::CallType callType() const { return callType_; }
webrtc::State state() const { return state_; }
- bool isVideo() const { return isVideo_; }
- bool haveLocalVideo() const;
+ bool haveLocalPiP() const;
bool isOffering() const { return isOffering_; }
bool isRemoteVideoRecvOnly() const { return isRemoteVideoRecvOnly_; }
+ bool isRemoteVideoSendOnly() const { return isRemoteVideoSendOnly_; }
- bool createOffer(bool isVideo);
+ bool createOffer(webrtc::CallType, uint32_t shareWindowId);
bool acceptOffer(const std::string &sdp);
bool acceptAnswer(const std::string &sdp);
void acceptICECandidates(const std::vector<mtx::events::msg::CallCandidates::Candidate> &);
bool isMicMuted() const;
bool toggleMicMute();
- void toggleCameraView();
+ void toggleLocalPiP();
void end();
void setTurnServers(const std::vector<std::string> &uris) { turnServers_ = uris; }
@@ -81,20 +93,23 @@ private:
bool initialised_ = false;
bool haveVoicePlugins_ = false;
bool haveVideoPlugins_ = false;
+ webrtc::CallType callType_ = webrtc::CallType::VOICE;
webrtc::State state_ = webrtc::State::DISCONNECTED;
- bool isVideo_ = false;
bool isOffering_ = false;
bool isRemoteVideoRecvOnly_ = false;
+ bool isRemoteVideoSendOnly_ = false;
QQuickItem *videoItem_ = nullptr;
GstElement *pipe_ = nullptr;
GstElement *webrtc_ = nullptr;
unsigned int busWatchId_ = 0;
std::vector<std::string> turnServers_;
+ uint32_t shareWindowId_ = 0;
bool init(std::string *errorMessage = nullptr);
bool startPipeline(int opusPayloadType, int vp8PayloadType);
bool createPipeline(int opusPayloadType, int vp8PayloadType);
bool addVideoPipeline(int vp8PayloadType);
+ void clear();
public:
WebRTCSession(WebRTCSession const &) = delete;
diff --git a/src/WelcomePage.cpp b/src/WelcomePage.cpp
index 22b73ac7..2cce7b8d 100644
--- a/src/WelcomePage.cpp
+++ b/src/WelcomePage.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QLabel>
#include <QLayout>
diff --git a/src/WelcomePage.h b/src/WelcomePage.h
index ae660215..d2dcc0c9 100644
--- a/src/WelcomePage.h
+++ b/src/WelcomePage.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QWidget>
diff --git a/src/dialogs/CreateRoom.cpp b/src/dialogs/CreateRoom.cpp
index fed46e02..ba385436 100644
--- a/src/dialogs/CreateRoom.cpp
+++ b/src/dialogs/CreateRoom.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
diff --git a/src/dialogs/CreateRoom.h b/src/dialogs/CreateRoom.h
index a482a636..d4c6474d 100644
--- a/src/dialogs/CreateRoom.h
+++ b/src/dialogs/CreateRoom.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFrame>
diff --git a/src/dialogs/FallbackAuth.cpp b/src/dialogs/FallbackAuth.cpp
index a0633c1e..c7b179f4 100644
--- a/src/dialogs/FallbackAuth.cpp
+++ b/src/dialogs/FallbackAuth.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QDesktopServices>
#include <QLabel>
#include <QPushButton>
diff --git a/src/dialogs/FallbackAuth.h b/src/dialogs/FallbackAuth.h
index 245fa03e..8e4e28ea 100644
--- a/src/dialogs/FallbackAuth.h
+++ b/src/dialogs/FallbackAuth.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QWidget>
diff --git a/src/dialogs/ImageOverlay.cpp b/src/dialogs/ImageOverlay.cpp
index e075fb67..f38b29f5 100644
--- a/src/dialogs/ImageOverlay.cpp
+++ b/src/dialogs/ImageOverlay.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QApplication>
#include <QDesktopWidget>
diff --git a/src/dialogs/ImageOverlay.h b/src/dialogs/ImageOverlay.h
index bf566ce4..93b6afdc 100644
--- a/src/dialogs/ImageOverlay.h
+++ b/src/dialogs/ImageOverlay.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/dialogs/InviteUsers.cpp b/src/dialogs/InviteUsers.cpp
index 8f1097fa..9dd6085f 100644
--- a/src/dialogs/InviteUsers.cpp
+++ b/src/dialogs/InviteUsers.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QDebug>
#include <QIcon>
#include <QLabel>
diff --git a/src/dialogs/InviteUsers.h b/src/dialogs/InviteUsers.h
index 684f60b4..e40183c1 100644
--- a/src/dialogs/InviteUsers.h
+++ b/src/dialogs/InviteUsers.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFrame>
diff --git a/src/dialogs/JoinRoom.cpp b/src/dialogs/JoinRoom.cpp
index b5c26e69..dc2e4804 100644
--- a/src/dialogs/JoinRoom.cpp
+++ b/src/dialogs/JoinRoom.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
diff --git a/src/dialogs/JoinRoom.h b/src/dialogs/JoinRoom.h
index 257cb950..f399f1fb 100644
--- a/src/dialogs/JoinRoom.h
+++ b/src/dialogs/JoinRoom.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFrame>
diff --git a/src/dialogs/LeaveRoom.cpp b/src/dialogs/LeaveRoom.cpp
index e3aea439..5246d693 100644
--- a/src/dialogs/LeaveRoom.cpp
+++ b/src/dialogs/LeaveRoom.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
diff --git a/src/dialogs/LeaveRoom.h b/src/dialogs/LeaveRoom.h
index a35cf04d..e9465579 100644
--- a/src/dialogs/LeaveRoom.h
+++ b/src/dialogs/LeaveRoom.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFrame>
diff --git a/src/dialogs/Logout.cpp b/src/dialogs/Logout.cpp
index 7c44b23c..fdfc3338 100644
--- a/src/dialogs/Logout.cpp
+++ b/src/dialogs/Logout.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QLabel>
#include <QPushButton>
diff --git a/src/dialogs/Logout.h b/src/dialogs/Logout.h
index b7e962eb..9d8d0f4b 100644
--- a/src/dialogs/Logout.h
+++ b/src/dialogs/Logout.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/dialogs/MemberList.cpp b/src/dialogs/MemberList.cpp
index 54e7bf96..21eb72b0 100644
--- a/src/dialogs/MemberList.cpp
+++ b/src/dialogs/MemberList.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QAbstractSlider>
#include <QLabel>
#include <QListWidgetItem>
diff --git a/src/dialogs/MemberList.h b/src/dialogs/MemberList.h
index c01b6829..b822eec8 100644
--- a/src/dialogs/MemberList.h
+++ b/src/dialogs/MemberList.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFrame>
diff --git a/src/dialogs/PreviewUploadOverlay.cpp b/src/dialogs/PreviewUploadOverlay.cpp
index bd207642..55421a7d 100644
--- a/src/dialogs/PreviewUploadOverlay.cpp
+++ b/src/dialogs/PreviewUploadOverlay.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QBuffer>
#include <QFile>
diff --git a/src/dialogs/PreviewUploadOverlay.h b/src/dialogs/PreviewUploadOverlay.h
index 5139e3f2..7493f67c 100644
--- a/src/dialogs/PreviewUploadOverlay.h
+++ b/src/dialogs/PreviewUploadOverlay.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/dialogs/RawMessage.h b/src/dialogs/RawMessage.h
index c69fad60..e95f675c 100644
--- a/src/dialogs/RawMessage.h
+++ b/src/dialogs/RawMessage.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFont>
diff --git a/src/dialogs/ReCaptcha.cpp b/src/dialogs/ReCaptcha.cpp
index 21dc8c77..c7b95f1a 100644
--- a/src/dialogs/ReCaptcha.cpp
+++ b/src/dialogs/ReCaptcha.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QDesktopServices>
#include <QLabel>
#include <QPushButton>
diff --git a/src/dialogs/ReCaptcha.h b/src/dialogs/ReCaptcha.h
index 88ff3722..0c9f7539 100644
--- a/src/dialogs/ReCaptcha.h
+++ b/src/dialogs/ReCaptcha.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QWidget>
diff --git a/src/dialogs/ReadReceipts.cpp b/src/dialogs/ReadReceipts.cpp
index 7dcffc28..fa7132fd 100644
--- a/src/dialogs/ReadReceipts.cpp
+++ b/src/dialogs/ReadReceipts.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QDebug>
#include <QIcon>
#include <QLabel>
diff --git a/src/dialogs/ReadReceipts.h b/src/dialogs/ReadReceipts.h
index 2e7a0217..5c6c5d2b 100644
--- a/src/dialogs/ReadReceipts.h
+++ b/src/dialogs/ReadReceipts.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QDateTime>
diff --git a/src/emoji/EmojiModel.cpp b/src/emoji/EmojiModel.cpp
index f207c740..70b85934 100644
--- a/src/emoji/EmojiModel.cpp
+++ b/src/emoji/EmojiModel.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "EmojiModel.h"
#include <Cache.h>
diff --git a/src/emoji/EmojiModel.h b/src/emoji/EmojiModel.h
index 938db46d..1a8bf029 100644
--- a/src/emoji/EmojiModel.h
+++ b/src/emoji/EmojiModel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAbstractListModel>
diff --git a/src/emoji/EmojiSearchModel.h b/src/emoji/EmojiSearchModel.h
index 7dbe6732..64af83dd 100644
--- a/src/emoji/EmojiSearchModel.h
+++ b/src/emoji/EmojiSearchModel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include "EmojiModel.h"
diff --git a/src/emoji/MacHelper.h b/src/emoji/MacHelper.h
index a2e94158..b3e2e631 100644
--- a/src/emoji/MacHelper.h
+++ b/src/emoji/MacHelper.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QMenuBar>
diff --git a/src/emoji/Provider.cpp b/src/emoji/Provider.cpp
index b780542c..70ac474e 100644
--- a/src/emoji/Provider.cpp
+++ b/src/emoji/Provider.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "emoji/Provider.h"
using namespace emoji;
diff --git a/src/emoji/Provider.h b/src/emoji/Provider.h
index 068162f4..43c880a2 100644
--- a/src/emoji/Provider.h
+++ b/src/emoji/Provider.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/main.cpp b/src/main.cpp
index 0c7c9f60..fe1a9ee3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <iostream>
diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h
index 950740ba..e2b3236a 100644
--- a/src/notifications/Manager.h
+++ b/src/notifications/Manager.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QImage>
diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp
index fb424b2a..a222bd36 100644
--- a/src/notifications/ManagerLinux.cpp
+++ b/src/notifications/ManagerLinux.cpp
@@ -44,12 +44,11 @@ NotificationsManager::NotificationsManager(QObject *parent)
SLOT(notificationReplied(uint, QString)));
}
-/**
- * This function is based on code from
- * https://github.com/rohieb/StratumsphereTrayIcon
- * Copyright (C) 2012 Roland Hieber <rohieb@rohieb.name>
- * Licensed under the GNU General Public License, version 3
- */
+// SPDX-FileCopyrightText: 2012 Roland Hieber <rohieb@rohieb.name>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
void
NotificationsManager::postNotification(const mtx::responses::Notification ¬ification,
const QImage &icon)
@@ -109,7 +108,7 @@ NotificationsManager::closeNotification(uint id)
"org.freedesktop.Notifications");
auto call = closeCall.asyncCall("CloseNotification", (uint)id); // replace_id
auto watcher = new QDBusPendingCallWatcher{call, this};
- connect(watcher, &QDBusPendingCallWatcher::finished, this, [watcher, this]() {
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, [watcher]() {
if (watcher->reply().type() == QDBusMessage::ErrorMessage) {
qDebug() << "D-Bus Error:" << watcher->reply().errorMessage();
};
@@ -174,7 +173,7 @@ NotificationsManager::notificationClosed(uint id, uint reason)
* http://www.clementine-player.org) and licensed under the GNU General Public
* License, version 3 or later.
*
- * Copyright 2010, David Sansome <me@davidsansome.com>
+ * SPDX-FileCopyrightText: 2010 David Sansome <me@davidsansome.com>
*/
QDBusArgument &
operator<<(QDBusArgument &arg, const QImage &image)
diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp
index 85abe642..3152d84f 100644
--- a/src/notifications/ManagerWin.cpp
+++ b/src/notifications/ManagerWin.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "notifications/Manager.h"
#include "wintoastlib.h"
diff --git a/src/popups/PopupItem.cpp b/src/popups/PopupItem.cpp
index 37fe142a..2daa6143 100644
--- a/src/popups/PopupItem.cpp
+++ b/src/popups/PopupItem.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QLabel>
#include <QPaintEvent>
#include <QPainter>
diff --git a/src/popups/PopupItem.h b/src/popups/PopupItem.h
index 499d6b33..fc24915e 100644
--- a/src/popups/PopupItem.h
+++ b/src/popups/PopupItem.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QWidget>
diff --git a/src/popups/SuggestionsPopup.cpp b/src/popups/SuggestionsPopup.cpp
index 8add4313..7b545d61 100644
--- a/src/popups/SuggestionsPopup.cpp
+++ b/src/popups/SuggestionsPopup.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QPaintEvent>
#include <QPainter>
#include <QStyleOption>
diff --git a/src/popups/SuggestionsPopup.h b/src/popups/SuggestionsPopup.h
index 6a0157a1..281edddb 100644
--- a/src/popups/SuggestionsPopup.h
+++ b/src/popups/SuggestionsPopup.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QWidget>
diff --git a/src/popups/UserMentions.cpp b/src/popups/UserMentions.cpp
index 23a679f1..56b57503 100644
--- a/src/popups/UserMentions.cpp
+++ b/src/popups/UserMentions.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QPaintEvent>
#include <QPainter>
#include <QScrollArea>
diff --git a/src/popups/UserMentions.h b/src/popups/UserMentions.h
index 885fe67d..f0b662d8 100644
--- a/src/popups/UserMentions.h
+++ b/src/popups/UserMentions.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <mtx/responses/notifications.hpp>
diff --git a/src/timeline/DelegateChooser.cpp b/src/timeline/DelegateChooser.cpp
index 8598fa77..39c8fa17 100644
--- a/src/timeline/DelegateChooser.cpp
+++ b/src/timeline/DelegateChooser.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "DelegateChooser.h"
#include "Logging.h"
diff --git a/src/timeline/DelegateChooser.h b/src/timeline/DelegateChooser.h
index 2524b068..22e423a2 100644
--- a/src/timeline/DelegateChooser.h
+++ b/src/timeline/DelegateChooser.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// A DelegateChooser like the one, that was added to Qt5.12 (in labs), but compatible with older Qt
// versions see KDE/kquickitemviews see qtdeclarative/qqmldelagatecomponent
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 94d43a83..6104ad00 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "EventStore.h"
#include <QThread>
diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h
index ced7bdc0..a10c2126 100644
--- a/src/timeline/EventStore.h
+++ b/src/timeline/EventStore.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <limits>
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index ab0fc3d7..d5a6a1dd 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "InputBar.h"
#include <QClipboard>
@@ -123,6 +127,20 @@ InputBar::insertMimeData(const QMimeData *md)
}
void
+InputBar::setText(QString newText)
+{
+ if (history_.empty())
+ history_.push_front(newText);
+ else
+ history_.front() = newText;
+ history_index_ = 0;
+
+ if (history_.size() == INPUT_HISTORY_SIZE)
+ history_.pop_back();
+
+ emit textChanged(newText);
+}
+void
InputBar::updateState(int selectionStart_, int selectionEnd_, int cursorPosition_, QString text_)
{
if (text_.isEmpty())
@@ -180,6 +198,10 @@ InputBar::send()
if (text().trimmed().isEmpty())
return;
+ nhlog::ui()->debug("Send: {}", text().toStdString());
+
+ auto wasEdit = !room->edit().isEmpty();
+
if (text().startsWith('/')) {
int command_end = text().indexOf(' ');
if (command_end == -1)
@@ -195,12 +217,10 @@ InputBar::send()
message(text());
}
- nhlog::ui()->debug("Send: {}", text().toStdString());
-
- if (history_.size() == INPUT_HISTORY_SIZE)
- history_.pop_back();
- history_.push_front("");
- history_index_ = 0;
+ if (!wasEdit) {
+ history_.push_front("");
+ setText("");
+ }
}
void
@@ -256,12 +276,10 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown)
if (!room->reply().isEmpty()) {
text.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
text.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
} else if (!room->reply().isEmpty()) {
auto related = room->relatedInfo(room->reply());
@@ -291,7 +309,6 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown)
text.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, related.related_event});
- room->resetReply();
}
room->sendMessageEvent(text, mtx::events::EventType::RoomMessage);
@@ -314,12 +331,10 @@ InputBar::emote(QString msg)
if (!room->reply().isEmpty()) {
emote.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
emote.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(emote, mtx::events::EventType::RoomMessage);
@@ -350,12 +365,10 @@ InputBar::image(const QString &filename,
if (!room->reply().isEmpty()) {
image.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
image.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(image, mtx::events::EventType::RoomMessage);
@@ -381,12 +394,10 @@ InputBar::file(const QString &filename,
if (!room->reply().isEmpty()) {
file.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
file.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(file, mtx::events::EventType::RoomMessage);
@@ -413,12 +424,10 @@ InputBar::audio(const QString &filename,
if (!room->reply().isEmpty()) {
audio.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
audio.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(audio, mtx::events::EventType::RoomMessage);
@@ -444,12 +453,10 @@ InputBar::video(const QString &filename,
if (!room->reply().isEmpty()) {
video.relations.relations.push_back(
{mtx::common::RelationType::InReplyTo, room->reply().toStdString()});
- room->resetReply();
}
if (!room->edit().isEmpty()) {
video.relations.relations.push_back(
{mtx::common::RelationType::Replace, room->edit().toStdString()});
- room->resetEdit();
}
room->sendMessageEvent(video, mtx::events::EventType::RoomMessage);
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index 678d953d..acd9e22c 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QObject>
@@ -41,7 +45,7 @@ public slots:
QString text() const;
QString previousText();
QString nextText();
- void setText(QString newText) { emit textChanged(newText); }
+ void setText(QString newText);
void send();
void paste(bool fromMouse);
diff --git a/src/timeline/Reaction.cpp b/src/timeline/Reaction.cpp
index 343c4649..963e04d6 100644
--- a/src/timeline/Reaction.cpp
+++ b/src/timeline/Reaction.cpp
@@ -1 +1,5 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "Reaction.h"
diff --git a/src/timeline/Reaction.h b/src/timeline/Reaction.h
index 5f122e0a..47dac617 100644
--- a/src/timeline/Reaction.h
+++ b/src/timeline/Reaction.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QObject>
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index af4c6aa2..ddec7287 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "TimelineModel.h"
#include <algorithm>
@@ -499,6 +503,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
data(event, static_cast<int>(ProportionalHeight)));
m.insert(names[Id], data(event, static_cast<int>(Id)));
m.insert(names[State], data(event, static_cast<int>(State)));
+ m.insert(names[IsEdited], data(event, static_cast<int>(IsEdited)));
+ m.insert(names[IsEditable], data(event, static_cast<int>(IsEditable)));
m.insert(names[IsEncrypted], data(event, static_cast<int>(IsEncrypted)));
m.insert(names[IsRoomEncrypted], data(event, static_cast<int>(IsRoomEncrypted)));
m.insert(names[ReplyTo], data(event, static_cast<int>(ReplyTo)));
@@ -865,7 +871,7 @@ TimelineModel::relatedInfo(QString id)
RelatedInfo related = {};
related.quoted_user = QString::fromStdString(mtx::accessors::sender(*event));
- related.related_event = mtx::accessors::event_id(*event);
+ related.related_event = id.toStdString();
related.type = mtx::accessors::msg_type(*event);
// get body, strip reply fallback, then transform the event to text, if it is a media event
@@ -877,11 +883,13 @@ TimelineModel::relatedInfo(QString id)
if (related.quoted_body.startsWith("\n"))
related.quoted_body.remove(0, 1);
related.quoted_body = utils::getQuoteBody(related);
+ related.quoted_body.replace("@room", QString::fromUtf8("@\u2060room"));
// get quoted body and strip reply fallback
related.quoted_formatted_body = mtx::accessors::formattedBodyWithFallback(*event);
related.quoted_formatted_body.remove(QRegularExpression(
"<mx-reply>.*</mx-reply>", QRegularExpression::DotMatchesEverythingOption));
+ related.quoted_formatted_body.replace("@room", "@\u2060aroom");
related.room = room_id_;
return related;
@@ -1550,6 +1558,17 @@ TimelineModel::setEdit(QString newEdit)
if (edit_.startsWith('m'))
return;
+ if (newEdit.isEmpty()) {
+ resetEdit();
+ return;
+ }
+
+ if (edit_.isEmpty()) {
+ this->textBeforeEdit = input()->text();
+ this->replyBeforeEdit = reply_;
+ nhlog::ui()->debug("Stored: {}", textBeforeEdit.toStdString());
+ }
+
if (edit_ != newEdit) {
auto ev = events.get(newEdit.toStdString(), "");
if (ev && mtx::accessors::sender(*ev) == http::client()->user_id().to_string()) {
@@ -1584,8 +1603,14 @@ TimelineModel::resetEdit()
if (!edit_.isEmpty()) {
edit_ = "";
emit editChanged(edit_);
- input()->setText("");
- resetReply();
+ nhlog::ui()->debug("Restoring: {}", textBeforeEdit.toStdString());
+ input()->setText(textBeforeEdit);
+ textBeforeEdit.clear();
+ if (replyBeforeEdit.isEmpty())
+ resetReply();
+ else
+ setReply(replyBeforeEdit);
+ replyBeforeEdit.clear();
}
}
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 5f599741..06da95c6 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAbstractListModel>
@@ -337,6 +341,7 @@ private:
QString currentId, currentReadId;
QString reply_, edit_;
+ QString textBeforeEdit, replyBeforeEdit;
std::vector<QString> typingUsers_;
TimelineViewManager *manager_;
@@ -354,4 +359,6 @@ TimelineModel::sendMessageEvent(const T &content, mtx::events::EventType eventTy
msgCopy.content = content;
msgCopy.type = eventType;
emit newMessageToSend(msgCopy);
+ resetReply();
+ resetEdit();
}
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 04af7060..3ed1c21c 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "TimelineViewManager.h"
#include <QDesktopServices>
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index f1c360ef..e3ed4991 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QHash>
diff --git a/src/ui/Avatar.cpp b/src/ui/Avatar.cpp
index 0d1bb924..53e72618 100644
--- a/src/ui/Avatar.cpp
+++ b/src/ui/Avatar.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QPainter>
#include <QPainterPath>
#include <QSettings>
diff --git a/src/ui/Avatar.h b/src/ui/Avatar.h
index 229a980d..bbf05be3 100644
--- a/src/ui/Avatar.h
+++ b/src/ui/Avatar.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QImage>
diff --git a/src/ui/Badge.cpp b/src/ui/Badge.cpp
index 6701f9b7..66210d06 100644
--- a/src/ui/Badge.cpp
+++ b/src/ui/Badge.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QPainter>
#include "Badge.h"
diff --git a/src/ui/Badge.h b/src/ui/Badge.h
index 748b56fd..98e16873 100644
--- a/src/ui/Badge.h
+++ b/src/ui/Badge.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QColor>
diff --git a/src/ui/DropShadow.cpp b/src/ui/DropShadow.cpp
index d437975c..a413e3f7 100644
--- a/src/ui/DropShadow.cpp
+++ b/src/ui/DropShadow.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "DropShadow.h"
#include <QLinearGradient>
diff --git a/src/ui/DropShadow.h b/src/ui/DropShadow.h
index 6997e1a0..4ace4731 100644
--- a/src/ui/DropShadow.h
+++ b/src/ui/DropShadow.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QColor>
diff --git a/src/ui/FlatButton.cpp b/src/ui/FlatButton.cpp
index 6660c58d..c036401b 100644
--- a/src/ui/FlatButton.cpp
+++ b/src/ui/FlatButton.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QEventTransition>
#include <QFontDatabase>
#include <QIcon>
diff --git a/src/ui/FlatButton.h b/src/ui/FlatButton.h
index 3749a0d9..c79945b7 100644
--- a/src/ui/FlatButton.h
+++ b/src/ui/FlatButton.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QPushButton>
diff --git a/src/ui/FloatingButton.cpp b/src/ui/FloatingButton.cpp
index f3a09ccd..95b6ae1d 100644
--- a/src/ui/FloatingButton.cpp
+++ b/src/ui/FloatingButton.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QPainter>
#include <QPainterPath>
diff --git a/src/ui/FloatingButton.h b/src/ui/FloatingButton.h
index 91e99ebb..b59b3854 100644
--- a/src/ui/FloatingButton.h
+++ b/src/ui/FloatingButton.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include "RaisedButton.h"
diff --git a/src/ui/InfoMessage.cpp b/src/ui/InfoMessage.cpp
index 0b69564d..fb3b306a 100644
--- a/src/ui/InfoMessage.cpp
+++ b/src/ui/InfoMessage.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "InfoMessage.h"
#include "Config.h"
diff --git a/src/ui/InfoMessage.h b/src/ui/InfoMessage.h
index f8f457e3..cc0c57dc 100644
--- a/src/ui/InfoMessage.h
+++ b/src/ui/InfoMessage.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QColor>
diff --git a/src/ui/Label.cpp b/src/ui/Label.cpp
index 8bd8c54e..2e8f8e1d 100644
--- a/src/ui/Label.cpp
+++ b/src/ui/Label.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include "Label.h"
#include <QMouseEvent>
diff --git a/src/ui/Label.h b/src/ui/Label.h
index 09cf27d7..a3eb511b 100644
--- a/src/ui/Label.h
+++ b/src/ui/Label.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QLabel>
diff --git a/src/ui/LoadingIndicator.cpp b/src/ui/LoadingIndicator.cpp
index d2b1240d..fb3c761c 100644
--- a/src/ui/LoadingIndicator.cpp
+++ b/src/ui/LoadingIndicator.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "LoadingIndicator.h"
#include <QPaintEvent>
diff --git a/src/ui/LoadingIndicator.h b/src/ui/LoadingIndicator.h
index 678ef611..ba56b449 100644
--- a/src/ui/LoadingIndicator.h
+++ b/src/ui/LoadingIndicator.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QColor>
diff --git a/src/ui/Menu.h b/src/ui/Menu.h
index d0427851..fd2946dd 100644
--- a/src/ui/Menu.h
+++ b/src/ui/Menu.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QMenu>
diff --git a/src/ui/NhekoCursorShape.cpp b/src/ui/NhekoCursorShape.cpp
index 06b0a321..b36eedbd 100644
--- a/src/ui/NhekoCursorShape.cpp
+++ b/src/ui/NhekoCursorShape.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "NhekoCursorShape.h"
#include <QCursor>
diff --git a/src/ui/NhekoCursorShape.h b/src/ui/NhekoCursorShape.h
index 2eab5e42..6f6a2b82 100644
--- a/src/ui/NhekoCursorShape.h
+++ b/src/ui/NhekoCursorShape.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
// see
diff --git a/src/ui/NhekoDropArea.cpp b/src/ui/NhekoDropArea.cpp
index 14b71524..54f48d3c 100644
--- a/src/ui/NhekoDropArea.cpp
+++ b/src/ui/NhekoDropArea.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "NhekoDropArea.h"
#include <QMimeData>
diff --git a/src/ui/NhekoDropArea.h b/src/ui/NhekoDropArea.h
index b03620f2..9fbf1737 100644
--- a/src/ui/NhekoDropArea.h
+++ b/src/ui/NhekoDropArea.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QQuickItem>
class NhekoDropArea : public QQuickItem
diff --git a/src/ui/OverlayModal.cpp b/src/ui/OverlayModal.cpp
index abd1827a..f5f28732 100644
--- a/src/ui/OverlayModal.cpp
+++ b/src/ui/OverlayModal.cpp
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#include <QPainter>
#include <QVBoxLayout>
diff --git a/src/ui/OverlayModal.h b/src/ui/OverlayModal.h
index e1fe8ec0..005614fa 100644
--- a/src/ui/OverlayModal.h
+++ b/src/ui/OverlayModal.h
@@ -1,19 +1,7 @@
-/*
- * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/ui/OverlayWidget.cpp b/src/ui/OverlayWidget.cpp
index a32d86b6..c8c95581 100644
--- a/src/ui/OverlayWidget.cpp
+++ b/src/ui/OverlayWidget.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "OverlayWidget.h"
#include <QPainter>
diff --git a/src/ui/OverlayWidget.h b/src/ui/OverlayWidget.h
index ed3ef52d..05bb8696 100644
--- a/src/ui/OverlayWidget.h
+++ b/src/ui/OverlayWidget.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QEvent>
diff --git a/src/ui/Painter.h b/src/ui/Painter.h
index c69dca95..3353f0c7 100644
--- a/src/ui/Painter.h
+++ b/src/ui/Painter.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QFontMetrics>
diff --git a/src/ui/RaisedButton.cpp b/src/ui/RaisedButton.cpp
index c519f84f..563cb8e5 100644
--- a/src/ui/RaisedButton.cpp
+++ b/src/ui/RaisedButton.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QEventTransition>
#include <QPropertyAnimation>
diff --git a/src/ui/RaisedButton.h b/src/ui/RaisedButton.h
index 47ef1acd..dcb579bb 100644
--- a/src/ui/RaisedButton.h
+++ b/src/ui/RaisedButton.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QGraphicsDropShadowEffect>
diff --git a/src/ui/Ripple.cpp b/src/ui/Ripple.cpp
index ef8a62dd..f0455f0b 100644
--- a/src/ui/Ripple.cpp
+++ b/src/ui/Ripple.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "Ripple.h"
#include "RippleOverlay.h"
diff --git a/src/ui/Ripple.h b/src/ui/Ripple.h
index 3701fb6c..2ad42b9e 100644
--- a/src/ui/Ripple.h
+++ b/src/ui/Ripple.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QBrush>
diff --git a/src/ui/RippleOverlay.cpp b/src/ui/RippleOverlay.cpp
index 20e98c0f..00915deb 100644
--- a/src/ui/RippleOverlay.cpp
+++ b/src/ui/RippleOverlay.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QPainter>
#include "Ripple.h"
diff --git a/src/ui/RippleOverlay.h b/src/ui/RippleOverlay.h
index 5d12aff7..7ae3e4f1 100644
--- a/src/ui/RippleOverlay.h
+++ b/src/ui/RippleOverlay.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QPainterPath>
diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp
index aa6f60a0..cb82cc4e 100644
--- a/src/ui/RoomSettings.cpp
+++ b/src/ui/RoomSettings.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "RoomSettings.h"
#include <QApplication>
@@ -229,7 +233,7 @@ RoomSettings::roomName() const
QString
RoomSettings::roomTopic() const
{
- return QString::fromStdString(info_.topic);
+ return utils::linkifyMessage(QString::fromStdString(info_.topic).toHtmlEscaped());
}
QString
@@ -622,4 +626,4 @@ RoomSettings::updateAvatar()
emit proxy->stopLoading();
});
});
-}
\ No newline at end of file
+}
diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h
index 25c6e588..367f3111 100644
--- a/src/ui/RoomSettings.h
+++ b/src/ui/RoomSettings.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QLabel>
diff --git a/src/ui/SnackBar.cpp b/src/ui/SnackBar.cpp
index 51a0ff38..18990c47 100644
--- a/src/ui/SnackBar.cpp
+++ b/src/ui/SnackBar.cpp
@@ -1,17 +1,19 @@
-#include <QPainter>
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
-#include <tweeny.h>
+#include <QPainter>
#include "SnackBar.h"
constexpr int STARTING_OFFSET = 1;
-constexpr int ANIMATION_DURATION = 6'000;
constexpr int BOX_PADDING = 10;
constexpr double MIN_WIDTH = 400.0;
constexpr double MIN_WIDTH_PERCENTAGE = 0.3;
SnackBar::SnackBar(QWidget *parent)
: OverlayWidget(parent)
+ , offset_anim(this, "offset", this)
{
QFont font;
font.setPointSizeF(font.pointSizeF() * 1.2);
@@ -24,17 +26,14 @@ SnackBar::SnackBar(QWidget *parent)
hideTimer_.setSingleShot(true);
- auto offset_anim = tweeny::from(1.0f).to(0.0f).during(100).via(tweeny::easing::cubicOut);
- connect(&showTimer_, &QTimer::timeout, this, [this, offset_anim]() mutable {
- if (offset_anim.progress() < 1.0f) {
- offset_ = offset_anim.step(0.07f);
- repaint();
- } else {
- showTimer_.stop();
- hideTimer_.start(ANIMATION_DURATION);
- offset_anim.seek(0.0f);
- }
- });
+ offset_anim.setStartValue(1.0);
+ offset_anim.setEndValue(0.0);
+ offset_anim.setDuration(100);
+ offset_anim.setEasingCurve(QEasingCurve::OutCubic);
+
+ connect(this, &SnackBar::offsetChanged, this, [this]() mutable { repaint(); });
+ connect(
+ &offset_anim, &QPropertyAnimation::finished, this, [this]() { hideTimer_.start(10000); });
connect(&hideTimer_, SIGNAL(timeout()), this, SLOT(hideMessage()));
@@ -50,7 +49,7 @@ SnackBar::start()
show();
raise();
- showTimer_.start(10);
+ offset_anim.start();
}
void
@@ -73,7 +72,6 @@ SnackBar::hideMessage()
void
SnackBar::stopTimers()
{
- showTimer_.stop();
hideTimer_.stop();
}
diff --git a/src/ui/SnackBar.h b/src/ui/SnackBar.h
index 15cbf626..8d127933 100644
--- a/src/ui/SnackBar.h
+++ b/src/ui/SnackBar.h
@@ -1,7 +1,12 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QCoreApplication>
#include <QPaintEvent>
+#include <QPropertyAnimation>
#include <QTimer>
#include <deque>
@@ -19,6 +24,7 @@ class SnackBar : public OverlayWidget
Q_PROPERTY(QColor bgColor READ backgroundColor WRITE setBackgroundColor)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
+ Q_PROPERTY(double offset READ offset WRITE setOffset NOTIFY offsetChanged)
public:
explicit SnackBar(QWidget *parent);
@@ -42,9 +48,21 @@ public:
update();
}
+ double offset() { return offset_; }
+ void setOffset(double offset)
+ {
+ if (offset != offset_) {
+ offset_ = offset;
+ emit offsetChanged();
+ }
+ }
+
public slots:
void showMessage(const QString &msg);
+signals:
+ void offsetChanged();
+
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
@@ -64,10 +82,11 @@ private:
std::deque<QString> messages_;
- QTimer showTimer_;
QTimer hideTimer_;
double boxHeight_;
+ QPropertyAnimation offset_anim;
+
SnackBarPosition position_;
};
diff --git a/src/ui/TextField.cpp b/src/ui/TextField.cpp
index 055fe73b..7d015e89 100644
--- a/src/ui/TextField.cpp
+++ b/src/ui/TextField.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "TextField.h"
#include <QCoreApplication>
diff --git a/src/ui/TextField.h b/src/ui/TextField.h
index 01fd5782..ac4c396e 100644
--- a/src/ui/TextField.h
+++ b/src/ui/TextField.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QColor>
diff --git a/src/ui/TextLabel.cpp b/src/ui/TextLabel.cpp
index 8ea2bb54..3568e15c 100644
--- a/src/ui/TextLabel.cpp
+++ b/src/ui/TextLabel.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include "ui/TextLabel.h"
#include <QAbstractTextDocumentLayout>
diff --git a/src/ui/TextLabel.h b/src/ui/TextLabel.h
index 56778dcc..bc095823 100644
--- a/src/ui/TextLabel.h
+++ b/src/ui/TextLabel.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QSize>
diff --git a/src/ui/Theme.cpp b/src/ui/Theme.cpp
index 7209864a..4341bd63 100644
--- a/src/ui/Theme.cpp
+++ b/src/ui/Theme.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QDebug>
#include "Theme.h"
diff --git a/src/ui/Theme.h b/src/ui/Theme.h
index 34971280..3243c076 100644
--- a/src/ui/Theme.h
+++ b/src/ui/Theme.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QColor>
diff --git a/src/ui/ThemeManager.cpp b/src/ui/ThemeManager.cpp
index 7baed1f3..834f5083 100644
--- a/src/ui/ThemeManager.cpp
+++ b/src/ui/ThemeManager.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QFontDatabase>
#include "ThemeManager.h"
diff --git a/src/ui/ThemeManager.h b/src/ui/ThemeManager.h
index d35ff754..f2099730 100644
--- a/src/ui/ThemeManager.h
+++ b/src/ui/ThemeManager.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QCommonStyle>
diff --git a/src/ui/ToggleButton.cpp b/src/ui/ToggleButton.cpp
index 40ea82ac..33bf8f92 100644
--- a/src/ui/ToggleButton.cpp
+++ b/src/ui/ToggleButton.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QColor>
#include <QCoreApplication>
#include <QEvent>
diff --git a/src/ui/ToggleButton.h b/src/ui/ToggleButton.h
index 14c3450b..2413b086 100644
--- a/src/ui/ToggleButton.h
+++ b/src/ui/ToggleButton.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAbstractButton>
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 77f6ced5..b5feb353 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include <QFileDialog>
#include <QImageReader>
#include <QMimeDatabase>
@@ -159,7 +163,7 @@ UserProfile::fetchDeviceList(const QString &userID)
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
- err->matrix_error.errcode,
+ mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
@@ -173,9 +177,10 @@ UserProfile::fetchDeviceList(const QString &userID)
std::string local_user_id = utils::localUser().toStdString();
if (err) {
- nhlog::net()->warn("failed to query device keys: {},{}",
- err->matrix_error.errcode,
- static_cast<int>(err->status_code));
+ nhlog::net()->warn(
+ "failed to query device keys: {},{}",
+ mtx::errors::to_string(err->matrix_error.errcode),
+ static_cast<int>(err->status_code));
return;
}
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index ffc5dcae..7c9c7495 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -1,3 +1,7 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#pragma once
#include <QAbstractListModel>
|