aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/accountregistry.cpp97
-rw-r--r--lib/accountregistry.h45
-rw-r--r--lib/avatar.h4
-rw-r--r--lib/connection.cpp45
-rw-r--r--lib/connection.h47
-rw-r--r--lib/connectiondata.cpp12
-rw-r--r--lib/connectiondata.h4
-rw-r--r--lib/converters.h33
-rw-r--r--lib/csapi/account-data.cpp32
-rw-r--r--lib/csapi/admin.cpp8
-rw-r--r--lib/csapi/admin.h5
-rw-r--r--lib/csapi/administrative_contact.cpp31
-rw-r--r--lib/csapi/appservice_room_directory.cpp6
-rw-r--r--lib/csapi/banning.cpp7
-rw-r--r--lib/csapi/capabilities.cpp9
-rw-r--r--lib/csapi/content-repo.cpp49
-rw-r--r--lib/csapi/content-repo.h44
-rw-r--r--lib/csapi/create_room.cpp4
-rw-r--r--lib/csapi/create_room.h5
-rw-r--r--lib/csapi/cross_signing.cpp9
-rw-r--r--lib/csapi/definitions/public_rooms_response.h2
-rw-r--r--lib/csapi/definitions/request_token_response.h2
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.h2
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.h2
-rw-r--r--lib/csapi/device_management.cpp19
-rw-r--r--lib/csapi/device_management.h5
-rw-r--r--lib/csapi/directory.cpp26
-rw-r--r--lib/csapi/directory.h5
-rw-r--r--lib/csapi/event_context.cpp11
-rw-r--r--lib/csapi/event_context.h20
-rw-r--r--lib/csapi/filter.cpp15
-rw-r--r--lib/csapi/filter.h10
-rw-r--r--lib/csapi/inviting.cpp5
-rw-r--r--lib/csapi/joining.cpp6
-rw-r--r--lib/csapi/joining.h10
-rw-r--r--lib/csapi/keys.cpp14
-rw-r--r--lib/csapi/keys.h5
-rw-r--r--lib/csapi/kicking.cpp4
-rw-r--r--lib/csapi/knocking.cpp4
-rw-r--r--lib/csapi/knocking.h5
-rw-r--r--lib/csapi/leaving.cpp12
-rw-r--r--lib/csapi/list_joined_rooms.cpp9
-rw-r--r--lib/csapi/list_public_rooms.cpp20
-rw-r--r--lib/csapi/list_public_rooms.h20
-rw-r--r--lib/csapi/login.cpp9
-rw-r--r--lib/csapi/login.h10
-rw-r--r--lib/csapi/logout.cpp14
-rw-r--r--lib/csapi/message_pagination.cpp7
-rw-r--r--lib/csapi/message_pagination.h20
-rw-r--r--lib/csapi/notifications.cpp8
-rw-r--r--lib/csapi/notifications.h5
-rw-r--r--lib/csapi/openid.cpp8
-rw-r--r--lib/csapi/openid.h5
-rw-r--r--lib/csapi/peeking_events.cpp7
-rw-r--r--lib/csapi/peeking_events.h15
-rw-r--r--lib/csapi/presence.cpp12
-rw-r--r--lib/csapi/presence.h10
-rw-r--r--lib/csapi/profile.cpp30
-rw-r--r--lib/csapi/profile.h12
-rw-r--r--lib/csapi/pusher.cpp9
-rw-r--r--lib/csapi/pusher.h4
-rw-r--r--lib/csapi/pushrules.cpp59
-rw-r--r--lib/csapi/pushrules.h10
-rw-r--r--lib/csapi/read_markers.cpp5
-rw-r--r--lib/csapi/receipts.cpp8
-rw-r--r--lib/csapi/redaction.cpp6
-rw-r--r--lib/csapi/redaction.h5
-rw-r--r--lib/csapi/registration.cpp36
-rw-r--r--lib/csapi/registration.h10
-rw-r--r--lib/csapi/report_content.cpp6
-rw-r--r--lib/csapi/room_send.cpp8
-rw-r--r--lib/csapi/room_send.h5
-rw-r--r--lib/csapi/room_state.cpp8
-rw-r--r--lib/csapi/room_state.h5
-rw-r--r--lib/csapi/room_upgrades.cpp5
-rw-r--r--lib/csapi/rooms.cpp41
-rw-r--r--lib/csapi/rooms.h14
-rw-r--r--lib/csapi/search.cpp4
-rw-r--r--lib/csapi/search.h2
-rw-r--r--lib/csapi/sso_login_redirect.cpp15
-rw-r--r--lib/csapi/tags.cpp24
-rw-r--r--lib/csapi/third_party_lookup.cpp41
-rw-r--r--lib/csapi/third_party_membership.cpp5
-rw-r--r--lib/csapi/to_device.cpp6
-rw-r--r--lib/csapi/typing.cpp6
-rw-r--r--lib/csapi/users.cpp4
-rw-r--r--lib/csapi/users.h7
-rw-r--r--lib/csapi/versions.cpp7
-rw-r--r--lib/csapi/voip.cpp9
-rw-r--r--lib/csapi/voip.h5
-rw-r--r--lib/csapi/wellknown.cpp7
-rw-r--r--lib/csapi/whoami.cpp9
-rw-r--r--lib/csapi/whoami.h10
-rw-r--r--lib/eventitem.h11
-rw-r--r--lib/events/encryptedfile.h88
-rw-r--r--lib/events/encryptionevent.cpp8
-rw-r--r--lib/events/encryptionevent.h4
-rw-r--r--lib/events/eventcontent.cpp20
-rw-r--r--lib/events/eventcontent.h17
-rw-r--r--lib/events/roomavatarevent.h2
-rw-r--r--lib/events/roomcreateevent.cpp21
-rw-r--r--lib/events/roomcreateevent.h2
-rw-r--r--lib/events/roomevent.h11
-rw-r--r--lib/events/roommessageevent.cpp8
-rw-r--r--lib/events/roommessageevent.h17
-rw-r--r--lib/events/stateevent.h4
-rw-r--r--lib/jobs/basejob.cpp166
-rw-r--r--lib/jobs/basejob.h82
-rw-r--r--lib/jobs/requestdata.h2
-rw-r--r--lib/jobs/syncjob.cpp2
-rw-r--r--lib/logging.cpp1
-rw-r--r--lib/logging.h3
-rw-r--r--lib/mxcreply.cpp70
-rw-r--r--lib/mxcreply.h29
-rw-r--r--lib/networkaccessmanager.cpp78
-rw-r--r--lib/networkaccessmanager.h5
-rw-r--r--lib/qt_connection_util.h28
-rw-r--r--lib/quotient_common.h41
-rw-r--r--lib/room.cpp117
-rw-r--r--lib/room.h47
-rw-r--r--lib/settings.cpp13
-rw-r--r--lib/settings.h19
-rw-r--r--lib/syncdata.cpp7
-rw-r--r--lib/user.cpp27
-rw-r--r--lib/user.h24
-rw-r--r--lib/util.cpp27
-rw-r--r--lib/util.h17
127 files changed, 1227 insertions, 1097 deletions
diff --git a/lib/accountregistry.cpp b/lib/accountregistry.cpp
new file mode 100644
index 00000000..a292ed45
--- /dev/null
+++ b/lib/accountregistry.cpp
@@ -0,0 +1,97 @@
+// SPDX-FileCopyrightText: Kitsune Ral <Kitsune-Ral@users.sf.net>
+// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "accountregistry.h"
+
+#include "connection.h"
+
+using namespace Quotient;
+
+void AccountRegistry::add(Connection* c)
+{
+ if (m_accounts.contains(c))
+ return;
+ beginInsertRows(QModelIndex(), m_accounts.size(), m_accounts.size());
+ m_accounts += c;
+ endInsertRows();
+}
+
+void AccountRegistry::drop(Connection* c)
+{
+ beginRemoveRows(QModelIndex(), m_accounts.indexOf(c), m_accounts.indexOf(c));
+ m_accounts.removeOne(c);
+ endRemoveRows();
+ Q_ASSERT(!m_accounts.contains(c));
+}
+
+bool AccountRegistry::isLoggedIn(const QString &userId) const
+{
+ return std::any_of(m_accounts.cbegin(), m_accounts.cend(),
+ [&userId](Connection* a) { return a->userId() == userId; });
+}
+
+bool AccountRegistry::contains(Connection *c) const
+{
+ return m_accounts.contains(c);
+}
+
+AccountRegistry::AccountRegistry() = default;
+
+QVariant AccountRegistry::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return {};
+ }
+
+ if (index.row() >= m_accounts.count()) {
+ return {};
+ }
+
+ auto account = m_accounts[index.row()];
+
+ if (role == ConnectionRole) {
+ return QVariant::fromValue(account);
+ }
+
+ return {};
+}
+
+int AccountRegistry::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ return 0;
+ }
+
+ return m_accounts.count();
+}
+
+QHash<int, QByteArray> AccountRegistry::roleNames() const
+{
+ return {{ConnectionRole, "connection"}};
+}
+
+bool AccountRegistry::isEmpty() const
+{
+ return m_accounts.isEmpty();
+}
+
+int AccountRegistry::count() const
+{
+ return m_accounts.count();
+}
+
+const QVector<Connection*> AccountRegistry::accounts() const
+{
+ return m_accounts;
+}
+
+Connection* AccountRegistry::get(const QString& userId)
+{
+ for (const auto &connection : m_accounts) {
+ if(connection->userId() == userId) {
+ return connection;
+ }
+ }
+ return nullptr;
+}
diff --git a/lib/accountregistry.h b/lib/accountregistry.h
new file mode 100644
index 00000000..5efda459
--- /dev/null
+++ b/lib/accountregistry.h
@@ -0,0 +1,45 @@
+// SPDX-FileCopyrightText: 2020 Kitsune Ral <Kitsune-Ral@users.sf.net>
+// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QAbstractListModel>
+
+namespace Quotient {
+class Connection;
+
+class AccountRegistry : public QAbstractListModel {
+ Q_OBJECT
+public:
+ enum EventRoles {
+ ConnectionRole = Qt::UserRole + 1,
+ };
+
+ static AccountRegistry &instance() {
+ static AccountRegistry _instance;
+ return _instance;
+ }
+
+ const QVector<Connection*> accounts() const;
+ void add(Connection* a);
+ void drop(Connection* a);
+ bool isLoggedIn(const QString& userId) const;
+ bool isEmpty() const;
+ int count() const;
+ bool contains(Connection*) const;
+ Connection* get(const QString& userId);
+
+ [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
+
+private:
+ AccountRegistry();
+
+ QVector<Connection *> m_accounts;
+};
+}
diff --git a/lib/avatar.h b/lib/avatar.h
index be125c17..d4634aea 100644
--- a/lib/avatar.h
+++ b/lib/avatar.h
@@ -21,7 +21,7 @@ public:
Avatar& operator=(Avatar&&);
using get_callback_t = std::function<void()>;
- using upload_callback_t = std::function<void(QString)>;
+ using upload_callback_t = std::function<void(QUrl)>;
QImage get(Connection* connection, int dimension,
get_callback_t callback) const;
@@ -42,5 +42,3 @@ private:
std::unique_ptr<Private> d;
};
} // namespace Quotient
-/// \deprecated Use namespace Quotient instead
-namespace QMatrixClient = Quotient;
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 7dd04aaa..1fe0d2d0 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -13,6 +13,7 @@
#include "room.h"
#include "settings.h"
#include "user.h"
+#include "accountregistry.h"
// NB: since Qt 6, moc_connection.cpp needs Room and User fully defined
#include "moc_connection.cpp"
@@ -258,6 +259,7 @@ Connection::~Connection()
{
qCDebug(MAIN) << "deconstructing connection object for" << userId();
stopSync();
+ AccountRegistry::instance().drop(this);
}
void Connection::resolveServer(const QString& mxid)
@@ -286,7 +288,7 @@ void Connection::resolveServer(const QString& mxid)
if (d->resolverJob->error() == BaseJob::Abandoned)
return;
- if (d->resolverJob->error() != BaseJob::NotFoundError) {
+ if (d->resolverJob->error() != BaseJob::NotFound) {
if (!d->resolverJob->status().good()) {
qCWarning(MAIN)
<< "Fetching .well-known file failed, FAIL_PROMPT";
@@ -314,8 +316,6 @@ void Connection::resolveServer(const QString& mxid)
setHomeserver(maybeBaseUrl);
}
Q_ASSERT(d->loginFlowsJob != nullptr); // Ensured by setHomeserver()
- connect(d->loginFlowsJob, &BaseJob::success, this,
- &Connection::resolved);
connect(d->loginFlowsJob, &BaseJob::failure, this, [this] {
qCWarning(MAIN) << "Homeserver base URL sanity check failed";
emit resolveError(tr("The homeserver doesn't seem to be working"));
@@ -341,7 +341,7 @@ void Connection::loginWithPassword(const QString& userId,
const QString& initialDeviceName,
const QString& deviceId)
{
- d->checkAndConnect(userId, [=] {
+ d->checkAndConnect(userId, [=,this] {
d->loginToServer(LoginFlows::Password.type, makeUserIdentifier(userId),
password, /*token*/ "", deviceId, initialDeviceName);
}, LoginFlows::Password);
@@ -401,7 +401,7 @@ void Connection::reloadCapabilities()
" disabling version upgrade recommendations to reduce noise";
});
connect(d->capabilitiesJob, &BaseJob::failure, this, [this] {
- if (d->capabilitiesJob->error() == BaseJob::IncorrectRequestError)
+ if (d->capabilitiesJob->error() == BaseJob::IncorrectRequest)
qCDebug(MAIN) << "Server doesn't support /capabilities;"
" version upgrade recommendations won't be issued";
});
@@ -443,6 +443,7 @@ void Connection::Private::completeSetup(const QString& mxId)
qCDebug(MAIN) << "Using server" << data->baseUrl().toDisplayString()
<< "by user" << data->userId()
<< "from device" << data->deviceId();
+ AccountRegistry::instance().add(q);
#ifndef Quotient_E2EE_ENABLED
qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off.";
#else // Quotient_E2EE_ENABLED
@@ -795,11 +796,6 @@ void Connection::stopSync()
QString Connection::nextBatchToken() const { return d->data->lastEvent(); }
-PostReceiptJob* Connection::postReceipt(Room* room, RoomEvent* event)
-{
- return callApi<PostReceiptJob>(room->id(), "m.read", event->id());
-}
-
JoinRoomJob* Connection::joinRoom(const QString& roomAlias,
const QStringList& serverNames)
{
@@ -843,6 +839,15 @@ inline auto splitMediaId(const QString& mediaId)
return idParts;
}
+QUrl Connection::makeMediaUrl(QUrl mxcUrl) const
+{
+ Q_ASSERT(mxcUrl.scheme() == "mxc");
+ QUrlQuery q(mxcUrl.query());
+ q.addQueryItem(QStringLiteral("user_id"), userId());
+ mxcUrl.setQuery(q);
+ return mxcUrl;
+}
+
MediaThumbnailJob* Connection::getThumbnail(const QString& mediaId,
QSize requestedSize,
RunningPolicy policy)
@@ -1053,7 +1058,7 @@ ForgetRoomJob* Connection::forgetRoom(const QString& id)
connect(leaveJob, &BaseJob::result, this,
[this, leaveJob, forgetJob, room] {
if (leaveJob->error() == BaseJob::Success
- || leaveJob->error() == BaseJob::NotFoundError) {
+ || leaveJob->error() == BaseJob::NotFound) {
run(forgetJob);
// If the matching /sync response hasn't arrived yet,
// mark the room for explicit deletion
@@ -1072,7 +1077,7 @@ ForgetRoomJob* Connection::forgetRoom(const QString& id)
connect(forgetJob, &BaseJob::result, this, [this, id, forgetJob] {
// Leave room in case of success, or room not known by server
if (forgetJob->error() == BaseJob::Success
- || forgetJob->error() == BaseJob::NotFoundError)
+ || forgetJob->error() == BaseJob::NotFound)
d->removeRoom(id); // Delete the room from roomMap
else
qCWarning(MAIN).nospace() << "Error forgetting room " << id << ": "
@@ -1239,20 +1244,6 @@ int Connection::millisToReconnect() const
return d->syncJob ? d->syncJob->millisToRetry() : 0;
}
-QHash<QPair<QString, bool>, Room*> Connection::roomMap() const
-{
- // Copy-on-write-and-remove-elements is faster than copying elements one by
- // one.
- QHash<QPair<QString, bool>, Room*> roomMap = d->roomMap;
- for (auto it = roomMap.begin(); it != roomMap.end();) {
- if (it.value()->joinState() == JoinState::Leave)
- it = roomMap.erase(it);
- else
- ++it;
- }
- return roomMap;
-}
-
QVector<Room*> Connection::allRooms() const
{
QVector<Room*> result;
@@ -1725,7 +1716,7 @@ void Connection::getTurnServers()
{
auto job = callApi<GetTurnServerJob>();
connect(job, &GetTurnServerJob::success, this,
- [=] { emit turnServersChanged(job->data()); });
+ [this,job] { emit turnServersChanged(job->data()); });
}
const QString Connection::SupportedRoomVersion::StableTag =
diff --git a/lib/connection.h b/lib/connection.h
index a7a071f3..1a6ca9b0 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -138,15 +138,6 @@ public:
explicit Connection(const QUrl& server, QObject* parent = nullptr);
~Connection() override;
- /// Get all Invited and Joined rooms
- /*!
- * \return a hashmap from a composite key - room name and whether
- * it's an Invite rather than Join - to room pointers
- * \sa allRooms, rooms, roomsWithTag
- */
- [[deprecated("Use allRooms(), roomsWithTag() or rooms(joinStates) instead")]]
- QHash<QPair<QString, bool>, Room*> roomMap() const;
-
/// Get all rooms known within this Connection
/*!
* This includes Invite, Join and Leave rooms, in no particular order.
@@ -524,30 +515,12 @@ public Q_SLOTS:
*/
void assumeIdentity(const QString& mxId, const QString& accessToken,
const QString& deviceId);
- /*! \deprecated Use loginWithPassword instead */
- void connectToServer(const QString& userId, const QString& password,
- const QString& initialDeviceName,
- const QString& deviceId = {})
- {
- loginWithPassword(userId, password, initialDeviceName, deviceId);
- }
- /*! \deprecated
- * Use assumeIdentity() if you have an access token or
- * loginWithToken() if you have a login token.
- */
- void connectWithToken(const QString& userId, const QString& accessToken,
- const QString& deviceId)
- {
- assumeIdentity(userId, accessToken, deviceId);
- }
/// Explicitly request capabilities from the server
void reloadCapabilities();
/// Find out if capabilites are still loading from the server
bool loadingCapabilities() const;
- /** @deprecated Use stopSync() instead */
- void disconnectFromServer() { stopSync(); }
void logout();
void sync(int timeout = -1);
@@ -556,6 +529,8 @@ public Q_SLOTS:
void stopSync();
QString nextBatchToken() const;
+ Q_INVOKABLE QUrl makeMediaUrl(QUrl mxcUrl) const;
+
virtual MediaThumbnailJob*
getThumbnail(const QString& mediaId, QSize requestedSize,
RunningPolicy policy = BackgroundRequest);
@@ -662,24 +637,7 @@ public Q_SLOTS:
/** \deprecated Do not use this directly, use Room::leaveRoom() instead */
virtual LeaveRoomJob* leaveRoom(Room* room);
- // Old API that will be abolished any time soon. DO NOT USE.
-
- /** @deprecated Use callApi<PostReceiptJob>() or Room::postReceipt() instead
- */
- virtual PostReceiptJob* postReceipt(Room* room, RoomEvent* event);
-
Q_SIGNALS:
- /**
- * @deprecated
- * This was a signal resulting from a successful resolveServer().
- * Since Connection now provides setHomeserver(), the HS URL
- * may change even without resolveServer() invocation. Use
- * loginFLowsChanged() instead of resolved(). You can also use
- * loginWith*() and assumeIdentity() without the HS URL set in
- * advance (i.e. without calling resolveServer), as they trigger
- * server name resolution from MXID if the server URL is not valid.
- */
- void resolved();
void resolveError(QString error);
void homeserverChanged(QUrl baseUrl);
@@ -687,7 +645,6 @@ Q_SIGNALS:
void capabilitiesLoaded();
void connected();
- void reconnected(); //< \deprecated Use connected() instead
void loggedOut();
/** Login data or state have changed
*
diff --git a/lib/connectiondata.cpp b/lib/connectiondata.cpp
index e54d909b..87ad4577 100644
--- a/lib/connectiondata.cpp
+++ b/lib/connectiondata.cpp
@@ -118,18 +118,6 @@ void ConnectionData::setToken(QByteArray token)
d->accessToken = std::move(token);
}
-void ConnectionData::setHost(QString host)
-{
- d->baseUrl.setHost(host);
- qCDebug(MAIN) << "updated baseUrl to" << d->baseUrl;
-}
-
-void ConnectionData::setPort(int port)
-{
- d->baseUrl.setPort(port);
- qCDebug(MAIN) << "updated baseUrl to" << d->baseUrl;
-}
-
const QString& ConnectionData::deviceId() const { return d->deviceId; }
const QString& ConnectionData::userId() const { return d->userId; }
diff --git a/lib/connectiondata.h b/lib/connectiondata.h
index 7dd96f26..e16a2dac 100644
--- a/lib/connectiondata.h
+++ b/lib/connectiondata.h
@@ -31,10 +31,6 @@ public:
void setBaseUrl(QUrl baseUrl);
void setToken(QByteArray accessToken);
- [[deprecated("Use setBaseUrl() instead")]]
- void setHost(QString host);
- [[deprecated("Use setBaseUrl() instead")]]
- void setPort(int port);
void setDeviceId(const QString& deviceId);
void setUserId(const QString& userId);
void setNeedsToken(const QString& requestName);
diff --git a/lib/converters.h b/lib/converters.h
index af6c0192..cc6378e4 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -151,10 +151,17 @@ struct JsonConverter<QDate> {
};
template <>
-struct JsonConverter<QUrl> : JsonConverter<QString> {
- static auto dump(const QUrl& url) // Override on top of that for QString
+struct JsonConverter<QUrl> {
+ static auto load(const QJsonValue& jv)
+ {
+ // QT_NO_URL_CAST_FROM_STRING makes this a bit more verbose
+ QUrl url;
+ url.setUrl(jv.toString());
+ return url;
+ }
+ static auto dump(const QUrl& url)
{
- return JsonConverter<QString>::dump(url.toString(QUrl::FullyEncoded));
+ return url.toString(QUrl::FullyEncoded);
}
};
@@ -164,15 +171,6 @@ struct JsonConverter<QJsonArray> : public TrivialJsonDumper<QJsonArray> {
};
template <>
-struct JsonConverter<QByteArray> {
- static QString dump(const QByteArray& ba) { return ba.constData(); }
- static auto load(const QJsonValue& jv)
- {
- return fromJson<QString>(jv).toLatin1();
- }
-};
-
-template <>
struct JsonConverter<QVariant> {
static QJsonValue dump(const QVariant& v);
static QVariant load(const QJsonValue& jv);
@@ -304,16 +302,15 @@ namespace _impl {
q.addQueryItem(k, v ? QStringLiteral("true") : QStringLiteral("false"));
}
- inline void addTo(QUrlQuery& q, const QString& k, const QStringList& vals)
+ inline void addTo(QUrlQuery& q, const QString& k, const QUrl& v)
{
- for (const auto& v : vals)
- q.addQueryItem(k, v);
+ q.addQueryItem(k, v.toEncoded());
}
- inline void addTo(QUrlQuery& q, const QString&, const QJsonObject& vals)
+ inline void addTo(QUrlQuery& q, const QString& k, const QStringList& vals)
{
- for (auto it = vals.begin(); it != vals.end(); ++it)
- q.addQueryItem(it.key(), it.value().toString());
+ for (const auto& v : vals)
+ q.addQueryItem(k, v);
}
// This one is for types that don't have isEmpty() and for all types
diff --git a/lib/csapi/account-data.cpp b/lib/csapi/account-data.cpp
index 6a40e908..09fc8d40 100644
--- a/lib/csapi/account-data.cpp
+++ b/lib/csapi/account-data.cpp
@@ -4,31 +4,29 @@
#include "account-data.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetAccountDataJob::SetAccountDataJob(const QString& userId, const QString& type,
const QJsonObject& content)
: BaseJob(HttpVerb::Put, QStringLiteral("SetAccountDataJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/account_data/" % type)
+ makePath("/_matrix/client/r0", "/user/", userId, "/account_data/",
+ type))
{
- setRequestData(Data(toJson(content)));
+ setRequestData(RequestData(toJson(content)));
}
QUrl GetAccountDataJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0") % "/user/"
- % userId % "/account_data/" % type);
+ makePath("/_matrix/client/r0", "/user/",
+ userId, "/account_data/", type));
}
GetAccountDataJob::GetAccountDataJob(const QString& userId, const QString& type)
: BaseJob(HttpVerb::Get, QStringLiteral("GetAccountDataJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/account_data/" % type)
+ makePath("/_matrix/client/r0", "/user/", userId, "/account_data/",
+ type))
{}
SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId,
@@ -36,10 +34,10 @@ SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId,
const QString& type,
const QJsonObject& content)
: BaseJob(HttpVerb::Put, QStringLiteral("SetAccountDataPerRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/rooms/" % roomId % "/account_data/" % type)
+ makePath("/_matrix/client/r0", "/user/", userId, "/rooms/",
+ roomId, "/account_data/", type))
{
- setRequestData(Data(toJson(content)));
+ setRequestData(RequestData(toJson(content)));
}
QUrl GetAccountDataPerRoomJob::makeRequestUrl(QUrl baseUrl,
@@ -48,15 +46,15 @@ QUrl GetAccountDataPerRoomJob::makeRequestUrl(QUrl baseUrl,
const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/user/" % userId % "/rooms/" % roomId
- % "/account_data/" % type);
+ makePath("/_matrix/client/r0", "/user/",
+ userId, "/rooms/", roomId,
+ "/account_data/", type));
}
GetAccountDataPerRoomJob::GetAccountDataPerRoomJob(const QString& userId,
const QString& roomId,
const QString& type)
: BaseJob(HttpVerb::Get, QStringLiteral("GetAccountDataPerRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/rooms/" % roomId % "/account_data/" % type)
+ makePath("/_matrix/client/r0", "/user/", userId, "/rooms/",
+ roomId, "/account_data/", type))
{}
diff --git a/lib/csapi/admin.cpp b/lib/csapi/admin.cpp
index 9619c441..81dd0624 100644
--- a/lib/csapi/admin.cpp
+++ b/lib/csapi/admin.cpp
@@ -4,18 +4,16 @@
#include "admin.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetWhoIsJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/admin/whois/" % userId);
+ makePath("/_matrix/client/r0",
+ "/admin/whois/", userId));
}
GetWhoIsJob::GetWhoIsJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetWhoIsJob"),
- QStringLiteral("/_matrix/client/r0") % "/admin/whois/" % userId)
+ makePath("/_matrix/client/r0", "/admin/whois/", userId))
{}
diff --git a/lib/csapi/admin.h b/lib/csapi/admin.h
index d4fe639b..570bf24a 100644
--- a/lib/csapi/admin.h
+++ b/lib/csapi/admin.h
@@ -74,10 +74,7 @@ public:
// Result properties
/// The Matrix user ID of the user.
- QString userId() const
- {
- return loadFromJson<QString>("user_id"_ls);
- }
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
/// Each key is an identifier for one of the user's devices.
QHash<QString, DeviceInfo> devices() const
diff --git a/lib/csapi/administrative_contact.cpp b/lib/csapi/administrative_contact.cpp
index fa4f475a..589c9fc1 100644
--- a/lib/csapi/administrative_contact.cpp
+++ b/lib/csapi/administrative_contact.cpp
@@ -4,25 +4,22 @@
#include "administrative_contact.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetAccount3PIDsJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/account/3pid");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/account/3pid"));
}
GetAccount3PIDsJob::GetAccount3PIDsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetAccount3PIDsJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/3pid")
+ makePath("/_matrix/client/r0", "/account/3pid"))
{}
Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds)
: BaseJob(HttpVerb::Post, QStringLiteral("Post3PIDsJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/3pid")
+ makePath("/_matrix/client/r0", "/account/3pid"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("three_pid_creds"), threePidCreds);
@@ -32,7 +29,7 @@ Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds)
Add3PIDJob::Add3PIDJob(const QString& clientSecret, const QString& sid,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/3pid/add")
+ makePath("/_matrix/client/r0", "/account/3pid/add"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
@@ -44,7 +41,7 @@ Add3PIDJob::Add3PIDJob(const QString& clientSecret, const QString& sid,
Bind3PIDJob::Bind3PIDJob(const QString& clientSecret, const QString& idServer,
const QString& idAccessToken, const QString& sid)
: BaseJob(HttpVerb::Post, QStringLiteral("Bind3PIDJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/3pid/bind")
+ makePath("/_matrix/client/r0", "/account/3pid/bind"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -58,7 +55,7 @@ Delete3pidFromAccountJob::Delete3pidFromAccountJob(const QString& medium,
const QString& address,
const QString& idServer)
: BaseJob(HttpVerb::Post, QStringLiteral("Delete3pidFromAccountJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/3pid/delete")
+ makePath("/_matrix/client/r0", "/account/3pid/delete"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("id_server"), idServer);
@@ -72,7 +69,7 @@ Unbind3pidFromAccountJob::Unbind3pidFromAccountJob(const QString& medium,
const QString& address,
const QString& idServer)
: BaseJob(HttpVerb::Post, QStringLiteral("Unbind3pidFromAccountJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/3pid/unbind")
+ makePath("/_matrix/client/r0", "/account/3pid/unbind"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("id_server"), idServer);
@@ -85,19 +82,19 @@ Unbind3pidFromAccountJob::Unbind3pidFromAccountJob(const QString& medium,
RequestTokenTo3PIDEmailJob::RequestTokenTo3PIDEmailJob(
const EmailValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenTo3PIDEmailJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/account/3pid/email/requestToken",
+ makePath("/_matrix/client/r0",
+ "/account/3pid/email/requestToken"),
false)
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
RequestTokenTo3PIDMSISDNJob::RequestTokenTo3PIDMSISDNJob(
const MsisdnValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenTo3PIDMSISDNJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/account/3pid/msisdn/requestToken",
+ makePath("/_matrix/client/r0",
+ "/account/3pid/msisdn/requestToken"),
false)
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
diff --git a/lib/csapi/appservice_room_directory.cpp b/lib/csapi/appservice_room_directory.cpp
index 4d87e4af..40d784c6 100644
--- a/lib/csapi/appservice_room_directory.cpp
+++ b/lib/csapi/appservice_room_directory.cpp
@@ -4,16 +4,14 @@
#include "appservice_room_directory.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
UpdateAppserviceRoomDirectoryVisibilityJob::UpdateAppserviceRoomDirectoryVisibilityJob(
const QString& networkId, const QString& roomId, const QString& visibility)
: BaseJob(HttpVerb::Put,
QStringLiteral("UpdateAppserviceRoomDirectoryVisibilityJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/directory/list/appservice/" % networkId % "/" % roomId)
+ makePath("/_matrix/client/r0", "/directory/list/appservice/",
+ networkId, "/", roomId))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("visibility"), visibility);
diff --git a/lib/csapi/banning.cpp b/lib/csapi/banning.cpp
index 8e0add1a..472128bb 100644
--- a/lib/csapi/banning.cpp
+++ b/lib/csapi/banning.cpp
@@ -4,14 +4,12 @@
#include "banning.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
BanJob::BanJob(const QString& roomId, const QString& userId,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("BanJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/ban")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/ban"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
@@ -22,8 +20,7 @@ BanJob::BanJob(const QString& roomId, const QString& userId,
UnbanJob::UnbanJob(const QString& roomId, const QString& userId,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("UnbanJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/unban")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/unban"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
diff --git a/lib/csapi/capabilities.cpp b/lib/csapi/capabilities.cpp
index 33a53cad..bc21e462 100644
--- a/lib/csapi/capabilities.cpp
+++ b/lib/csapi/capabilities.cpp
@@ -4,20 +4,17 @@
#include "capabilities.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetCapabilitiesJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/capabilities");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/capabilities"));
}
GetCapabilitiesJob::GetCapabilitiesJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetCapabilitiesJob"),
- QStringLiteral("/_matrix/client/r0") % "/capabilities")
+ makePath("/_matrix/client/r0", "/capabilities"))
{
addExpectedKey("capabilities");
}
diff --git a/lib/csapi/content-repo.cpp b/lib/csapi/content-repo.cpp
index e913bfd1..6d1e38b6 100644
--- a/lib/csapi/content-repo.cpp
+++ b/lib/csapi/content-repo.cpp
@@ -4,8 +4,6 @@
#include "content-repo.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToUploadContent(const QString& filename)
@@ -18,11 +16,11 @@ auto queryToUploadContent(const QString& filename)
UploadContentJob::UploadContentJob(QIODevice* content, const QString& filename,
const QString& contentType)
: BaseJob(HttpVerb::Post, QStringLiteral("UploadContentJob"),
- QStringLiteral("/_matrix/media/r0") % "/upload",
+ makePath("/_matrix/media/r0", "/upload"),
queryToUploadContent(filename))
{
setRequestHeader("Content-Type", contentType.toLatin1());
- setRequestData(Data(content));
+ setRequestData(RequestData(content));
addExpectedKey("content_uri");
}
@@ -37,17 +35,16 @@ QUrl GetContentJob::makeRequestUrl(QUrl baseUrl, const QString& serverName,
const QString& mediaId, bool allowRemote)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/media/r0")
- % "/download/" % serverName % "/"
- % mediaId,
+ makePath("/_matrix/media/r0", "/download/",
+ serverName, "/", mediaId),
queryToGetContent(allowRemote));
}
GetContentJob::GetContentJob(const QString& serverName, const QString& mediaId,
bool allowRemote)
: BaseJob(HttpVerb::Get, QStringLiteral("GetContentJob"),
- QStringLiteral("/_matrix/media/r0") % "/download/" % serverName
- % "/" % mediaId,
+ makePath("/_matrix/media/r0", "/download/", serverName, "/",
+ mediaId),
queryToGetContent(allowRemote), {}, false)
{
setExpectedContentTypes({ "*/*" });
@@ -67,9 +64,9 @@ QUrl GetContentOverrideNameJob::makeRequestUrl(QUrl baseUrl,
bool allowRemote)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/media/r0")
- % "/download/" % serverName % "/"
- % mediaId % "/" % fileName,
+ makePath("/_matrix/media/r0", "/download/",
+ serverName, "/", mediaId, "/",
+ fileName),
queryToGetContentOverrideName(allowRemote));
}
@@ -78,8 +75,8 @@ GetContentOverrideNameJob::GetContentOverrideNameJob(const QString& serverName,
const QString& fileName,
bool allowRemote)
: BaseJob(HttpVerb::Get, QStringLiteral("GetContentOverrideNameJob"),
- QStringLiteral("/_matrix/media/r0") % "/download/" % serverName
- % "/" % mediaId % "/" % fileName,
+ makePath("/_matrix/media/r0", "/download/", serverName, "/",
+ mediaId, "/", fileName),
queryToGetContentOverrideName(allowRemote), {}, false)
{
setExpectedContentTypes({ "*/*" });
@@ -104,8 +101,7 @@ QUrl GetContentThumbnailJob::makeRequestUrl(QUrl baseUrl,
{
return BaseJob::makeRequestUrl(
std::move(baseUrl),
- QStringLiteral("/_matrix/media/r0") % "/thumbnail/" % serverName % "/"
- % mediaId,
+ makePath("/_matrix/media/r0", "/thumbnail/", serverName, "/", mediaId),
queryToGetContentThumbnail(width, height, method, allowRemote));
}
@@ -114,15 +110,15 @@ GetContentThumbnailJob::GetContentThumbnailJob(const QString& serverName,
int height, const QString& method,
bool allowRemote)
: BaseJob(HttpVerb::Get, QStringLiteral("GetContentThumbnailJob"),
- QStringLiteral("/_matrix/media/r0") % "/thumbnail/" % serverName
- % "/" % mediaId,
+ makePath("/_matrix/media/r0", "/thumbnail/", serverName, "/",
+ mediaId),
queryToGetContentThumbnail(width, height, method, allowRemote),
{}, false)
{
setExpectedContentTypes({ "image/jpeg", "image/png" });
}
-auto queryToGetUrlPreview(const QString& url, Omittable<qint64> ts)
+auto queryToGetUrlPreview(const QUrl& url, Omittable<qint64> ts)
{
QUrlQuery _q;
addParam<>(_q, QStringLiteral("url"), url);
@@ -130,29 +126,28 @@ auto queryToGetUrlPreview(const QString& url, Omittable<qint64> ts)
return _q;
}
-QUrl GetUrlPreviewJob::makeRequestUrl(QUrl baseUrl, const QString& url,
+QUrl GetUrlPreviewJob::makeRequestUrl(QUrl baseUrl, const QUrl& url,
Omittable<qint64> ts)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/media/r0")
- % "/preview_url",
+ makePath("/_matrix/media/r0",
+ "/preview_url"),
queryToGetUrlPreview(url, ts));
}
-GetUrlPreviewJob::GetUrlPreviewJob(const QString& url, Omittable<qint64> ts)
+GetUrlPreviewJob::GetUrlPreviewJob(const QUrl& url, Omittable<qint64> ts)
: BaseJob(HttpVerb::Get, QStringLiteral("GetUrlPreviewJob"),
- QStringLiteral("/_matrix/media/r0") % "/preview_url",
+ makePath("/_matrix/media/r0", "/preview_url"),
queryToGetUrlPreview(url, ts))
{}
QUrl GetConfigJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/media/r0")
- % "/config");
+ makePath("/_matrix/media/r0", "/config"));
}
GetConfigJob::GetConfigJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetConfigJob"),
- QStringLiteral("/_matrix/media/r0") % "/config")
+ makePath("/_matrix/media/r0", "/config"))
{}
diff --git a/lib/csapi/content-repo.h b/lib/csapi/content-repo.h
index a41453b2..28409f5c 100644
--- a/lib/csapi/content-repo.h
+++ b/lib/csapi/content-repo.h
@@ -34,10 +34,7 @@ public:
/// The [MXC URI](/client-server-api/#matrix-content-mxc-uris) to the
/// uploaded content.
- QString contentUri() const
- {
- return loadFromJson<QString>("content_uri"_ls);
- }
+ QUrl contentUri() const { return loadFromJson<QUrl>("content_uri"_ls); }
};
/*! \brief Download content from the content repository.
@@ -72,10 +69,7 @@ public:
// Result properties
/// The content type of the file that was previously uploaded.
- QString contentType() const
- {
- return reply()->rawHeader("Content-Type");
- }
+ QString contentType() const { return reply()->rawHeader("Content-Type"); }
/// The name of the file that was previously uploaded, if set.
QString contentDisposition() const
@@ -84,10 +78,7 @@ public:
}
/// The content that was previously uploaded.
- QIODevice* data()
- {
- return reply();
- }
+ QIODevice* data() { return reply(); }
};
/*! \brief Download content from the content repository overriding the file name
@@ -132,10 +123,7 @@ public:
// Result properties
/// The content type of the file that was previously uploaded.
- QString contentType() const
- {
- return reply()->rawHeader("Content-Type");
- }
+ QString contentType() const { return reply()->rawHeader("Content-Type"); }
/// The `fileName` requested or the name of the file that was previously
/// uploaded, if set.
@@ -145,10 +133,7 @@ public:
}
/// The content that was previously uploaded.
- QIODevice* data()
- {
- return reply();
- }
+ QIODevice* data() { return reply(); }
};
/*! \brief Download a thumbnail of content from the content repository
@@ -202,16 +187,10 @@ public:
// Result properties
/// The content type of the thumbnail.
- QString contentType() const
- {
- return reply()->rawHeader("Content-Type");
- }
+ QString contentType() const { return reply()->rawHeader("Content-Type"); }
/// A thumbnail of the requested content.
- QIODevice* data()
- {
- return reply();
- }
+ QIODevice* data() { return reply(); }
};
/*! \brief Get information about a URL for a client
@@ -237,14 +216,14 @@ public:
* return a newer version if it does not have the requested version
* available.
*/
- explicit GetUrlPreviewJob(const QString& url, Omittable<qint64> ts = none);
+ explicit GetUrlPreviewJob(const QUrl& url, Omittable<qint64> ts = none);
/*! \brief Construct a URL without creating a full-fledged job object
*
* This function can be used when a URL for GetUrlPreviewJob
* is necessary but the job itself isn't.
*/
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& url,
+ static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& url,
Omittable<qint64> ts = none);
// Result properties
@@ -257,10 +236,7 @@ public:
/// An [MXC URI](/client-server-api/#matrix-content-mxc-uris) to the image.
/// Omitted if there is no image.
- QString ogImage() const
- {
- return loadFromJson<QString>("og:image"_ls);
- }
+ QUrl ogImage() const { return loadFromJson<QUrl>("og:image"_ls); }
};
/*! \brief Get the configuration for the content repository.
diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp
index a94f9951..9aaef87f 100644
--- a/lib/csapi/create_room.cpp
+++ b/lib/csapi/create_room.cpp
@@ -4,8 +4,6 @@
#include "create_room.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
CreateRoomJob::CreateRoomJob(const QString& visibility,
@@ -18,7 +16,7 @@ CreateRoomJob::CreateRoomJob(const QString& visibility,
const QString& preset, Omittable<bool> isDirect,
const QJsonObject& powerLevelContentOverride)
: BaseJob(HttpVerb::Post, QStringLiteral("CreateRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/createRoom")
+ makePath("/_matrix/client/r0", "/createRoom"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility);
diff --git a/lib/csapi/create_room.h b/lib/csapi/create_room.h
index 8c6af7d4..81dfbffc 100644
--- a/lib/csapi/create_room.h
+++ b/lib/csapi/create_room.h
@@ -268,10 +268,7 @@ public:
// Result properties
/// The created room's ID.
- QString roomId() const
- {
- return loadFromJson<QString>("room_id"_ls);
- }
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
};
template <>
diff --git a/lib/csapi/cross_signing.cpp b/lib/csapi/cross_signing.cpp
index 9bfc026a..1fa0e949 100644
--- a/lib/csapi/cross_signing.cpp
+++ b/lib/csapi/cross_signing.cpp
@@ -4,8 +4,6 @@
#include "cross_signing.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
UploadCrossSigningKeysJob::UploadCrossSigningKeysJob(
@@ -13,8 +11,7 @@ UploadCrossSigningKeysJob::UploadCrossSigningKeysJob(
const Omittable<CrossSigningKey>& selfSigningKey,
const Omittable<CrossSigningKey>& userSigningKey)
: BaseJob(HttpVerb::Post, QStringLiteral("UploadCrossSigningKeysJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/keys/device_signing/upload")
+ makePath("/_matrix/client/r0", "/keys/device_signing/upload"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("master_key"), masterKey);
@@ -28,7 +25,7 @@ UploadCrossSigningKeysJob::UploadCrossSigningKeysJob(
UploadCrossSigningSignaturesJob::UploadCrossSigningSignaturesJob(
const QHash<QString, QHash<QString, QJsonObject>>& signatures)
: BaseJob(HttpVerb::Post, QStringLiteral("UploadCrossSigningSignaturesJob"),
- QStringLiteral("/_matrix/client/r0") % "/keys/signatures/upload")
+ makePath("/_matrix/client/r0", "/keys/signatures/upload"))
{
- setRequestData(Data(toJson(signatures)));
+ setRequestData(RequestData(toJson(signatures)));
}
diff --git a/lib/csapi/definitions/public_rooms_response.h b/lib/csapi/definitions/public_rooms_response.h
index 34b447d2..2938b4ec 100644
--- a/lib/csapi/definitions/public_rooms_response.h
+++ b/lib/csapi/definitions/public_rooms_response.h
@@ -36,7 +36,7 @@ struct PublicRoomsChunk {
bool guestCanJoin;
/// The URL for the room's avatar, if one is set.
- QString avatarUrl;
+ QUrl avatarUrl;
/// The room's join rule. When not present, the room is assumed to
/// be `public`. Note that rooms with `invite` join rules are not
diff --git a/lib/csapi/definitions/request_token_response.h b/lib/csapi/definitions/request_token_response.h
index f9981100..d5fbbadb 100644
--- a/lib/csapi/definitions/request_token_response.h
+++ b/lib/csapi/definitions/request_token_response.h
@@ -25,7 +25,7 @@ struct RequestTokenResponse {
/// will happen without the client's involvement provided the homeserver
/// advertises this specification version in the `/versions` response
/// (ie: r0.5.0).
- QString submitUrl;
+ QUrl submitUrl;
};
template <>
diff --git a/lib/csapi/definitions/wellknown/homeserver.h b/lib/csapi/definitions/wellknown/homeserver.h
index 5cfaca24..b7db4182 100644
--- a/lib/csapi/definitions/wellknown/homeserver.h
+++ b/lib/csapi/definitions/wellknown/homeserver.h
@@ -10,7 +10,7 @@ namespace Quotient {
/// Used by clients to discover homeserver information.
struct HomeserverInformation {
/// The base URL for the homeserver for client-server connections.
- QString baseUrl;
+ QUrl baseUrl;
};
template <>
diff --git a/lib/csapi/definitions/wellknown/identity_server.h b/lib/csapi/definitions/wellknown/identity_server.h
index 3bd07bd1..885e3d34 100644
--- a/lib/csapi/definitions/wellknown/identity_server.h
+++ b/lib/csapi/definitions/wellknown/identity_server.h
@@ -10,7 +10,7 @@ namespace Quotient {
/// Used by clients to discover identity server information.
struct IdentityServerInformation {
/// The base URL for the identity server for client-server connections.
- QString baseUrl;
+ QUrl baseUrl;
};
template <>
diff --git a/lib/csapi/device_management.cpp b/lib/csapi/device_management.cpp
index eac9a545..da6dbc76 100644
--- a/lib/csapi/device_management.cpp
+++ b/lib/csapi/device_management.cpp
@@ -4,38 +4,35 @@
#include "device_management.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetDevicesJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/devices");
+ makePath("/_matrix/client/r0", "/devices"));
}
GetDevicesJob::GetDevicesJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetDevicesJob"),
- QStringLiteral("/_matrix/client/r0") % "/devices")
+ makePath("/_matrix/client/r0", "/devices"))
{}
QUrl GetDeviceJob::makeRequestUrl(QUrl baseUrl, const QString& deviceId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/devices/" % deviceId);
+ makePath("/_matrix/client/r0", "/devices/",
+ deviceId));
}
GetDeviceJob::GetDeviceJob(const QString& deviceId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetDeviceJob"),
- QStringLiteral("/_matrix/client/r0") % "/devices/" % deviceId)
+ makePath("/_matrix/client/r0", "/devices/", deviceId))
{}
UpdateDeviceJob::UpdateDeviceJob(const QString& deviceId,
const QString& displayName)
: BaseJob(HttpVerb::Put, QStringLiteral("UpdateDeviceJob"),
- QStringLiteral("/_matrix/client/r0") % "/devices/" % deviceId)
+ makePath("/_matrix/client/r0", "/devices/", deviceId))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("display_name"), displayName);
@@ -45,7 +42,7 @@ UpdateDeviceJob::UpdateDeviceJob(const QString& deviceId,
DeleteDeviceJob::DeleteDeviceJob(const QString& deviceId,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"),
- QStringLiteral("/_matrix/client/r0") % "/devices/" % deviceId)
+ makePath("/_matrix/client/r0", "/devices/", deviceId))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
@@ -55,7 +52,7 @@ DeleteDeviceJob::DeleteDeviceJob(const QString& deviceId,
DeleteDevicesJob::DeleteDevicesJob(const QStringList& devices,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Post, QStringLiteral("DeleteDevicesJob"),
- QStringLiteral("/_matrix/client/r0") % "/delete_devices")
+ makePath("/_matrix/client/r0", "/delete_devices"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("devices"), devices);
diff --git a/lib/csapi/device_management.h b/lib/csapi/device_management.h
index e2acea18..7fb69873 100644
--- a/lib/csapi/device_management.h
+++ b/lib/csapi/device_management.h
@@ -59,10 +59,7 @@ public:
// Result properties
/// Device information
- Device device() const
- {
- return fromJson<Device>(jsonData());
- }
+ Device device() const { return fromJson<Device>(jsonData()); }
};
/*! \brief Update a device
diff --git a/lib/csapi/directory.cpp b/lib/csapi/directory.cpp
index 25ea82e2..b351b4ef 100644
--- a/lib/csapi/directory.cpp
+++ b/lib/csapi/directory.cpp
@@ -4,14 +4,11 @@
#include "directory.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias, const QString& roomId)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomAliasJob"),
- QStringLiteral("/_matrix/client/r0") % "/directory/room/"
- % roomAlias)
+ makePath("/_matrix/client/r0", "/directory/room/", roomAlias))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("room_id"), roomId);
@@ -21,41 +18,38 @@ SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias, const QString& roomId
QUrl GetRoomIdByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/directory/room/" % roomAlias);
+ makePath("/_matrix/client/r0",
+ "/directory/room/", roomAlias));
}
GetRoomIdByAliasJob::GetRoomIdByAliasJob(const QString& roomAlias)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomIdByAliasJob"),
- QStringLiteral("/_matrix/client/r0") % "/directory/room/"
- % roomAlias,
+ makePath("/_matrix/client/r0", "/directory/room/", roomAlias),
false)
{}
QUrl DeleteRoomAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/directory/room/" % roomAlias);
+ makePath("/_matrix/client/r0",
+ "/directory/room/", roomAlias));
}
DeleteRoomAliasJob::DeleteRoomAliasJob(const QString& roomAlias)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteRoomAliasJob"),
- QStringLiteral("/_matrix/client/r0") % "/directory/room/"
- % roomAlias)
+ makePath("/_matrix/client/r0", "/directory/room/", roomAlias))
{}
QUrl GetLocalAliasesJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/aliases");
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/aliases"));
}
GetLocalAliasesJob::GetLocalAliasesJob(const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetLocalAliasesJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/aliases")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/aliases"))
{
addExpectedKey("aliases");
}
diff --git a/lib/csapi/directory.h b/lib/csapi/directory.h
index 00215cae..93a31595 100644
--- a/lib/csapi/directory.h
+++ b/lib/csapi/directory.h
@@ -51,10 +51,7 @@ public:
// Result properties
/// The room ID for this room alias.
- QString roomId() const
- {
- return loadFromJson<QString>("room_id"_ls);
- }
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
/// A list of servers that are aware of this room alias.
QStringList servers() const
diff --git a/lib/csapi/event_context.cpp b/lib/csapi/event_context.cpp
index 3f4cd61e..877838e2 100644
--- a/lib/csapi/event_context.cpp
+++ b/lib/csapi/event_context.cpp
@@ -4,8 +4,6 @@
#include "event_context.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToGetEventContext(Omittable<int> limit, const QString& filter)
@@ -22,9 +20,8 @@ QUrl GetEventContextJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& filter)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/context/"
- % eventId,
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/context/", eventId),
queryToGetEventContext(limit, filter));
}
@@ -33,7 +30,7 @@ GetEventContextJob::GetEventContextJob(const QString& roomId,
Omittable<int> limit,
const QString& filter)
: BaseJob(HttpVerb::Get, QStringLiteral("GetEventContextJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/context/" % eventId,
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/context/",
+ eventId),
queryToGetEventContext(limit, filter))
{}
diff --git a/lib/csapi/event_context.h b/lib/csapi/event_context.h
index 6a49769f..4e50edf3 100644
--- a/lib/csapi/event_context.h
+++ b/lib/csapi/event_context.h
@@ -58,16 +58,10 @@ public:
// Result properties
/// A token that can be used to paginate backwards with.
- QString begin() const
- {
- return loadFromJson<QString>("start"_ls);
- }
+ QString begin() const { return loadFromJson<QString>("start"_ls); }
/// A token that can be used to paginate forwards with.
- QString end() const
- {
- return loadFromJson<QString>("end"_ls);
- }
+ QString end() const { return loadFromJson<QString>("end"_ls); }
/// A list of room events that happened just before the
/// requested event, in reverse-chronological order.
@@ -77,10 +71,7 @@ public:
}
/// Details of the requested event.
- RoomEventPtr event()
- {
- return takeFromJson<RoomEventPtr>("event"_ls);
- }
+ RoomEventPtr event() { return takeFromJson<RoomEventPtr>("event"_ls); }
/// A list of room events that happened just after the
/// requested event, in chronological order.
@@ -90,10 +81,7 @@ public:
}
/// The state of the room at the last event returned.
- StateEvents state()
- {
- return takeFromJson<StateEvents>("state"_ls);
- }
+ StateEvents state() { return takeFromJson<StateEvents>("state"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/filter.cpp b/lib/csapi/filter.cpp
index bb3a893f..38c68be7 100644
--- a/lib/csapi/filter.cpp
+++ b/lib/csapi/filter.cpp
@@ -4,16 +4,13 @@
#include "filter.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
DefineFilterJob::DefineFilterJob(const QString& userId, const Filter& filter)
: BaseJob(HttpVerb::Post, QStringLiteral("DefineFilterJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/filter")
+ makePath("/_matrix/client/r0", "/user/", userId, "/filter"))
{
- setRequestData(Data(toJson(filter)));
+ setRequestData(RequestData(toJson(filter)));
addExpectedKey("filter_id");
}
@@ -21,12 +18,12 @@ QUrl GetFilterJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& filterId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0") % "/user/"
- % userId % "/filter/" % filterId);
+ makePath("/_matrix/client/r0", "/user/",
+ userId, "/filter/", filterId));
}
GetFilterJob::GetFilterJob(const QString& userId, const QString& filterId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetFilterJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/filter/" % filterId)
+ makePath("/_matrix/client/r0", "/user/", userId, "/filter/",
+ filterId))
{}
diff --git a/lib/csapi/filter.h b/lib/csapi/filter.h
index 7e9e14ee..01bec36b 100644
--- a/lib/csapi/filter.h
+++ b/lib/csapi/filter.h
@@ -35,10 +35,7 @@ public:
/// with a `{` as this character is used to determine
/// if the filter provided is inline JSON or a previously
/// declared filter by homeservers on some APIs.
- QString filterId() const
- {
- return loadFromJson<QString>("filter_id"_ls);
- }
+ QString filterId() const { return loadFromJson<QString>("filter_id"_ls); }
};
/*! \brief Download a filter
@@ -67,10 +64,7 @@ public:
// Result properties
/// The filter definition.
- Filter filter() const
- {
- return fromJson<Filter>(jsonData());
- }
+ Filter filter() const { return fromJson<Filter>(jsonData()); }
};
} // namespace Quotient
diff --git a/lib/csapi/inviting.cpp b/lib/csapi/inviting.cpp
index 1e2554f4..39d24611 100644
--- a/lib/csapi/inviting.cpp
+++ b/lib/csapi/inviting.cpp
@@ -4,15 +4,12 @@
#include "inviting.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
InviteUserJob::InviteUserJob(const QString& roomId, const QString& userId,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("InviteUserJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/invite")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/invite"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp
index f5266f0b..373c1c6a 100644
--- a/lib/csapi/joining.cpp
+++ b/lib/csapi/joining.cpp
@@ -4,15 +4,13 @@
#include "joining.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
JoinRoomByIdJob::JoinRoomByIdJob(
const QString& roomId, const Omittable<ThirdPartySigned>& thirdPartySigned,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("JoinRoomByIdJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/join")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/join"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"),
@@ -34,7 +32,7 @@ JoinRoomJob::JoinRoomJob(const QString& roomIdOrAlias,
const Omittable<ThirdPartySigned>& thirdPartySigned,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("JoinRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/join/" % roomIdOrAlias,
+ makePath("/_matrix/client/r0", "/join/", roomIdOrAlias),
queryToJoinRoom(serverName))
{
QJsonObject _data;
diff --git a/lib/csapi/joining.h b/lib/csapi/joining.h
index 6dcd1351..d0199b11 100644
--- a/lib/csapi/joining.h
+++ b/lib/csapi/joining.h
@@ -49,10 +49,7 @@ public:
// Result properties
/// The joined room ID.
- QString roomId() const
- {
- return loadFromJson<QString>("room_id"_ls);
- }
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
};
/*! \brief Start the requesting user participating in a particular room.
@@ -98,10 +95,7 @@ public:
// Result properties
/// The joined room ID.
- QString roomId() const
- {
- return loadFromJson<QString>("room_id"_ls);
- }
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/keys.cpp b/lib/csapi/keys.cpp
index ba5d8e12..d6bd2fab 100644
--- a/lib/csapi/keys.cpp
+++ b/lib/csapi/keys.cpp
@@ -4,14 +4,12 @@
#include "keys.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
UploadKeysJob::UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys,
const QHash<QString, QVariant>& oneTimeKeys)
: BaseJob(HttpVerb::Post, QStringLiteral("UploadKeysJob"),
- QStringLiteral("/_matrix/client/r0") % "/keys/upload")
+ makePath("/_matrix/client/r0", "/keys/upload"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("device_keys"), deviceKeys);
@@ -23,7 +21,7 @@ UploadKeysJob::UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys,
QueryKeysJob::QueryKeysJob(const QHash<QString, QStringList>& deviceKeys,
Omittable<int> timeout, const QString& token)
: BaseJob(HttpVerb::Post, QStringLiteral("QueryKeysJob"),
- QStringLiteral("/_matrix/client/r0") % "/keys/query")
+ makePath("/_matrix/client/r0", "/keys/query"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
@@ -36,7 +34,7 @@ ClaimKeysJob::ClaimKeysJob(
const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
Omittable<int> timeout)
: BaseJob(HttpVerb::Post, QStringLiteral("ClaimKeysJob"),
- QStringLiteral("/_matrix/client/r0") % "/keys/claim")
+ makePath("/_matrix/client/r0", "/keys/claim"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
@@ -57,13 +55,13 @@ QUrl GetKeysChangesJob::makeRequestUrl(QUrl baseUrl, const QString& from,
const QString& to)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/keys/changes",
+ makePath("/_matrix/client/r0",
+ "/keys/changes"),
queryToGetKeysChanges(from, to));
}
GetKeysChangesJob::GetKeysChangesJob(const QString& from, const QString& to)
: BaseJob(HttpVerb::Get, QStringLiteral("GetKeysChangesJob"),
- QStringLiteral("/_matrix/client/r0") % "/keys/changes",
+ makePath("/_matrix/client/r0", "/keys/changes"),
queryToGetKeysChanges(from, to))
{}
diff --git a/lib/csapi/keys.h b/lib/csapi/keys.h
index 53ba6495..7db09e8d 100644
--- a/lib/csapi/keys.h
+++ b/lib/csapi/keys.h
@@ -267,10 +267,7 @@ public:
/// The Matrix User IDs of all users who may have left all
/// the end-to-end encrypted rooms they previously shared
/// with the user.
- QStringList left() const
- {
- return loadFromJson<QStringList>("left"_ls);
- }
+ QStringList left() const { return loadFromJson<QStringList>("left"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/kicking.cpp b/lib/csapi/kicking.cpp
index 7de5ce01..433e592c 100644
--- a/lib/csapi/kicking.cpp
+++ b/lib/csapi/kicking.cpp
@@ -4,14 +4,12 @@
#include "kicking.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
KickJob::KickJob(const QString& roomId, const QString& userId,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("KickJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/kick")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/kick"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
diff --git a/lib/csapi/knocking.cpp b/lib/csapi/knocking.cpp
index 788bb378..73e13e6e 100644
--- a/lib/csapi/knocking.cpp
+++ b/lib/csapi/knocking.cpp
@@ -4,8 +4,6 @@
#include "knocking.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToKnockRoom(const QStringList& serverName)
@@ -18,7 +16,7 @@ auto queryToKnockRoom(const QStringList& serverName)
KnockRoomJob::KnockRoomJob(const QString& roomIdOrAlias,
const QStringList& serverName, const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("KnockRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/knock/" % roomIdOrAlias,
+ makePath("/_matrix/client/r0", "/knock/", roomIdOrAlias),
queryToKnockRoom(serverName))
{
QJsonObject _data;
diff --git a/lib/csapi/knocking.h b/lib/csapi/knocking.h
index 607b55a9..1108cb64 100644
--- a/lib/csapi/knocking.h
+++ b/lib/csapi/knocking.h
@@ -49,10 +49,7 @@ public:
// Result properties
/// The knocked room ID.
- QString roomId() const
- {
- return loadFromJson<QString>("room_id"_ls);
- }
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/leaving.cpp b/lib/csapi/leaving.cpp
index f4c5f120..0e5386be 100644
--- a/lib/csapi/leaving.cpp
+++ b/lib/csapi/leaving.cpp
@@ -4,14 +4,11 @@
#include "leaving.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
LeaveRoomJob::LeaveRoomJob(const QString& roomId, const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("LeaveRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/leave")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/leave"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason);
@@ -21,12 +18,11 @@ LeaveRoomJob::LeaveRoomJob(const QString& roomId, const QString& reason)
QUrl ForgetRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/forget");
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/forget"));
}
ForgetRoomJob::ForgetRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Post, QStringLiteral("ForgetRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/forget")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/forget"))
{}
diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp
index 8d7e267f..22ba04da 100644
--- a/lib/csapi/list_joined_rooms.cpp
+++ b/lib/csapi/list_joined_rooms.cpp
@@ -4,20 +4,17 @@
#include "list_joined_rooms.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetJoinedRoomsJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/joined_rooms");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/joined_rooms"));
}
GetJoinedRoomsJob::GetJoinedRoomsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetJoinedRoomsJob"),
- QStringLiteral("/_matrix/client/r0") % "/joined_rooms")
+ makePath("/_matrix/client/r0", "/joined_rooms"))
{
addExpectedKey("joined_rooms");
}
diff --git a/lib/csapi/list_public_rooms.cpp b/lib/csapi/list_public_rooms.cpp
index a4bcb934..25f8da5c 100644
--- a/lib/csapi/list_public_rooms.cpp
+++ b/lib/csapi/list_public_rooms.cpp
@@ -4,31 +4,27 @@
#include "list_public_rooms.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetRoomVisibilityOnDirectoryJob::makeRequestUrl(QUrl baseUrl,
const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/directory/list/room/" % roomId);
+ makePath("/_matrix/client/r0",
+ "/directory/list/room/", roomId));
}
GetRoomVisibilityOnDirectoryJob::GetRoomVisibilityOnDirectoryJob(
const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomVisibilityOnDirectoryJob"),
- QStringLiteral("/_matrix/client/r0") % "/directory/list/room/"
- % roomId,
+ makePath("/_matrix/client/r0", "/directory/list/room/", roomId),
false)
{}
SetRoomVisibilityOnDirectoryJob::SetRoomVisibilityOnDirectoryJob(
const QString& roomId, const QString& visibility)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomVisibilityOnDirectoryJob"),
- QStringLiteral("/_matrix/client/r0") % "/directory/list/room/"
- % roomId)
+ makePath("/_matrix/client/r0", "/directory/list/room/", roomId))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility);
@@ -50,15 +46,15 @@ QUrl GetPublicRoomsJob::makeRequestUrl(QUrl baseUrl, Omittable<int> limit,
const QString& server)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/publicRooms",
+ makePath("/_matrix/client/r0",
+ "/publicRooms"),
queryToGetPublicRooms(limit, since, server));
}
GetPublicRoomsJob::GetPublicRoomsJob(Omittable<int> limit, const QString& since,
const QString& server)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPublicRoomsJob"),
- QStringLiteral("/_matrix/client/r0") % "/publicRooms",
+ makePath("/_matrix/client/r0", "/publicRooms"),
queryToGetPublicRooms(limit, since, server), {}, false)
{
addExpectedKey("chunk");
@@ -78,7 +74,7 @@ QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server,
Omittable<bool> includeAllNetworks,
const QString& thirdPartyInstanceId)
: BaseJob(HttpVerb::Post, QStringLiteral("QueryPublicRoomsJob"),
- QStringLiteral("/_matrix/client/r0") % "/publicRooms",
+ makePath("/_matrix/client/r0", "/publicRooms"),
queryToQueryPublicRooms(server))
{
QJsonObject _data;
diff --git a/lib/csapi/list_public_rooms.h b/lib/csapi/list_public_rooms.h
index 1c73c0af..963c8b56 100644
--- a/lib/csapi/list_public_rooms.h
+++ b/lib/csapi/list_public_rooms.h
@@ -111,18 +111,12 @@ public:
/// A pagination token for the response. The absence of this token
/// means there are no more results to fetch and the client should
/// stop paginating.
- QString nextBatch() const
- {
- return loadFromJson<QString>("next_batch"_ls);
- }
+ QString nextBatch() const { return loadFromJson<QString>("next_batch"_ls); }
/// A pagination token that allows fetching previous results. The
/// absence of this token means there are no results before this
/// batch, i.e. this is the first batch.
- QString prevBatch() const
- {
- return loadFromJson<QString>("prev_batch"_ls);
- }
+ QString prevBatch() const { return loadFromJson<QString>("prev_batch"_ls); }
/// An estimate on the total number of public rooms, if the
/// server has an estimate.
@@ -196,18 +190,12 @@ public:
/// A pagination token for the response. The absence of this token
/// means there are no more results to fetch and the client should
/// stop paginating.
- QString nextBatch() const
- {
- return loadFromJson<QString>("next_batch"_ls);
- }
+ QString nextBatch() const { return loadFromJson<QString>("next_batch"_ls); }
/// A pagination token that allows fetching previous results. The
/// absence of this token means there are no results before this
/// batch, i.e. this is the first batch.
- QString prevBatch() const
- {
- return loadFromJson<QString>("prev_batch"_ls);
- }
+ QString prevBatch() const { return loadFromJson<QString>("prev_batch"_ls); }
/// An estimate on the total number of public rooms, if the
/// server has an estimate.
diff --git a/lib/csapi/login.cpp b/lib/csapi/login.cpp
index a5bac9ea..71fd93c5 100644
--- a/lib/csapi/login.cpp
+++ b/lib/csapi/login.cpp
@@ -4,20 +4,17 @@
#include "login.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetLoginFlowsJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/login");
+ makePath("/_matrix/client/r0", "/login"));
}
GetLoginFlowsJob::GetLoginFlowsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetLoginFlowsJob"),
- QStringLiteral("/_matrix/client/r0") % "/login", false)
+ makePath("/_matrix/client/r0", "/login"), false)
{}
LoginJob::LoginJob(const QString& type,
@@ -26,7 +23,7 @@ LoginJob::LoginJob(const QString& type,
const QString& deviceId,
const QString& initialDeviceDisplayName)
: BaseJob(HttpVerb::Post, QStringLiteral("LoginJob"),
- QStringLiteral("/_matrix/client/r0") % "/login", false)
+ makePath("/_matrix/client/r0", "/login"), false)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("type"), type);
diff --git a/lib/csapi/login.h b/lib/csapi/login.h
index ce783af2..b35db1eb 100644
--- a/lib/csapi/login.h
+++ b/lib/csapi/login.h
@@ -121,10 +121,7 @@ public:
// Result properties
/// The fully-qualified Matrix ID for the account.
- QString userId() const
- {
- return loadFromJson<QString>("user_id"_ls);
- }
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
/// An access token for the account.
/// This access token can then be used to authorize other requests.
@@ -146,10 +143,7 @@ public:
/// ID of the logged-in device. Will be the same as the
/// corresponding parameter in the request, if one was specified.
- QString deviceId() const
- {
- return loadFromJson<QString>("device_id"_ls);
- }
+ QString deviceId() const { return loadFromJson<QString>("device_id"_ls); }
/// Optional client configuration provided by the server. If present,
/// clients SHOULD use the provided object to reconfigure themselves,
diff --git a/lib/csapi/logout.cpp b/lib/csapi/logout.cpp
index 9583b8ec..e8083e31 100644
--- a/lib/csapi/logout.cpp
+++ b/lib/csapi/logout.cpp
@@ -4,30 +4,26 @@
#include "logout.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl LogoutJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/logout");
+ makePath("/_matrix/client/r0", "/logout"));
}
LogoutJob::LogoutJob()
: BaseJob(HttpVerb::Post, QStringLiteral("LogoutJob"),
- QStringLiteral("/_matrix/client/r0") % "/logout")
+ makePath("/_matrix/client/r0", "/logout"))
{}
QUrl LogoutAllJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/logout/all");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/logout/all"));
}
LogoutAllJob::LogoutAllJob()
: BaseJob(HttpVerb::Post, QStringLiteral("LogoutAllJob"),
- QStringLiteral("/_matrix/client/r0") % "/logout/all")
+ makePath("/_matrix/client/r0", "/logout/all"))
{}
diff --git a/lib/csapi/message_pagination.cpp b/lib/csapi/message_pagination.cpp
index 441e4dea..1a93b75b 100644
--- a/lib/csapi/message_pagination.cpp
+++ b/lib/csapi/message_pagination.cpp
@@ -4,8 +4,6 @@
#include "message_pagination.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToGetRoomEvents(const QString& from, const QString& to,
@@ -28,7 +26,7 @@ QUrl GetRoomEventsJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
{
return BaseJob::makeRequestUrl(
std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/messages",
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/messages"),
queryToGetRoomEvents(from, to, dir, limit, filter));
}
@@ -36,7 +34,6 @@ GetRoomEventsJob::GetRoomEventsJob(const QString& roomId, const QString& from,
const QString& dir, const QString& to,
Omittable<int> limit, const QString& filter)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomEventsJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/messages",
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/messages"),
queryToGetRoomEvents(from, to, dir, limit, filter))
{}
diff --git a/lib/csapi/message_pagination.h b/lib/csapi/message_pagination.h
index 020ef543..363e4d99 100644
--- a/lib/csapi/message_pagination.h
+++ b/lib/csapi/message_pagination.h
@@ -66,26 +66,17 @@ public:
/// The token the pagination starts from. If `dir=b` this will be
/// the token supplied in `from`.
- QString begin() const
- {
- return loadFromJson<QString>("start"_ls);
- }
+ QString begin() const { return loadFromJson<QString>("start"_ls); }
/// The token the pagination ends at. If `dir=b` this token should
/// be used again to request even earlier events.
- QString end() const
- {
- return loadFromJson<QString>("end"_ls);
- }
+ QString end() const { return loadFromJson<QString>("end"_ls); }
/// A list of room events. The order depends on the `dir` parameter.
/// For `dir=b` events will be in reverse-chronological order,
/// for `dir=f` in chronological order, so that events start
/// at the `from` point.
- RoomEvents chunk()
- {
- return takeFromJson<RoomEvents>("chunk"_ls);
- }
+ RoomEvents chunk() { return takeFromJson<RoomEvents>("chunk"_ls); }
/// A list of state events relevant to showing the `chunk`. For example, if
/// `lazy_load_members` is enabled in the filter then this may contain
@@ -95,10 +86,7 @@ public:
/// may remove membership events which would have already been
/// sent to the client in prior calls to this endpoint, assuming
/// the membership of those members has not changed.
- StateEvents state()
- {
- return takeFromJson<StateEvents>("state"_ls);
- }
+ StateEvents state() { return takeFromJson<StateEvents>("state"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/notifications.cpp b/lib/csapi/notifications.cpp
index a38e46f5..1e523c6f 100644
--- a/lib/csapi/notifications.cpp
+++ b/lib/csapi/notifications.cpp
@@ -4,8 +4,6 @@
#include "notifications.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToGetNotifications(const QString& from, Omittable<int> limit,
@@ -23,8 +21,8 @@ QUrl GetNotificationsJob::makeRequestUrl(QUrl baseUrl, const QString& from,
const QString& only)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/notifications",
+ makePath("/_matrix/client/r0",
+ "/notifications"),
queryToGetNotifications(from, limit, only));
}
@@ -32,7 +30,7 @@ GetNotificationsJob::GetNotificationsJob(const QString& from,
Omittable<int> limit,
const QString& only)
: BaseJob(HttpVerb::Get, QStringLiteral("GetNotificationsJob"),
- QStringLiteral("/_matrix/client/r0") % "/notifications",
+ makePath("/_matrix/client/r0", "/notifications"),
queryToGetNotifications(from, limit, only))
{
addExpectedKey("notifications");
diff --git a/lib/csapi/notifications.h b/lib/csapi/notifications.h
index 0cc165ce..0c38fe6b 100644
--- a/lib/csapi/notifications.h
+++ b/lib/csapi/notifications.h
@@ -71,10 +71,7 @@ public:
/// The token to supply in the `from` param of the next
/// `/notifications` request in order to request more
/// events. If this is absent, there are no more results.
- QString nextToken() const
- {
- return loadFromJson<QString>("next_token"_ls);
- }
+ QString nextToken() const { return loadFromJson<QString>("next_token"_ls); }
/// The list of events that triggered notifications.
std::vector<Notification> notifications()
diff --git a/lib/csapi/openid.cpp b/lib/csapi/openid.cpp
index 3941e9c0..5c93a2d7 100644
--- a/lib/csapi/openid.cpp
+++ b/lib/csapi/openid.cpp
@@ -4,15 +4,13 @@
#include "openid.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
RequestOpenIdTokenJob::RequestOpenIdTokenJob(const QString& userId,
const QJsonObject& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestOpenIdTokenJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/openid/request_token")
+ makePath("/_matrix/client/r0", "/user/", userId,
+ "/openid/request_token"))
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
diff --git a/lib/csapi/openid.h b/lib/csapi/openid.h
index 88218c20..0be39c8c 100644
--- a/lib/csapi/openid.h
+++ b/lib/csapi/openid.h
@@ -43,10 +43,7 @@ public:
/// Specification](http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse)
/// with the only difference being the lack of an `id_token`. Instead,
/// the Matrix homeserver's name is provided.
- OpenidToken tokenData() const
- {
- return fromJson<OpenidToken>(jsonData());
- }
+ OpenidToken tokenData() const { return fromJson<OpenidToken>(jsonData()); }
};
} // namespace Quotient
diff --git a/lib/csapi/peeking_events.cpp b/lib/csapi/peeking_events.cpp
index ad2f9afe..eb5d22fa 100644
--- a/lib/csapi/peeking_events.cpp
+++ b/lib/csapi/peeking_events.cpp
@@ -4,8 +4,6 @@
#include "peeking_events.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToPeekEvents(const QString& from, Omittable<int> timeout,
@@ -22,14 +20,13 @@ QUrl PeekEventsJob::makeRequestUrl(QUrl baseUrl, const QString& from,
Omittable<int> timeout, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/events",
+ makePath("/_matrix/client/r0", "/events"),
queryToPeekEvents(from, timeout, roomId));
}
PeekEventsJob::PeekEventsJob(const QString& from, Omittable<int> timeout,
const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("PeekEventsJob"),
- QStringLiteral("/_matrix/client/r0") % "/events",
+ makePath("/_matrix/client/r0", "/events"),
queryToPeekEvents(from, timeout, roomId))
{}
diff --git a/lib/csapi/peeking_events.h b/lib/csapi/peeking_events.h
index 1eee880f..885ff340 100644
--- a/lib/csapi/peeking_events.h
+++ b/lib/csapi/peeking_events.h
@@ -53,23 +53,14 @@ public:
/// A token which correlates to the first value in `chunk`. This
/// is usually the same token supplied to `from=`.
- QString begin() const
- {
- return loadFromJson<QString>("start"_ls);
- }
+ QString begin() const { return loadFromJson<QString>("start"_ls); }
/// A token which correlates to the last value in `chunk`. This
/// token should be used in the next request to `/events`.
- QString end() const
- {
- return loadFromJson<QString>("end"_ls);
- }
+ QString end() const { return loadFromJson<QString>("end"_ls); }
/// An array of events.
- RoomEvents chunk()
- {
- return takeFromJson<RoomEvents>("chunk"_ls);
- }
+ RoomEvents chunk() { return takeFromJson<RoomEvents>("chunk"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/presence.cpp b/lib/csapi/presence.cpp
index 58d0d157..4f77c466 100644
--- a/lib/csapi/presence.cpp
+++ b/lib/csapi/presence.cpp
@@ -4,15 +4,12 @@
#include "presence.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetPresenceJob::SetPresenceJob(const QString& userId, const QString& presence,
const QString& statusMsg)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPresenceJob"),
- QStringLiteral("/_matrix/client/r0") % "/presence/" % userId
- % "/status")
+ makePath("/_matrix/client/r0", "/presence/", userId, "/status"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("presence"), presence);
@@ -23,14 +20,13 @@ SetPresenceJob::SetPresenceJob(const QString& userId, const QString& presence,
QUrl GetPresenceJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/presence/" % userId % "/status");
+ makePath("/_matrix/client/r0", "/presence/",
+ userId, "/status"));
}
GetPresenceJob::GetPresenceJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPresenceJob"),
- QStringLiteral("/_matrix/client/r0") % "/presence/" % userId
- % "/status")
+ makePath("/_matrix/client/r0", "/presence/", userId, "/status"))
{
addExpectedKey("presence");
}
diff --git a/lib/csapi/presence.h b/lib/csapi/presence.h
index c817ad9f..4ab50e25 100644
--- a/lib/csapi/presence.h
+++ b/lib/csapi/presence.h
@@ -55,10 +55,7 @@ public:
// Result properties
/// This user's presence.
- QString presence() const
- {
- return loadFromJson<QString>("presence"_ls);
- }
+ QString presence() const { return loadFromJson<QString>("presence"_ls); }
/// The length of time in milliseconds since an action was performed
/// by this user.
@@ -68,10 +65,7 @@ public:
}
/// The state message for this user if one was set.
- QString statusMsg() const
- {
- return loadFromJson<QString>("status_msg"_ls);
- }
+ QString statusMsg() const { return loadFromJson<QString>("status_msg"_ls); }
/// Whether the user is currently active
Omittable<bool> currentlyActive() const
diff --git a/lib/csapi/profile.cpp b/lib/csapi/profile.cpp
index 8436b8e6..64ac84ca 100644
--- a/lib/csapi/profile.cpp
+++ b/lib/csapi/profile.cpp
@@ -4,15 +4,12 @@
#include "profile.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetDisplayNameJob::SetDisplayNameJob(const QString& userId,
const QString& displayname)
: BaseJob(HttpVerb::Put, QStringLiteral("SetDisplayNameJob"),
- QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
- % "/displayname")
+ makePath("/_matrix/client/r0", "/profile/", userId, "/displayname"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("displayname"), displayname);
@@ -22,21 +19,19 @@ SetDisplayNameJob::SetDisplayNameJob(const QString& userId,
QUrl GetDisplayNameJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/profile/" % userId % "/displayname");
+ makePath("/_matrix/client/r0", "/profile/",
+ userId, "/displayname"));
}
GetDisplayNameJob::GetDisplayNameJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetDisplayNameJob"),
- QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
- % "/displayname",
+ makePath("/_matrix/client/r0", "/profile/", userId, "/displayname"),
false)
{}
-SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId, const QString& avatarUrl)
+SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId, const QUrl& avatarUrl)
: BaseJob(HttpVerb::Put, QStringLiteral("SetAvatarUrlJob"),
- QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
- % "/avatar_url")
+ makePath("/_matrix/client/r0", "/profile/", userId, "/avatar_url"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("avatar_url"), avatarUrl);
@@ -46,25 +41,24 @@ SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId, const QString& avatarUrl
QUrl GetAvatarUrlJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/profile/" % userId % "/avatar_url");
+ makePath("/_matrix/client/r0", "/profile/",
+ userId, "/avatar_url"));
}
GetAvatarUrlJob::GetAvatarUrlJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetAvatarUrlJob"),
- QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
- % "/avatar_url",
+ makePath("/_matrix/client/r0", "/profile/", userId, "/avatar_url"),
false)
{}
QUrl GetUserProfileJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/profile/" % userId);
+ makePath("/_matrix/client/r0", "/profile/",
+ userId));
}
GetUserProfileJob::GetUserProfileJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetUserProfileJob"),
- QStringLiteral("/_matrix/client/r0") % "/profile/" % userId, false)
+ makePath("/_matrix/client/r0", "/profile/", userId), false)
{}
diff --git a/lib/csapi/profile.h b/lib/csapi/profile.h
index 3cda34f8..7f9c9e95 100644
--- a/lib/csapi/profile.h
+++ b/lib/csapi/profile.h
@@ -73,7 +73,7 @@ public:
* \param avatarUrl
* The new avatar URL for this user.
*/
- explicit SetAvatarUrlJob(const QString& userId, const QString& avatarUrl);
+ explicit SetAvatarUrlJob(const QString& userId, const QUrl& avatarUrl);
};
/*! \brief Get the user's avatar URL.
@@ -101,10 +101,7 @@ public:
// Result properties
/// The user's avatar URL if they have set one, otherwise not present.
- QString avatarUrl() const
- {
- return loadFromJson<QString>("avatar_url"_ls);
- }
+ QUrl avatarUrl() const { return loadFromJson<QUrl>("avatar_url"_ls); }
};
/*! \brief Get this user's profile information.
@@ -133,10 +130,7 @@ public:
// Result properties
/// The user's avatar URL if they have set one, otherwise not present.
- QString avatarUrl() const
- {
- return loadFromJson<QString>("avatar_url"_ls);
- }
+ QUrl avatarUrl() const { return loadFromJson<QUrl>("avatar_url"_ls); }
/// The user's display name if they have set one, otherwise not present.
QString displayname() const
diff --git a/lib/csapi/pusher.cpp b/lib/csapi/pusher.cpp
index 028022c5..ef4b3767 100644
--- a/lib/csapi/pusher.cpp
+++ b/lib/csapi/pusher.cpp
@@ -4,20 +4,17 @@
#include "pusher.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetPushersJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/pushers");
+ makePath("/_matrix/client/r0", "/pushers"));
}
GetPushersJob::GetPushersJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushersJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushers")
+ makePath("/_matrix/client/r0", "/pushers"))
{}
PostPusherJob::PostPusherJob(const QString& pushkey, const QString& kind,
@@ -26,7 +23,7 @@ PostPusherJob::PostPusherJob(const QString& pushkey, const QString& kind,
const QString& lang, const PusherData& data,
const QString& profileTag, Omittable<bool> append)
: BaseJob(HttpVerb::Post, QStringLiteral("PostPusherJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushers/set")
+ makePath("/_matrix/client/r0", "/pushers/set"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("pushkey"), pushkey);
diff --git a/lib/csapi/pusher.h b/lib/csapi/pusher.h
index 13c9ec25..622b0df6 100644
--- a/lib/csapi/pusher.h
+++ b/lib/csapi/pusher.h
@@ -21,7 +21,7 @@ public:
struct PusherData {
/// Required if `kind` is `http`. The URL to use to send
/// notifications to.
- QString url;
+ QUrl url;
/// The format to use when sending notifications to the Push
/// Gateway.
QString format;
@@ -119,7 +119,7 @@ public:
/// Required if `kind` is `http`. The URL to use to send
/// notifications to. MUST be an HTTPS URL with a path of
/// `/_matrix/push/v1/notify`.
- QString url;
+ QUrl url;
/// The format to send notifications in to Push Gateways if the
/// `kind` is `http`. The details about what fields the
/// homeserver should send to the push gateway are defined in the
diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp
index ab7d0038..0d840788 100644
--- a/lib/csapi/pushrules.cpp
+++ b/lib/csapi/pushrules.cpp
@@ -4,20 +4,17 @@
#include "pushrules.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetPushRulesJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/pushrules");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/pushrules"));
}
GetPushRulesJob::GetPushRulesJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushRulesJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules")
+ makePath("/_matrix/client/r0", "/pushrules"))
{
addExpectedKey("global");
}
@@ -26,16 +23,15 @@ QUrl GetPushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind, const QString& ruleId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId);
+ makePath("/_matrix/client/r0", "/pushrules/",
+ scope, "/", kind, "/", ruleId));
}
GetPushRuleJob::GetPushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushRuleJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId)
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId))
{}
QUrl DeletePushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
@@ -43,16 +39,15 @@ QUrl DeletePushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& ruleId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId);
+ makePath("/_matrix/client/r0", "/pushrules/",
+ scope, "/", kind, "/", ruleId));
}
DeletePushRuleJob::DeletePushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeletePushRuleJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId)
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId))
{}
auto queryToSetPushRule(const QString& before, const QString& after)
@@ -70,8 +65,8 @@ SetPushRuleJob::SetPushRuleJob(const QString& scope, const QString& kind,
const QVector<PushCondition>& conditions,
const QString& pattern)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPushRuleJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId,
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId),
queryToSetPushRule(before, after))
{
QJsonObject _data;
@@ -86,17 +81,17 @@ QUrl IsPushRuleEnabledJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& ruleId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId % "/enabled");
+ makePath("/_matrix/client/r0", "/pushrules/",
+ scope, "/", kind, "/", ruleId,
+ "/enabled"));
}
IsPushRuleEnabledJob::IsPushRuleEnabledJob(const QString& scope,
const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, QStringLiteral("IsPushRuleEnabledJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId % "/enabled")
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId, "/enabled"))
{
addExpectedKey("enabled");
}
@@ -105,8 +100,8 @@ SetPushRuleEnabledJob::SetPushRuleEnabledJob(const QString& scope,
const QString& kind,
const QString& ruleId, bool enabled)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPushRuleEnabledJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId % "/enabled")
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId, "/enabled"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("enabled"), enabled);
@@ -118,17 +113,17 @@ QUrl GetPushRuleActionsJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& ruleId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId % "/actions");
+ makePath("/_matrix/client/r0", "/pushrules/",
+ scope, "/", kind, "/", ruleId,
+ "/actions"));
}
GetPushRuleActionsJob::GetPushRuleActionsJob(const QString& scope,
const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushRuleActionsJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId % "/actions")
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId, "/actions"))
{
addExpectedKey("actions");
}
@@ -138,8 +133,8 @@ SetPushRuleActionsJob::SetPushRuleActionsJob(const QString& scope,
const QString& ruleId,
const QVector<QVariant>& actions)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPushRuleActionsJob"),
- QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
- % kind % "/" % ruleId % "/actions")
+ makePath("/_matrix/client/r0", "/pushrules/", scope, "/", kind,
+ "/", ruleId, "/actions"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("actions"), actions);
diff --git a/lib/csapi/pushrules.h b/lib/csapi/pushrules.h
index 90d2ce79..a5eb48f0 100644
--- a/lib/csapi/pushrules.h
+++ b/lib/csapi/pushrules.h
@@ -72,10 +72,7 @@ public:
/// The specific push rule. This will also include keys specific to the
/// rule itself such as the rule's `actions` and `conditions` if set.
- PushRule pushRule() const
- {
- return fromJson<PushRule>(jsonData());
- }
+ PushRule pushRule() const { return fromJson<PushRule>(jsonData()); }
};
/*! \brief Delete a push rule.
@@ -191,10 +188,7 @@ public:
// Result properties
/// Whether the push rule is enabled or not.
- bool enabled() const
- {
- return loadFromJson<bool>("enabled"_ls);
- }
+ bool enabled() const { return loadFromJson<bool>("enabled"_ls); }
};
/*! \brief Enable or disable a push rule.
diff --git a/lib/csapi/read_markers.cpp b/lib/csapi/read_markers.cpp
index 39e4d148..f2edb71e 100644
--- a/lib/csapi/read_markers.cpp
+++ b/lib/csapi/read_markers.cpp
@@ -4,16 +4,13 @@
#include "read_markers.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetReadMarkerJob::SetReadMarkerJob(const QString& roomId,
const QString& mFullyRead,
const QString& mRead)
: BaseJob(HttpVerb::Post, QStringLiteral("SetReadMarkerJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/read_markers")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/read_markers"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("m.fully_read"), mFullyRead);
diff --git a/lib/csapi/receipts.cpp b/lib/csapi/receipts.cpp
index 00d1c28a..401c3bfe 100644
--- a/lib/csapi/receipts.cpp
+++ b/lib/csapi/receipts.cpp
@@ -4,16 +4,14 @@
#include "receipts.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
PostReceiptJob::PostReceiptJob(const QString& roomId, const QString& receiptType,
const QString& eventId,
const QJsonObject& receipt)
: BaseJob(HttpVerb::Post, QStringLiteral("PostReceiptJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/receipt/" % receiptType % "/" % eventId)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/receipt/",
+ receiptType, "/", eventId))
{
- setRequestData(Data(toJson(receipt)));
+ setRequestData(RequestData(toJson(receipt)));
}
diff --git a/lib/csapi/redaction.cpp b/lib/csapi/redaction.cpp
index 91497064..acf1b0e4 100644
--- a/lib/csapi/redaction.cpp
+++ b/lib/csapi/redaction.cpp
@@ -4,15 +4,13 @@
#include "redaction.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
RedactEventJob::RedactEventJob(const QString& roomId, const QString& eventId,
const QString& txnId, const QString& reason)
: BaseJob(HttpVerb::Put, QStringLiteral("RedactEventJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/redact/" % eventId % "/" % txnId)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/redact/",
+ eventId, "/", txnId))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason);
diff --git a/lib/csapi/redaction.h b/lib/csapi/redaction.h
index f12e6b71..f0db9f9f 100644
--- a/lib/csapi/redaction.h
+++ b/lib/csapi/redaction.h
@@ -46,10 +46,7 @@ public:
// Result properties
/// A unique identifier for the event.
- QString eventId() const
- {
- return loadFromJson<QString>("event_id"_ls);
- }
+ QString eventId() const { return loadFromJson<QString>("event_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp
index 38649e63..153abcee 100644
--- a/lib/csapi/registration.cpp
+++ b/lib/csapi/registration.cpp
@@ -4,8 +4,6 @@
#include "registration.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToRegister(const QString& kind)
@@ -22,7 +20,7 @@ RegisterJob::RegisterJob(const QString& kind,
const QString& initialDeviceDisplayName,
Omittable<bool> inhibitLogin)
: BaseJob(HttpVerb::Post, QStringLiteral("RegisterJob"),
- QStringLiteral("/_matrix/client/r0") % "/register",
+ makePath("/_matrix/client/r0", "/register"),
queryToRegister(kind), {}, false)
{
QJsonObject _data;
@@ -40,28 +38,26 @@ RegisterJob::RegisterJob(const QString& kind,
RequestTokenToRegisterEmailJob::RequestTokenToRegisterEmailJob(
const EmailValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenToRegisterEmailJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/register/email/requestToken",
+ makePath("/_matrix/client/r0", "/register/email/requestToken"),
false)
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
RequestTokenToRegisterMSISDNJob::RequestTokenToRegisterMSISDNJob(
const MsisdnValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenToRegisterMSISDNJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/register/msisdn/requestToken",
+ makePath("/_matrix/client/r0", "/register/msisdn/requestToken"),
false)
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
ChangePasswordJob::ChangePasswordJob(const QString& newPassword,
bool logoutDevices,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/password")
+ makePath("/_matrix/client/r0", "/account/password"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("new_password"), newPassword);
@@ -74,28 +70,28 @@ RequestTokenToResetPasswordEmailJob::RequestTokenToResetPasswordEmailJob(
const EmailValidationData& body)
: BaseJob(HttpVerb::Post,
QStringLiteral("RequestTokenToResetPasswordEmailJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/account/password/email/requestToken",
+ makePath("/_matrix/client/r0",
+ "/account/password/email/requestToken"),
false)
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
RequestTokenToResetPasswordMSISDNJob::RequestTokenToResetPasswordMSISDNJob(
const MsisdnValidationData& body)
: BaseJob(HttpVerb::Post,
QStringLiteral("RequestTokenToResetPasswordMSISDNJob"),
- QStringLiteral("/_matrix/client/r0")
- % "/account/password/msisdn/requestToken",
+ makePath("/_matrix/client/r0",
+ "/account/password/msisdn/requestToken"),
false)
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
}
DeactivateAccountJob::DeactivateAccountJob(
const Omittable<AuthenticationData>& auth, const QString& idServer)
: BaseJob(HttpVerb::Post, QStringLiteral("DeactivateAccountJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/deactivate")
+ makePath("/_matrix/client/r0", "/account/deactivate"))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
@@ -115,13 +111,13 @@ QUrl CheckUsernameAvailabilityJob::makeRequestUrl(QUrl baseUrl,
const QString& username)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/register/available",
+ makePath("/_matrix/client/r0",
+ "/register/available"),
queryToCheckUsernameAvailability(username));
}
CheckUsernameAvailabilityJob::CheckUsernameAvailabilityJob(const QString& username)
: BaseJob(HttpVerb::Get, QStringLiteral("CheckUsernameAvailabilityJob"),
- QStringLiteral("/_matrix/client/r0") % "/register/available",
+ makePath("/_matrix/client/r0", "/register/available"),
queryToCheckUsernameAvailability(username), {}, false)
{}
diff --git a/lib/csapi/registration.h b/lib/csapi/registration.h
index 0ad8b101..c1614f20 100644
--- a/lib/csapi/registration.h
+++ b/lib/csapi/registration.h
@@ -108,10 +108,7 @@ public:
///
/// Any user ID returned by this API must conform to the grammar given in
/// the [Matrix specification](/appendices/#user-identifiers).
- QString userId() const
- {
- return loadFromJson<QString>("user_id"_ls);
- }
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
/// An access token for the account.
/// This access token can then be used to authorize other requests.
@@ -135,10 +132,7 @@ public:
/// ID of the registered device. Will be the same as the
/// corresponding parameter in the request, if one was specified.
/// Required if the `inhibit_login` option is false.
- QString deviceId() const
- {
- return loadFromJson<QString>("device_id"_ls);
- }
+ QString deviceId() const { return loadFromJson<QString>("device_id"_ls); }
};
/*! \brief Begins the validation process for an email to be used during
diff --git a/lib/csapi/report_content.cpp b/lib/csapi/report_content.cpp
index ea906380..0a76d5b8 100644
--- a/lib/csapi/report_content.cpp
+++ b/lib/csapi/report_content.cpp
@@ -4,15 +4,13 @@
#include "report_content.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
ReportContentJob::ReportContentJob(const QString& roomId, const QString& eventId,
Omittable<int> score, const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("ReportContentJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/report/" % eventId)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/report/",
+ eventId))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("score"), score);
diff --git a/lib/csapi/room_send.cpp b/lib/csapi/room_send.cpp
index 63986c56..f80f9300 100644
--- a/lib/csapi/room_send.cpp
+++ b/lib/csapi/room_send.cpp
@@ -4,16 +4,14 @@
#include "room_send.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SendMessageJob::SendMessageJob(const QString& roomId, const QString& eventType,
const QString& txnId, const QJsonObject& body)
: BaseJob(HttpVerb::Put, QStringLiteral("SendMessageJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/send/" % eventType % "/" % txnId)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/send/",
+ eventType, "/", txnId))
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
addExpectedKey("event_id");
}
diff --git a/lib/csapi/room_send.h b/lib/csapi/room_send.h
index a9e7ca13..96f5beca 100644
--- a/lib/csapi/room_send.h
+++ b/lib/csapi/room_send.h
@@ -49,10 +49,7 @@ public:
// Result properties
/// A unique identifier for the event.
- QString eventId() const
- {
- return loadFromJson<QString>("event_id"_ls);
- }
+ QString eventId() const { return loadFromJson<QString>("event_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/room_state.cpp b/lib/csapi/room_state.cpp
index e18108ac..f6d2e6ec 100644
--- a/lib/csapi/room_state.cpp
+++ b/lib/csapi/room_state.cpp
@@ -4,8 +4,6 @@
#include "room_state.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetRoomStateWithKeyJob::SetRoomStateWithKeyJob(const QString& roomId,
@@ -13,9 +11,9 @@ SetRoomStateWithKeyJob::SetRoomStateWithKeyJob(const QString& roomId,
const QString& stateKey,
const QJsonObject& body)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomStateWithKeyJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/state/" % eventType % "/" % stateKey)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/state/",
+ eventType, "/", stateKey))
{
- setRequestData(Data(toJson(body)));
+ setRequestData(RequestData(toJson(body)));
addExpectedKey("event_id");
}
diff --git a/lib/csapi/room_state.h b/lib/csapi/room_state.h
index 99eb4fc9..f95af223 100644
--- a/lib/csapi/room_state.h
+++ b/lib/csapi/room_state.h
@@ -71,10 +71,7 @@ public:
// Result properties
/// A unique identifier for the event.
- QString eventId() const
- {
- return loadFromJson<QString>("event_id"_ls);
- }
+ QString eventId() const { return loadFromJson<QString>("event_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/room_upgrades.cpp b/lib/csapi/room_upgrades.cpp
index e3791b08..d4129cfb 100644
--- a/lib/csapi/room_upgrades.cpp
+++ b/lib/csapi/room_upgrades.cpp
@@ -4,14 +4,11 @@
#include "room_upgrades.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
UpgradeRoomJob::UpgradeRoomJob(const QString& roomId, const QString& newVersion)
: BaseJob(HttpVerb::Post, QStringLiteral("UpgradeRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/upgrade")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/upgrade"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("new_version"), newVersion);
diff --git a/lib/csapi/rooms.cpp b/lib/csapi/rooms.cpp
index 3dd87021..5310aa32 100644
--- a/lib/csapi/rooms.cpp
+++ b/lib/csapi/rooms.cpp
@@ -4,24 +4,21 @@
#include "rooms.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetOneRoomEventJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/event/"
- % eventId);
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/event/", eventId));
}
GetOneRoomEventJob::GetOneRoomEventJob(const QString& roomId,
const QString& eventId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetOneRoomEventJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/event/" % eventId)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/event/",
+ eventId))
{}
QUrl GetRoomStateWithKeyJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
@@ -29,30 +26,29 @@ QUrl GetRoomStateWithKeyJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& stateKey)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/state/"
- % eventType % "/" % stateKey);
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/state/", eventType, "/",
+ stateKey));
}
GetRoomStateWithKeyJob::GetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
const QString& stateKey)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomStateWithKeyJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/state/" % eventType % "/" % stateKey)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/state/",
+ eventType, "/", stateKey))
{}
QUrl GetRoomStateJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/state");
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/state"));
}
GetRoomStateJob::GetRoomStateJob(const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomStateJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/state")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/state"))
{}
auto queryToGetMembersByRoom(const QString& at, const QString& membership,
@@ -72,7 +68,7 @@ QUrl GetMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
{
return BaseJob::makeRequestUrl(
std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/members",
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/members"),
queryToGetMembersByRoom(at, membership, notMembership));
}
@@ -81,8 +77,7 @@ GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId,
const QString& membership,
const QString& notMembership)
: BaseJob(HttpVerb::Get, QStringLiteral("GetMembersByRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/members",
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/members"),
queryToGetMembersByRoom(at, membership, notMembership))
{}
@@ -90,12 +85,12 @@ QUrl GetJoinedMembersByRoomJob::makeRequestUrl(QUrl baseUrl,
const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/rooms/" % roomId % "/joined_members");
+ makePath("/_matrix/client/r0", "/rooms/",
+ roomId, "/joined_members"));
}
GetJoinedMembersByRoomJob::GetJoinedMembersByRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetJoinedMembersByRoomJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/joined_members")
+ makePath("/_matrix/client/r0", "/rooms/", roomId,
+ "/joined_members"))
{}
diff --git a/lib/csapi/rooms.h b/lib/csapi/rooms.h
index 179d7a27..2620582b 100644
--- a/lib/csapi/rooms.h
+++ b/lib/csapi/rooms.h
@@ -38,11 +38,7 @@ public:
// Result properties
/// The full event.
- EventPtr event()
-
- {
- return fromJson<EventPtr>(jsonData());
- }
+ EventPtr event() { return fromJson<EventPtr>(jsonData()); }
};
/*! \brief Get the state identified by the type and key.
@@ -103,11 +99,7 @@ public:
// Result properties
/// The current state of the room
- StateEvents events()
-
- {
- return fromJson<StateEvents>(jsonData());
- }
+ StateEvents events() { return fromJson<StateEvents>(jsonData()); }
};
/*! \brief Get the m.room.member events for the room.
@@ -183,7 +175,7 @@ public:
/// The display name of the user this object is representing.
QString displayName;
/// The mxc avatar url of the user this object is representing.
- QString avatarUrl;
+ QUrl avatarUrl;
};
// Construction/destruction
diff --git a/lib/csapi/search.cpp b/lib/csapi/search.cpp
index 05ad871e..295dd1cc 100644
--- a/lib/csapi/search.cpp
+++ b/lib/csapi/search.cpp
@@ -4,8 +4,6 @@
#include "search.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToSearch(const QString& nextBatch)
@@ -18,7 +16,7 @@ auto queryToSearch(const QString& nextBatch)
SearchJob::SearchJob(const Categories& searchCategories,
const QString& nextBatch)
: BaseJob(HttpVerb::Post, QStringLiteral("SearchJob"),
- QStringLiteral("/_matrix/client/r0") % "/search",
+ makePath("/_matrix/client/r0", "/search"),
queryToSearch(nextBatch))
{
QJsonObject _data;
diff --git a/lib/csapi/search.h b/lib/csapi/search.h
index b56d9154..3d02752a 100644
--- a/lib/csapi/search.h
+++ b/lib/csapi/search.h
@@ -81,7 +81,7 @@ public:
/// Performs a full text search across different categories.
QString displayname;
/// Performs a full text search across different categories.
- QString avatarUrl;
+ QUrl avatarUrl;
};
/// Context for result, if requested.
diff --git a/lib/csapi/sso_login_redirect.cpp b/lib/csapi/sso_login_redirect.cpp
index 92601b4d..871d6ff6 100644
--- a/lib/csapi/sso_login_redirect.cpp
+++ b/lib/csapi/sso_login_redirect.cpp
@@ -4,8 +4,6 @@
#include "sso_login_redirect.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
auto queryToRedirectToSSO(const QString& redirectUrl)
@@ -18,14 +16,14 @@ auto queryToRedirectToSSO(const QString& redirectUrl)
QUrl RedirectToSSOJob::makeRequestUrl(QUrl baseUrl, const QString& redirectUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/login/sso/redirect",
+ makePath("/_matrix/client/r0",
+ "/login/sso/redirect"),
queryToRedirectToSSO(redirectUrl));
}
RedirectToSSOJob::RedirectToSSOJob(const QString& redirectUrl)
: BaseJob(HttpVerb::Get, QStringLiteral("RedirectToSSOJob"),
- QStringLiteral("/_matrix/client/r0") % "/login/sso/redirect",
+ makePath("/_matrix/client/r0", "/login/sso/redirect"),
queryToRedirectToSSO(redirectUrl), {}, false)
{}
@@ -40,15 +38,14 @@ QUrl RedirectToIdPJob::makeRequestUrl(QUrl baseUrl, const QString& idpId,
const QString& redirectUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/login/sso/redirect/" % idpId,
+ makePath("/_matrix/client/r0",
+ "/login/sso/redirect/", idpId),
queryToRedirectToIdP(redirectUrl));
}
RedirectToIdPJob::RedirectToIdPJob(const QString& idpId,
const QString& redirectUrl)
: BaseJob(HttpVerb::Get, QStringLiteral("RedirectToIdPJob"),
- QStringLiteral("/_matrix/client/r0") % "/login/sso/redirect/"
- % idpId,
+ makePath("/_matrix/client/r0", "/login/sso/redirect/", idpId),
queryToRedirectToIdP(redirectUrl), {}, false)
{}
diff --git a/lib/csapi/tags.cpp b/lib/csapi/tags.cpp
index dc22dc18..f717de6e 100644
--- a/lib/csapi/tags.cpp
+++ b/lib/csapi/tags.cpp
@@ -4,30 +4,28 @@
#include "tags.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetRoomTagsJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0") % "/user/"
- % userId % "/rooms/" % roomId % "/tags");
+ makePath("/_matrix/client/r0", "/user/",
+ userId, "/rooms/", roomId, "/tags"));
}
GetRoomTagsJob::GetRoomTagsJob(const QString& userId, const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomTagsJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/rooms/" % roomId % "/tags")
+ makePath("/_matrix/client/r0", "/user/", userId, "/rooms/",
+ roomId, "/tags"))
{}
SetRoomTagJob::SetRoomTagJob(const QString& userId, const QString& roomId,
const QString& tag, Omittable<float> order,
const QVariantHash& additionalProperties)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomTagJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/rooms/" % roomId % "/tags/" % tag)
+ makePath("/_matrix/client/r0", "/user/", userId, "/rooms/",
+ roomId, "/tags/", tag))
{
QJsonObject _data;
fillJson(_data, additionalProperties);
@@ -39,14 +37,14 @@ QUrl DeleteRoomTagJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& roomId, const QString& tag)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/user/" % userId % "/rooms/" % roomId
- % "/tags/" % tag);
+ makePath("/_matrix/client/r0", "/user/",
+ userId, "/rooms/", roomId, "/tags/",
+ tag));
}
DeleteRoomTagJob::DeleteRoomTagJob(const QString& userId, const QString& roomId,
const QString& tag)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteRoomTagJob"),
- QStringLiteral("/_matrix/client/r0") % "/user/" % userId
- % "/rooms/" % roomId % "/tags/" % tag)
+ makePath("/_matrix/client/r0", "/user/", userId, "/rooms/",
+ roomId, "/tags/", tag))
{}
diff --git a/lib/csapi/third_party_lookup.cpp b/lib/csapi/third_party_lookup.cpp
index 93687a76..4c930668 100644
--- a/lib/csapi/third_party_lookup.cpp
+++ b/lib/csapi/third_party_lookup.cpp
@@ -4,34 +4,31 @@
#include "third_party_lookup.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetProtocolsJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/thirdparty/protocols");
+ makePath("/_matrix/client/r0",
+ "/thirdparty/protocols"));
}
GetProtocolsJob::GetProtocolsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetProtocolsJob"),
- QStringLiteral("/_matrix/client/r0") % "/thirdparty/protocols")
+ makePath("/_matrix/client/r0", "/thirdparty/protocols"))
{}
QUrl GetProtocolMetadataJob::makeRequestUrl(QUrl baseUrl,
const QString& protocol)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/thirdparty/protocol/" % protocol);
+ makePath("/_matrix/client/r0",
+ "/thirdparty/protocol/", protocol));
}
GetProtocolMetadataJob::GetProtocolMetadataJob(const QString& protocol)
: BaseJob(HttpVerb::Get, QStringLiteral("GetProtocolMetadataJob"),
- QStringLiteral("/_matrix/client/r0") % "/thirdparty/protocol/"
- % protocol)
+ makePath("/_matrix/client/r0", "/thirdparty/protocol/", protocol))
{}
auto queryToQueryLocationByProtocol(const QString& searchFields)
@@ -46,16 +43,15 @@ QUrl QueryLocationByProtocolJob::makeRequestUrl(QUrl baseUrl,
const QString& searchFields)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/thirdparty/location/" % protocol,
+ makePath("/_matrix/client/r0",
+ "/thirdparty/location/", protocol),
queryToQueryLocationByProtocol(searchFields));
}
QueryLocationByProtocolJob::QueryLocationByProtocolJob(
const QString& protocol, const QString& searchFields)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryLocationByProtocolJob"),
- QStringLiteral("/_matrix/client/r0") % "/thirdparty/location/"
- % protocol,
+ makePath("/_matrix/client/r0", "/thirdparty/location/", protocol),
queryToQueryLocationByProtocol(searchFields))
{}
@@ -71,16 +67,15 @@ QUrl QueryUserByProtocolJob::makeRequestUrl(QUrl baseUrl,
const QString& fields)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/thirdparty/user/" % protocol,
+ makePath("/_matrix/client/r0",
+ "/thirdparty/user/", protocol),
queryToQueryUserByProtocol(fields));
}
QueryUserByProtocolJob::QueryUserByProtocolJob(const QString& protocol,
const QString& fields)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryUserByProtocolJob"),
- QStringLiteral("/_matrix/client/r0") % "/thirdparty/user/"
- % protocol,
+ makePath("/_matrix/client/r0", "/thirdparty/user/", protocol),
queryToQueryUserByProtocol(fields))
{}
@@ -94,14 +89,14 @@ auto queryToQueryLocationByAlias(const QString& alias)
QUrl QueryLocationByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& alias)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/thirdparty/location",
+ makePath("/_matrix/client/r0",
+ "/thirdparty/location"),
queryToQueryLocationByAlias(alias));
}
QueryLocationByAliasJob::QueryLocationByAliasJob(const QString& alias)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryLocationByAliasJob"),
- QStringLiteral("/_matrix/client/r0") % "/thirdparty/location",
+ makePath("/_matrix/client/r0", "/thirdparty/location"),
queryToQueryLocationByAlias(alias))
{}
@@ -115,13 +110,13 @@ auto queryToQueryUserByID(const QString& userid)
QUrl QueryUserByIDJob::makeRequestUrl(QUrl baseUrl, const QString& userid)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/thirdparty/user",
+ makePath("/_matrix/client/r0",
+ "/thirdparty/user"),
queryToQueryUserByID(userid));
}
QueryUserByIDJob::QueryUserByIDJob(const QString& userid)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryUserByIDJob"),
- QStringLiteral("/_matrix/client/r0") % "/thirdparty/user",
+ makePath("/_matrix/client/r0", "/thirdparty/user"),
queryToQueryUserByID(userid))
{}
diff --git a/lib/csapi/third_party_membership.cpp b/lib/csapi/third_party_membership.cpp
index fda772d2..59275e41 100644
--- a/lib/csapi/third_party_membership.cpp
+++ b/lib/csapi/third_party_membership.cpp
@@ -4,16 +4,13 @@
#include "third_party_membership.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
InviteBy3PIDJob::InviteBy3PIDJob(const QString& roomId, const QString& idServer,
const QString& idAccessToken,
const QString& medium, const QString& address)
: BaseJob(HttpVerb::Post, QStringLiteral("InviteBy3PIDJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/invite")
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/invite"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("id_server"), idServer);
diff --git a/lib/csapi/to_device.cpp b/lib/csapi/to_device.cpp
index 3775174d..628e8314 100644
--- a/lib/csapi/to_device.cpp
+++ b/lib/csapi/to_device.cpp
@@ -4,16 +4,14 @@
#include "to_device.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SendToDeviceJob::SendToDeviceJob(
const QString& eventType, const QString& txnId,
const QHash<QString, QHash<QString, QJsonObject>>& messages)
: BaseJob(HttpVerb::Put, QStringLiteral("SendToDeviceJob"),
- QStringLiteral("/_matrix/client/r0") % "/sendToDevice/"
- % eventType % "/" % txnId)
+ makePath("/_matrix/client/r0", "/sendToDevice/", eventType, "/",
+ txnId))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("messages"), messages);
diff --git a/lib/csapi/typing.cpp b/lib/csapi/typing.cpp
index 8e214053..c9673118 100644
--- a/lib/csapi/typing.cpp
+++ b/lib/csapi/typing.cpp
@@ -4,15 +4,13 @@
#include "typing.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SetTypingJob::SetTypingJob(const QString& userId, const QString& roomId,
bool typing, Omittable<int> timeout)
: BaseJob(HttpVerb::Put, QStringLiteral("SetTypingJob"),
- QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
- % "/typing/" % userId)
+ makePath("/_matrix/client/r0", "/rooms/", roomId, "/typing/",
+ userId))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("typing"), typing);
diff --git a/lib/csapi/users.cpp b/lib/csapi/users.cpp
index a0279d7e..48b727f0 100644
--- a/lib/csapi/users.cpp
+++ b/lib/csapi/users.cpp
@@ -4,14 +4,12 @@
#include "users.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
SearchUserDirectoryJob::SearchUserDirectoryJob(const QString& searchTerm,
Omittable<int> limit)
: BaseJob(HttpVerb::Post, QStringLiteral("SearchUserDirectoryJob"),
- QStringLiteral("/_matrix/client/r0") % "/user_directory/search")
+ makePath("/_matrix/client/r0", "/user_directory/search"))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("search_term"), searchTerm);
diff --git a/lib/csapi/users.h b/lib/csapi/users.h
index 772a6365..ec186592 100644
--- a/lib/csapi/users.h
+++ b/lib/csapi/users.h
@@ -41,7 +41,7 @@ public:
/// The display name of the user, if one exists.
QString displayName;
/// The avatar url, as an MXC, if one exists.
- QString avatarUrl;
+ QUrl avatarUrl;
};
// Construction/destruction
@@ -66,10 +66,7 @@ public:
}
/// Indicates if the result list has been truncated by the limit.
- bool limited() const
- {
- return loadFromJson<bool>("limited"_ls);
- }
+ bool limited() const { return loadFromJson<bool>("limited"_ls); }
};
template <>
diff --git a/lib/csapi/versions.cpp b/lib/csapi/versions.cpp
index 9003e27f..a1efc33e 100644
--- a/lib/csapi/versions.cpp
+++ b/lib/csapi/versions.cpp
@@ -4,20 +4,17 @@
#include "versions.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetVersionsJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client")
- % "/versions");
+ makePath("/_matrix/client", "/versions"));
}
GetVersionsJob::GetVersionsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetVersionsJob"),
- QStringLiteral("/_matrix/client") % "/versions", false)
+ makePath("/_matrix/client", "/versions"), false)
{
addExpectedKey("versions");
}
diff --git a/lib/csapi/voip.cpp b/lib/csapi/voip.cpp
index 43170057..c748ad94 100644
--- a/lib/csapi/voip.cpp
+++ b/lib/csapi/voip.cpp
@@ -4,18 +4,15 @@
#include "voip.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetTurnServerJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/voip/turnServer");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/voip/turnServer"));
}
GetTurnServerJob::GetTurnServerJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetTurnServerJob"),
- QStringLiteral("/_matrix/client/r0") % "/voip/turnServer")
+ makePath("/_matrix/client/r0", "/voip/turnServer"))
{}
diff --git a/lib/csapi/voip.h b/lib/csapi/voip.h
index 85ab8b41..087ebbbd 100644
--- a/lib/csapi/voip.h
+++ b/lib/csapi/voip.h
@@ -28,10 +28,7 @@ public:
// Result properties
/// The TURN server credentials.
- QJsonObject data() const
- {
- return fromJson<QJsonObject>(jsonData());
- }
+ QJsonObject data() const { return fromJson<QJsonObject>(jsonData()); }
};
} // namespace Quotient
diff --git a/lib/csapi/wellknown.cpp b/lib/csapi/wellknown.cpp
index 1aa0a90b..0b441279 100644
--- a/lib/csapi/wellknown.cpp
+++ b/lib/csapi/wellknown.cpp
@@ -4,18 +4,15 @@
#include "wellknown.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetWellknownJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/.well-known")
- % "/matrix/client");
+ makePath("/.well-known", "/matrix/client"));
}
GetWellknownJob::GetWellknownJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetWellknownJob"),
- QStringLiteral("/.well-known") % "/matrix/client", false)
+ makePath("/.well-known", "/matrix/client"), false)
{}
diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp
index 73f0298e..ed8a9817 100644
--- a/lib/csapi/whoami.cpp
+++ b/lib/csapi/whoami.cpp
@@ -4,20 +4,17 @@
#include "whoami.h"
-#include <QtCore/QStringBuilder>
-
using namespace Quotient;
QUrl GetTokenOwnerJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- QStringLiteral("/_matrix/client/r0")
- % "/account/whoami");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), makePath("/_matrix/client/r0", "/account/whoami"));
}
GetTokenOwnerJob::GetTokenOwnerJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetTokenOwnerJob"),
- QStringLiteral("/_matrix/client/r0") % "/account/whoami")
+ makePath("/_matrix/client/r0", "/account/whoami"))
{
addExpectedKey("user_id");
}
diff --git a/lib/csapi/whoami.h b/lib/csapi/whoami.h
index 203742c9..319f82c5 100644
--- a/lib/csapi/whoami.h
+++ b/lib/csapi/whoami.h
@@ -34,19 +34,13 @@ public:
// Result properties
/// The user ID that owns the access token.
- QString userId() const
- {
- return loadFromJson<QString>("user_id"_ls);
- }
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
/// Device ID associated with the access token. If no device
/// is associated with the access token (such as in the case
/// of application services) then this field can be omitted.
/// Otherwise this is required.
- QString deviceId() const
- {
- return loadFromJson<QString>("device_id"_ls);
- }
+ QString deviceId() const { return loadFromJson<QString>("device_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/eventitem.h b/lib/eventitem.h
index 1986ba77..a70a3c3e 100644
--- a/lib/eventitem.h
+++ b/lib/eventitem.h
@@ -11,9 +11,9 @@
namespace Quotient {
class StateEventBase;
-class EventStatus {
- Q_GADGET
-public:
+namespace EventStatus {
+ Q_NAMESPACE
+
/** Special marks an event can assume
*
* This is used to hint at a special status of some events in UI.
@@ -32,8 +32,8 @@ public:
Hidden = 0x100, //< The event should not be shown in the timeline
};
Q_DECLARE_FLAGS(Status, Code)
- Q_FLAG(Status)
-};
+ Q_FLAG_NS(Status)
+} // namespace EventStatus
class EventItemBase {
public:
@@ -148,4 +148,3 @@ inline QDebug& operator<<(QDebug& d, const TimelineItem& ti)
return d;
}
} // namespace Quotient
-Q_DECLARE_METATYPE(Quotient::EventStatus)
diff --git a/lib/events/encryptedfile.h b/lib/events/encryptedfile.h
new file mode 100644
index 00000000..24ac9de1
--- /dev/null
+++ b/lib/events/encryptedfile.h
@@ -0,0 +1,88 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPl-2.1-or-later
+
+#pragma once
+
+#include "converters.h"
+
+namespace Quotient {
+/**
+ * JSON Web Key object as specified in
+ * https://spec.matrix.org/unstable/client-server-api/#extensions-to-mroommessage-msgtypes
+ * The only currently relevant member is `k`, the rest needs to be set to the defaults specified in the spec.
+ */
+struct JWK
+{
+ Q_GADGET
+ Q_PROPERTY(QString kty MEMBER kty CONSTANT)
+ Q_PROPERTY(QStringList keyOps MEMBER keyOps CONSTANT)
+ Q_PROPERTY(QString alg MEMBER alg CONSTANT)
+ Q_PROPERTY(QString k MEMBER k CONSTANT)
+ Q_PROPERTY(bool ext MEMBER ext CONSTANT)
+
+public:
+ QString kty;
+ QStringList keyOps;
+ QString alg;
+ QString k;
+ bool ext;
+};
+
+struct EncryptedFile
+{
+ Q_GADGET
+ Q_PROPERTY(QUrl url MEMBER url CONSTANT)
+ Q_PROPERTY(JWK key MEMBER key CONSTANT)
+ Q_PROPERTY(QString iv MEMBER iv CONSTANT)
+ Q_PROPERTY(QHash<QString, QString> hashes MEMBER hashes CONSTANT)
+ Q_PROPERTY(QString v MEMBER v CONSTANT)
+
+public:
+ QUrl url;
+ JWK key;
+ QString iv;
+ QHash<QString, QString> hashes;
+ QString v;
+};
+
+template <>
+struct JsonObjectConverter<EncryptedFile> {
+ static void dumpTo(QJsonObject& jo, const EncryptedFile& pod)
+ {
+ addParam<>(jo, QStringLiteral("url"), pod.url);
+ addParam<>(jo, QStringLiteral("key"), pod.key);
+ addParam<>(jo, QStringLiteral("iv"), pod.iv);
+ addParam<>(jo, QStringLiteral("hashes"), pod.hashes);
+ addParam<>(jo, QStringLiteral("v"), pod.v);
+ }
+ static void fillFrom(const QJsonObject& jo, EncryptedFile& pod)
+ {
+ fromJson(jo.value("url"_ls), pod.url);
+ fromJson(jo.value("key"_ls), pod.key);
+ fromJson(jo.value("iv"_ls), pod.iv);
+ fromJson(jo.value("hashes"_ls), pod.hashes);
+ fromJson(jo.value("v"_ls), pod.v);
+ }
+};
+
+template <>
+struct JsonObjectConverter<JWK> {
+ static void dumpTo(QJsonObject& jo, const JWK& pod)
+ {
+ addParam<>(jo, QStringLiteral("kty"), pod.kty);
+ addParam<>(jo, QStringLiteral("key_ops"), pod.keyOps);
+ addParam<>(jo, QStringLiteral("alg"), pod.alg);
+ addParam<>(jo, QStringLiteral("k"), pod.k);
+ addParam<>(jo, QStringLiteral("ext"), pod.ext);
+ }
+ static void fillFrom(const QJsonObject& jo, JWK& pod)
+ {
+ fromJson(jo.value("kty"_ls), pod.kty);
+ fromJson(jo.value("key_ops"_ls), pod.keyOps);
+ fromJson(jo.value("alg"_ls), pod.alg);
+ fromJson(jo.value("k"_ls), pod.k);
+ fromJson(jo.value("ext"_ls), pod.ext);
+ }
+};
+} // namespace Quotient
diff --git a/lib/events/encryptionevent.cpp b/lib/events/encryptionevent.cpp
index 490a5e8a..aa05a96e 100644
--- a/lib/events/encryptionevent.cpp
+++ b/lib/events/encryptionevent.cpp
@@ -39,6 +39,14 @@ EncryptionEventContent::EncryptionEventContent(const QJsonObject& json)
, rotationPeriodMsgs(json[RotationPeriodMsgsKeyL].toInt(100))
{}
+EncryptionEventContent::EncryptionEventContent(EncryptionType et)
+ : encryption(et)
+{
+ if(encryption != Undefined) {
+ algorithm = encryptionStrings[encryption];
+ }
+}
+
void EncryptionEventContent::fillJson(QJsonObject* o) const
{
Q_ASSERT(o);
diff --git a/lib/events/encryptionevent.h b/lib/events/encryptionevent.h
index 65ee4187..14439fcc 100644
--- a/lib/events/encryptionevent.h
+++ b/lib/events/encryptionevent.h
@@ -12,9 +12,7 @@ class EncryptionEventContent : public EventContent::Base {
public:
enum EncryptionType : size_t { MegolmV1AesSha2 = 0, Undefined };
- explicit EncryptionEventContent(EncryptionType et = Undefined)
- : encryption(et)
- {}
+ explicit EncryptionEventContent(EncryptionType et = Undefined);
explicit EncryptionEventContent(const QJsonObject& json);
EncryptionType encryption;
diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp
index 1f28f195..22878d4c 100644
--- a/lib/events/eventcontent.cpp
+++ b/lib/events/eventcontent.cpp
@@ -30,11 +30,12 @@ FileInfo::FileInfo(const QFileInfo &fi)
}
FileInfo::FileInfo(QUrl u, qint64 payloadSize, const QMimeType& mimeType,
- QString originalFilename)
+ Omittable<EncryptedFile> file, QString originalFilename)
: mimeType(mimeType)
, url(move(u))
, payloadSize(payloadSize)
, originalName(move(originalFilename))
+ , file(file)
{
if (!isValid())
qCWarning(MESSAGES)
@@ -44,6 +45,7 @@ FileInfo::FileInfo(QUrl u, qint64 payloadSize, const QMimeType& mimeType,
}
FileInfo::FileInfo(QUrl mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &file,
QString originalFilename)
: originalInfoJson(infoJson)
, mimeType(
@@ -51,7 +53,11 @@ FileInfo::FileInfo(QUrl mxcUrl, const QJsonObject& infoJson,
, url(move(mxcUrl))
, payloadSize(fromJson<qint64>(infoJson["size"_ls]))
, originalName(move(originalFilename))
+ , file(file)
{
+ if(url.isEmpty() && file.has_value()) {
+ url = file->url;
+ }
if (!mimeType.isValid())
mimeType = QMimeDatabase().mimeTypeForData(QByteArray());
}
@@ -76,14 +82,15 @@ ImageInfo::ImageInfo(const QFileInfo& fi, QSize imageSize)
{}
ImageInfo::ImageInfo(const QUrl& mxcUrl, qint64 fileSize, const QMimeType& type,
- QSize imageSize, const QString& originalFilename)
- : FileInfo(mxcUrl, fileSize, type, originalFilename)
+ QSize imageSize, const Omittable<EncryptedFile> &file, const QString& originalFilename)
+ : FileInfo(mxcUrl, fileSize, type, file, originalFilename)
, imageSize(imageSize)
{}
ImageInfo::ImageInfo(const QUrl& mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &file,
const QString& originalFilename)
- : FileInfo(mxcUrl, infoJson, originalFilename)
+ : FileInfo(mxcUrl, infoJson, file, originalFilename)
, imageSize(infoJson["w"_ls].toInt(), infoJson["h"_ls].toInt())
{}
@@ -96,9 +103,10 @@ void ImageInfo::fillInfoJson(QJsonObject* infoJson) const
infoJson->insert(QStringLiteral("h"), imageSize.height());
}
-Thumbnail::Thumbnail(const QJsonObject& infoJson)
+Thumbnail::Thumbnail(const QJsonObject& infoJson, const Omittable<EncryptedFile> &file)
: ImageInfo(QUrl(infoJson["thumbnail_url"_ls].toString()),
- infoJson["thumbnail_info"_ls].toObject())
+ infoJson["thumbnail_info"_ls].toObject(),
+ file)
{}
void Thumbnail::fillInfoJson(QJsonObject* infoJson) const
diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h
index 40ec3a49..f609a603 100644
--- a/lib/events/eventcontent.h
+++ b/lib/events/eventcontent.h
@@ -12,6 +12,8 @@
#include <QtCore/QUrl>
#include <QtCore/QMetaType>
+#include "encryptedfile.h"
+
class QFileInfo;
namespace Quotient {
@@ -80,8 +82,10 @@ namespace EventContent {
explicit FileInfo(const QFileInfo& fi);
explicit FileInfo(QUrl mxcUrl, qint64 payloadSize = -1,
const QMimeType& mimeType = {},
+ Omittable<EncryptedFile> file = none,
QString originalFilename = {});
FileInfo(QUrl mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &file,
QString originalFilename = {});
bool isValid() const;
@@ -103,6 +107,7 @@ namespace EventContent {
QUrl url;
qint64 payloadSize;
QString originalName;
+ Omittable<EncryptedFile> file = none;
};
template <typename InfoT>
@@ -122,8 +127,10 @@ namespace EventContent {
explicit ImageInfo(const QFileInfo& fi, QSize imageSize = {});
explicit ImageInfo(const QUrl& mxcUrl, qint64 fileSize = -1,
const QMimeType& type = {}, QSize imageSize = {},
+ const Omittable<EncryptedFile> &file = none,
const QString& originalFilename = {});
ImageInfo(const QUrl& mxcUrl, const QJsonObject& infoJson,
+ const Omittable<EncryptedFile> &encryptedFile,
const QString& originalFilename = {});
void fillInfoJson(QJsonObject* infoJson) const;
@@ -142,7 +149,7 @@ namespace EventContent {
class Thumbnail : public ImageInfo {
public:
Thumbnail() = default; // Allow empty thumbnails
- Thumbnail(const QJsonObject& infoJson);
+ Thumbnail(const QJsonObject& infoJson, const Omittable<EncryptedFile> &file = none);
Thumbnail(const ImageInfo& info) : ImageInfo(info) {}
using ImageInfo::ImageInfo;
@@ -182,7 +189,7 @@ namespace EventContent {
explicit UrlBasedContent(const QJsonObject& json)
: TypedBase(json)
, InfoT(QUrl(json["url"].toString()), json["info"].toObject(),
- json["filename"].toString())
+ fromJson<Omittable<EncryptedFile>>(json["file"]), json["filename"].toString())
{
// A small hack to facilitate links creation in QML.
originalJson.insert("mediaId", InfoT::mediaId());
@@ -196,7 +203,11 @@ namespace EventContent {
void fillJson(QJsonObject* json) const override
{
Q_ASSERT(json);
- json->insert("url", InfoT::url.toString());
+ if (!InfoT::file.has_value()) {
+ json->insert("url", InfoT::url.toString());
+ } else {
+ json->insert("file", Quotient::toJson(*InfoT::file));
+ }
if (!InfoT::originalName.isEmpty())
json->insert("filename", InfoT::originalName);
json->insert("info", toInfoJson<InfoT>(*this));
diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h
index 3fa11a0f..8618ba31 100644
--- a/lib/events/roomavatarevent.h
+++ b/lib/events/roomavatarevent.h
@@ -25,7 +25,7 @@ public:
const QSize& imageSize = {},
const QString& originalFilename = {})
: RoomAvatarEvent(EventContent::ImageContent {
- mxcUrl, fileSize, mimeType, imageSize, originalFilename })
+ mxcUrl, fileSize, mimeType, imageSize, none, originalFilename })
{}
QUrl url() const { return content().url; }
diff --git a/lib/events/roomcreateevent.cpp b/lib/events/roomcreateevent.cpp
index 6558bade..ff93041c 100644
--- a/lib/events/roomcreateevent.cpp
+++ b/lib/events/roomcreateevent.cpp
@@ -5,6 +5,22 @@
using namespace Quotient;
+template <>
+struct Quotient::JsonConverter<RoomType> {
+ static RoomType load(const QJsonValue& jv)
+ {
+ const auto& roomTypeString = jv.toString();
+ for (auto it = RoomTypeStrings.begin(); it != RoomTypeStrings.end();
+ ++it)
+ if (roomTypeString == *it)
+ return RoomType(it - RoomTypeStrings.begin());
+
+ if (!roomTypeString.isEmpty())
+ qCWarning(EVENTS) << "Unknown Room Type: " << roomTypeString;
+ return RoomType::Undefined;
+ }
+};
+
bool RoomCreateEvent::isFederated() const
{
return fromJson<bool>(contentJson()["m.federate"_ls]);
@@ -26,3 +42,8 @@ bool RoomCreateEvent::isUpgrade() const
{
return contentJson().contains("predecessor"_ls);
}
+
+RoomType RoomCreateEvent::roomType() const
+{
+ return fromJson<RoomType>(contentJson()["type"_ls]);
+}
diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h
index 05e623ed..b3ad287c 100644
--- a/lib/events/roomcreateevent.h
+++ b/lib/events/roomcreateevent.h
@@ -4,6 +4,7 @@
#pragma once
#include "stateevent.h"
+#include "quotient_common.h"
namespace Quotient {
class RoomCreateEvent : public StateEventBase {
@@ -24,6 +25,7 @@ public:
QString version() const;
Predecessor predecessor() const;
bool isUpgrade() const;
+ RoomType roomType() const;
};
REGISTER_EVENT_TYPE(RoomCreateEvent)
} // namespace Quotient
diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h
index fea509c0..3174764f 100644
--- a/lib/events/roomevent.h
+++ b/lib/events/roomevent.h
@@ -14,7 +14,9 @@ class RedactionEvent;
class RoomEvent : public Event {
Q_GADGET
Q_PROPERTY(QString id READ id)
- Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT)
+ //! \deprecated Use originTimestamp instead
+ Q_PROPERTY(QDateTime timestamp READ originTimestamp CONSTANT)
+ Q_PROPERTY(QDateTime originTimestamp READ originTimestamp CONSTANT)
Q_PROPERTY(QString roomId READ roomId CONSTANT)
Q_PROPERTY(QString senderId READ senderId CONSTANT)
Q_PROPERTY(QString redactionReason READ redactionReason)
@@ -32,11 +34,12 @@ public:
QString id() const;
QDateTime originTimestamp() const;
- [[deprecated("Use originTimestamp()")]] QDateTime timestamp() const {
- return originTimestamp();
- }
QString roomId() const;
QString senderId() const;
+ //! \brief Determine whether the event has been replaced
+ //!
+ //! \return true if this event has been overridden by another event
+ //! with `"rel_type": "m.replace"`; false otherwise
bool isReplaced() const;
QString replacedBy() const;
bool isRedacted() const { return bool(_redactedBecause); }
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 71f85363..9b46594e 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -145,21 +145,21 @@ TypedBase* contentFromFile(const QFileInfo& file, bool asGenericFile)
auto mimeTypeName = mimeType.name();
if (mimeTypeName.startsWith("image/"))
return new ImageContent(localUrl, file.size(), mimeType,
- QImageReader(filePath).size(),
+ QImageReader(filePath).size(), none,
file.fileName());
// duration can only be obtained asynchronously and can only be reliably
// done by starting to play the file. Left for a future implementation.
if (mimeTypeName.startsWith("video/"))
return new VideoContent(localUrl, file.size(), mimeType,
- QMediaResource(localUrl).resolution(),
+ QMediaResource(localUrl).resolution(), none,
file.fileName());
if (mimeTypeName.startsWith("audio/"))
- return new AudioContent(localUrl, file.size(), mimeType,
+ return new AudioContent(localUrl, file.size(), mimeType, none,
file.fileName());
}
- return new FileContent(localUrl, file.size(), mimeType, file.fileName());
+ return new FileContent(localUrl, file.size(), mimeType, none, file.fileName());
}
RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h
index 7bcda2ba..88d3b74c 100644
--- a/lib/events/roommessageevent.h
+++ b/lib/events/roommessageevent.h
@@ -62,9 +62,26 @@ public:
_content.data());
}
QMimeType mimeType() const;
+ //! \brief Determine whether the message has text content
+ //!
+ //! \return true, if the message type is one of m.text, m.notice, m.emote,
+ //! or the message type is unspecified (in which case plainBody()
+ //! can still be examined); false otherwise
bool hasTextContent() const;
+ //! \brief Determine whether the message has a file/attachment
+ //!
+ //! \return true, if the message has a data structure corresponding to
+ //! a file (such as m.file or m.audio); false otherwise
bool hasFileContent() const;
+ //! \brief Determine whether the message has a thumbnail
+ //!
+ //! \return true, if the message has a data structure corresponding to
+ //! a thumbnail (the message type may be one for visual content,
+ //! such as m.image, or generic binary content, i.e. m.file);
+ //! false otherwise
bool hasThumbnail() const;
+ //! \brief Obtain id of an event replaced by the current one
+ //! \sa RoomEvent::isReplaced, RoomEvent::replacedBy
QString replacedEvent() const;
static QString rawMsgTypeForUrl(const QUrl& url);
diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h
index 1415f709..bc414a5f 100644
--- a/lib/events/stateevent.h
+++ b/lib/events/stateevent.h
@@ -100,10 +100,6 @@ public:
visitor(_content);
editJson()[ContentKeyL] = _content.toJson();
}
- [[deprecated("Use prevContent instead")]] const ContentT* prev_content() const
- {
- return prevContent();
- }
const ContentT* prevContent() const
{
return _prev ? &_prev->content : nullptr;
diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp
index 400a9243..971fea7b 100644
--- a/lib/jobs/basejob.cpp
+++ b/lib/jobs/basejob.cpp
@@ -24,7 +24,7 @@ BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode)
{
// Based on https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
if (httpCode / 10 == 41) // 41x errors
- return httpCode == 410 ? IncorrectRequestError : NotFoundError;
+ return httpCode == 410 ? IncorrectRequest : NotFound;
switch (httpCode) {
case 401:
return Unauthorised;
@@ -32,19 +32,19 @@ BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode)
case 403: case 407: // clang-format on
return ContentAccessError;
case 404:
- return NotFoundError;
+ return NotFound;
// clang-format off
case 400: case 405: case 406: case 426: case 428: case 505: // clang-format on
case 494: // Unofficial nginx "Request header too large"
case 497: // Unofficial nginx "HTTP request sent to HTTPS port"
- return IncorrectRequestError;
+ return IncorrectRequest;
case 429:
- return TooManyRequestsError;
+ return TooManyRequests;
case 501:
case 510:
- return RequestNotImplementedError;
+ return RequestNotImplemented;
case 511:
- return NetworkAuthRequiredError;
+ return NetworkAuthRequired;
default:
return NetworkError;
}
@@ -71,8 +71,8 @@ public:
// Using an idiom from clang-tidy:
// http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html
- Private(HttpVerb v, QString endpoint, const QUrlQuery& q, Data&& data,
- bool nt)
+ Private(HttpVerb v, QByteArray endpoint, const QUrlQuery& q,
+ RequestData&& data, bool nt)
: verb(v)
, apiEndpoint(std::move(endpoint))
, requestQuery(q)
@@ -106,10 +106,10 @@ public:
// Contents for the network request
HttpVerb verb;
- QString apiEndpoint;
+ QByteArray apiEndpoint;
QHash<QByteArray, QByteArray> requestHeaders;
QUrlQuery requestQuery;
- Data requestData;
+ RequestData requestData;
bool needsToken;
bool inBackground = false;
@@ -156,8 +156,8 @@ public:
{
// FIXME: use std::array {} when Apple stdlib gets deduction guides for it
static const auto verbs =
- to_array({ QStringLiteral("GET"), QStringLiteral("PUT"),
- QStringLiteral("POST"), QStringLiteral("DELETE") });
+ make_array(QStringLiteral("GET"), QStringLiteral("PUT"),
+ QStringLiteral("POST"), QStringLiteral("DELETE"));
const auto verbWord = verbs.at(size_t(verb));
return verbWord % ' '
% (reply ? reply->url().toString(QUrl::RemoveQuery)
@@ -166,14 +166,36 @@ public:
}
};
-BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
+inline bool isHex(QChar c)
+{
+ return c.isDigit() || (c >= u'A' && c <= u'F') || (c >= u'a' && c <= u'f');
+}
+
+QByteArray BaseJob::encodeIfParam(const QString& paramPart)
+{
+ const auto percentIndex = paramPart.indexOf('%');
+ if (percentIndex != -1 && paramPart.size() > percentIndex + 2
+ && isHex(paramPart[percentIndex + 1])
+ && isHex(paramPart[percentIndex + 2])) {
+ qCWarning(JOBS)
+ << "Developers, upfront percent-encoding of job parameters is "
+ "deprecated since libQuotient 0.7; the string involved is"
+ << paramPart;
+ return QUrl(paramPart, QUrl::TolerantMode).toEncoded();
+ }
+ return QUrl::toPercentEncoding(paramPart);
+}
+
+BaseJob::BaseJob(HttpVerb verb, const QString& name, QByteArray endpoint,
bool needsToken)
- : BaseJob(verb, name, endpoint, QUrlQuery {}, Data {}, needsToken)
+ : BaseJob(verb, name, std::move(endpoint), QUrlQuery {}, RequestData {},
+ needsToken)
{}
-BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
- const QUrlQuery &query, Data&& data, bool needsToken)
- : d(new Private(verb, endpoint, query, std::move(data), needsToken))
+BaseJob::BaseJob(HttpVerb verb, const QString& name, QByteArray endpoint,
+ const QUrlQuery& query, RequestData&& data, bool needsToken)
+ : d(new Private(verb, std::move(endpoint), query, std::move(data),
+ needsToken))
{
setObjectName(name);
connect(&d->timer, &QTimer::timeout, this, &BaseJob::timeout);
@@ -194,13 +216,6 @@ QUrl BaseJob::requestUrl() const { return d->reply ? d->reply->url() : QUrl(); }
bool BaseJob::isBackground() const { return d->inBackground; }
-const QString& BaseJob::apiEndpoint() const { return d->apiEndpoint; }
-
-void BaseJob::setApiEndpoint(const QString& apiEndpoint)
-{
- d->apiEndpoint = apiEndpoint;
-}
-
const BaseJob::headers_t& BaseJob::requestHeaders() const
{
return d->requestHeaders;
@@ -217,16 +232,19 @@ void BaseJob::setRequestHeaders(const BaseJob::headers_t& headers)
d->requestHeaders = headers;
}
-const QUrlQuery& BaseJob::query() const { return d->requestQuery; }
+QUrlQuery BaseJob::query() const { return d->requestQuery; }
void BaseJob::setRequestQuery(const QUrlQuery& query)
{
d->requestQuery = query;
}
-const BaseJob::Data& BaseJob::requestData() const { return d->requestData; }
+const RequestData& BaseJob::requestData() const { return d->requestData; }
-void BaseJob::setRequestData(Data&& data) { std::swap(d->requestData, data); }
+void BaseJob::setRequestData(RequestData&& data)
+{
+ std::swap(d->requestData, data);
+}
const QByteArrayList& BaseJob::expectedContentTypes() const
{
@@ -256,17 +274,17 @@ const QNetworkReply* BaseJob::reply() const { return d->reply.data(); }
QNetworkReply* BaseJob::reply() { return d->reply.data(); }
-QUrl BaseJob::makeRequestUrl(QUrl baseUrl, const QString& path,
+QUrl BaseJob::makeRequestUrl(QUrl baseUrl, const QByteArray& encodedPath,
const QUrlQuery& query)
{
- auto pathBase = baseUrl.path();
- // QUrl::adjusted(QUrl::StripTrailingSlashes) doesn't help with root '/'
- while (pathBase.endsWith('/'))
- pathBase.chop(1);
- if (!path.startsWith('/')) // Normally API files do start with '/'
- pathBase.push_back('/'); // so this shouldn't be needed these days
-
- baseUrl.setPath(pathBase + path, QUrl::TolerantMode);
+ // Make sure the added path is relative even if it's not (the official
+ // API definitions have the leading slash though it's not really correct).
+ const auto pathUrl =
+ QUrl::fromEncoded(encodedPath.mid(encodedPath.startsWith('/')),
+ QUrl::StrictMode);
+ Q_ASSERT_X(pathUrl.isValid(), __FUNCTION__,
+ qPrintable(pathUrl.errorString()));
+ baseUrl = baseUrl.resolved(pathUrl);
baseUrl.setQuery(query);
return baseUrl;
}
@@ -347,7 +365,7 @@ void BaseJob::initiate(ConnectionData* connData, bool inBackground)
qCCritical(d->logCat)
<< "Developers, ensure the Connection is valid before using it";
Q_ASSERT(false);
- setStatus(IncorrectRequestError, tr("Invalid server connection"));
+ setStatus(IncorrectRequest, tr("Invalid server connection"));
}
// The status is no good, finalise
QTimer::singleShot(0, this, &BaseJob::finishJob);
@@ -397,42 +415,42 @@ BaseJob::Status BaseJob::Private::parseJson()
void BaseJob::gotReply()
{
- setStatus(checkReply(reply()));
-
- if (status().good()
- && d->expectedContentTypes == QByteArrayList { "application/json" }) {
+ // Defer actually updating the status until it's finalised
+ auto statusSoFar = checkReply(reply());
+ if (statusSoFar.good()
+ && d->expectedContentTypes == QByteArrayList { "application/json" }) //
+ {
d->rawResponse = reply()->readAll();
- setStatus(d->parseJson());
- if (status().good() && !expectedKeys().empty()) {
+ statusSoFar = d->parseJson();
+ if (statusSoFar.good() && !expectedKeys().empty()) {
const auto& responseObject = jsonData();
QByteArrayList missingKeys;
for (const auto& k: expectedKeys())
if (!responseObject.contains(k))
missingKeys.push_back(k);
if (!missingKeys.empty())
- setStatus(IncorrectResponse, tr("Required JSON keys missing: ")
- + missingKeys.join());
+ statusSoFar = { IncorrectResponse,
+ tr("Required JSON keys missing: ")
+ + missingKeys.join() };
}
+ setStatus(statusSoFar);
if (!status().good()) // Bad JSON in a "good" reply: bail out
return;
- } // else {
+ }
// If the endpoint expects anything else than just (API-related) JSON
// reply()->readAll() is not performed and the whole reply processing
// is left to derived job classes: they may read it piecemeal or customise
// per content type in prepareResult(), or even have read it already
// (see, e.g., DownloadFileJob).
- // }
-
- if (status().good())
+ if (statusSoFar.good()) {
setStatus(prepareResult());
- else {
- d->rawResponse = reply()->readAll();
- qCDebug(d->logCat).noquote()
- << "Error body (truncated if long):" << rawDataSample(500);
- // Parse the error payload and update the status if needed
- if (const auto newStatus = prepareError(); !newStatus.good())
- setStatus(newStatus);
+ return;
}
+
+ d->rawResponse = reply()->readAll();
+ qCDebug(d->logCat).noquote()
+ << "Error body (truncated if long):" << rawDataSample(500);
+ setStatus(prepareError(statusSoFar));
}
bool checkContentType(const QByteArray& type, const QByteArrayList& patterns)
@@ -497,7 +515,7 @@ BaseJob::Status BaseJob::checkReply(const QNetworkReply* reply) const
BaseJob::Status BaseJob::prepareResult() { return Success; }
-BaseJob::Status BaseJob::prepareError()
+BaseJob::Status BaseJob::prepareError(Status currentStatus)
{
// Try to make sense of the error payload but be prepared for all kinds
// of unexpected stuff (raw HTML, plain text, foreign JSON among those)
@@ -507,10 +525,10 @@ BaseJob::Status BaseJob::prepareError()
// By now, if d->parseJson() above succeeded then jsonData() will return
// a valid JSON object - or an empty object otherwise (in which case most
- // of if's below will fall through to `return NoError` at the end
+ // of if's below will fall through retaining the current status)
const auto& errorJson = jsonData();
const auto errCode = errorJson.value("errcode"_ls).toString();
- if (error() == TooManyRequestsError || errCode == "M_LIMIT_EXCEEDED") {
+ if (error() == TooManyRequests || errCode == "M_LIMIT_EXCEEDED") {
QString msg = tr("Too many requests");
int64_t retryAfterMs = errorJson.value("retry_after_ms"_ls).toInt(-1);
if (retryAfterMs >= 0)
@@ -520,16 +538,16 @@ BaseJob::Status BaseJob::prepareError()
d->connection->limitRate(milliseconds(retryAfterMs));
- return { TooManyRequestsError, msg };
+ return { TooManyRequests, msg };
}
if (errCode == "M_CONSENT_NOT_GIVEN") {
d->errorUrl = QUrl(errorJson.value("consent_uri"_ls).toString());
- return { UserConsentRequiredError };
+ return { UserConsentRequired };
}
if (errCode == "M_UNSUPPORTED_ROOM_VERSION"
|| errCode == "M_INCOMPATIBLE_ROOM_VERSION")
- return { UnsupportedRoomVersionError,
+ return { UnsupportedRoomVersion,
errorJson.contains("room_version"_ls)
? tr("Requested room version: %1")
.arg(errorJson.value("room_version"_ls).toString())
@@ -542,9 +560,9 @@ BaseJob::Status BaseJob::prepareError()
// Not localisable on the client side
if (errorJson.contains("error"_ls)) // Keep the code, update the message
- return { d->status.code, errorJson.value("error"_ls).toString() };
+ return { currentStatus.code, errorJson.value("error"_ls).toString() };
- return NoError; // Retain the status if the error payload is not recognised
+ return currentStatus; // The error payload is not recognised
}
QJsonValue BaseJob::takeValueFromJson(const QString& key)
@@ -711,27 +729,27 @@ QString BaseJob::statusCaption() const
return tr("Request was abandoned");
case NetworkError:
return tr("Network problems");
- case TimeoutError:
+ case Timeout:
return tr("Request timed out");
case Unauthorised:
return tr("Unauthorised request");
case ContentAccessError:
return tr("Access error");
- case NotFoundError:
+ case NotFound:
return tr("Not found");
- case IncorrectRequestError:
+ case IncorrectRequest:
return tr("Invalid request");
- case IncorrectResponseError:
+ case IncorrectResponse:
return tr("Response could not be parsed");
- case TooManyRequestsError:
+ case TooManyRequests:
return tr("Too many requests");
- case RequestNotImplementedError:
+ case RequestNotImplemented:
return tr("Function not implemented by the server");
- case NetworkAuthRequiredError:
+ case NetworkAuthRequired:
return tr("Network authentication required");
- case UserConsentRequiredError:
+ case UserConsentRequired:
return tr("User consent required");
- case UnsupportedRoomVersionError:
+ case UnsupportedRoomVersion:
return tr("The server does not support the needed room version");
default:
return tr("Request failed");
@@ -793,7 +811,7 @@ void BaseJob::abandon()
void BaseJob::timeout()
{
- setStatus(TimeoutError, "The job has timed out");
+ setStatus(Timeout, "The job has timed out");
finishJob();
}
diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h
index d33d542e..119d7cce 100644
--- a/lib/jobs/basejob.h
+++ b/lib/jobs/basejob.h
@@ -9,6 +9,7 @@
#include "../converters.h"
#include <QtCore/QObject>
+#include <QtCore/QStringBuilder>
class QNetworkReply;
class QSslError;
@@ -23,7 +24,19 @@ class BaseJob : public QObject {
Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT)
Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries)
Q_PROPERTY(int statusCode READ error NOTIFY statusChanged)
+
+ static QByteArray encodeIfParam(const QString& paramPart);
+ template <int N>
+ static inline auto encodeIfParam(const char (&constPart)[N])
+ {
+ return constPart;
+ }
+
public:
+#define WITH_DEPRECATED_ERROR_VERSION(Recommended) \
+ Recommended, Recommended##Error Q_DECL_ENUMERATOR_DEPRECATED_X( \
+ "Use " #Recommended) = Recommended
+
/*! The status code of a job
*
* Every job is created in Unprepared status; upon calling prepare()
@@ -34,7 +47,7 @@ public:
*/
enum StatusCode {
Success = 0,
- NoError = Success, // To be compatible with Qt conventions
+ NoError = Success,
Pending = 1,
WarningLevel = 20, //< Warnings have codes starting from this
UnexpectedResponseType = 21,
@@ -43,28 +56,18 @@ public:
Abandoned = 50, //< A tiny period between abandoning and object deletion
ErrorLevel = 100, //< Errors have codes starting from this
NetworkError = 101,
- Timeout,
- TimeoutError = Timeout,
+ WITH_DEPRECATED_ERROR_VERSION(Timeout),
Unauthorised,
ContentAccessError,
- NotFoundError,
- IncorrectRequest,
- IncorrectRequestError = IncorrectRequest,
- IncorrectResponse,
- IncorrectResponseError = IncorrectResponse,
- JsonParseError //< \deprecated Use IncorrectResponse instead
- = IncorrectResponse,
- TooManyRequests,
- TooManyRequestsError = TooManyRequests,
+ WITH_DEPRECATED_ERROR_VERSION(NotFound),
+ WITH_DEPRECATED_ERROR_VERSION(IncorrectRequest),
+ WITH_DEPRECATED_ERROR_VERSION(IncorrectResponse),
+ WITH_DEPRECATED_ERROR_VERSION(TooManyRequests),
RateLimited = TooManyRequests,
- RequestNotImplemented,
- RequestNotImplementedError = RequestNotImplemented,
- UnsupportedRoomVersion,
- UnsupportedRoomVersionError = UnsupportedRoomVersion,
- NetworkAuthRequired,
- NetworkAuthRequiredError = NetworkAuthRequired,
- UserConsentRequired,
- UserConsentRequiredError = UserConsentRequired,
+ WITH_DEPRECATED_ERROR_VERSION(RequestNotImplemented),
+ WITH_DEPRECATED_ERROR_VERSION(UnsupportedRoomVersion),
+ WITH_DEPRECATED_ERROR_VERSION(NetworkAuthRequired),
+ WITH_DEPRECATED_ERROR_VERSION(UserConsentRequired),
CannotLeaveRoom,
UserDeactivated,
FileError,
@@ -72,7 +75,19 @@ public:
};
Q_ENUM(StatusCode)
- using Data = RequestData;
+#undef WITH_DEPRECATED_ERROR_VERSION
+
+ template <typename... StrTs>
+ static QByteArray makePath(StrTs&&... parts)
+ {
+ return (QByteArray() % ... % encodeIfParam(parts));
+ }
+
+ using Data
+#ifndef Q_CC_MSVC
+ Q_DECL_DEPRECATED_X("Use Quotient::RequestData instead")
+#endif
+ = RequestData;
/*!
* This structure stores the status of a server call job. The status
@@ -122,10 +137,11 @@ public:
};
public:
- BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
+ BaseJob(HttpVerb verb, const QString& name, QByteArray endpoint,
+ bool needsToken = true);
+ BaseJob(HttpVerb verb, const QString& name, QByteArray endpoint,
+ const QUrlQuery& query, RequestData&& data = {},
bool needsToken = true);
- BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
- const QUrlQuery& query, Data&& data = {}, bool needsToken = true);
QUrl requestUrl() const;
bool isBackground() const;
@@ -180,7 +196,7 @@ public:
* If there's no top-level JSON object in the response or if there's
* no node with the key \p keyName, \p defaultValue is returned.
*/
- template <typename T, typename StrT> // Waiting for QStringViews...
+ template <typename T, typename StrT>
T loadFromJson(const StrT& keyName, T&& defaultValue = {}) const
{
const auto& jv = jsonData().value(keyName);
@@ -322,16 +338,18 @@ Q_SIGNALS:
protected:
using headers_t = QHash<QByteArray, QByteArray>;
+ Q_DECL_DEPRECATED_X("Deprecated due to being unused")
const QString& apiEndpoint() const;
+ Q_DECL_DEPRECATED_X("Deprecated due to being unused")
void setApiEndpoint(const QString& apiEndpoint);
const headers_t& requestHeaders() const;
void setRequestHeader(const headers_t::key_type& headerName,
const headers_t::mapped_type& headerValue);
void setRequestHeaders(const headers_t& headers);
- const QUrlQuery& query() const;
+ QUrlQuery query() const;
void setRequestQuery(const QUrlQuery& query);
- const Data& requestData() const;
- void setRequestData(Data&& data);
+ const RequestData& requestData() const;
+ void setRequestData(RequestData&& data);
const QByteArrayList& expectedContentTypes() const;
void addExpectedContentType(const QByteArray& contentType);
void setExpectedContentTypes(const QByteArrayList& contentTypes);
@@ -347,7 +365,7 @@ protected:
* The function ensures exactly one '/' between the path component of
* \p baseUrl and \p path. The query component of \p baseUrl is ignored.
*/
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& path,
+ static QUrl makeRequestUrl(QUrl baseUrl, const QByteArray &encodedPath,
const QUrlQuery& query = {});
/*! Prepares the job for execution
@@ -381,10 +399,12 @@ protected:
* was not good (usually because of an unsuccessful HTTP code).
* The base implementation assumes Matrix JSON error object in the body;
* overrides are strongly recommended to call it for all stock Matrix
- * responses as early as possible but in addition can process custom errors,
+ * responses as early as possible and only then process custom errors,
* with JSON or non-JSON payload.
+ *
+ * \return updated (if necessary) job status
*/
- virtual Status prepareError();
+ virtual Status prepareError(Status currentStatus);
/*! \brief Get direct access to the JSON response object in the job
*
diff --git a/lib/jobs/requestdata.h b/lib/jobs/requestdata.h
index 21657631..4f05e5ff 100644
--- a/lib/jobs/requestdata.h
+++ b/lib/jobs/requestdata.h
@@ -35,5 +35,3 @@ private:
std::unique_ptr<QIODevice> _source;
};
} // namespace Quotient
-/// \deprecated Use namespace Quotient instead
-namespace QMatrixClient = Quotient;
diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp
index 59a34ef3..9b1b46f0 100644
--- a/lib/jobs/syncjob.cpp
+++ b/lib/jobs/syncjob.cpp
@@ -10,7 +10,7 @@ static size_t jobId = 0;
SyncJob::SyncJob(const QString& since, const QString& filter, int timeout,
const QString& presence)
: BaseJob(HttpVerb::Get, QStringLiteral("SyncJob-%1").arg(++jobId),
- QStringLiteral("_matrix/client/r0/sync"))
+ "_matrix/client/r0/sync")
{
setLoggingCategory(SYNCJOB);
QUrlQuery query;
diff --git a/lib/logging.cpp b/lib/logging.cpp
index ffcc851c..15eac69d 100644
--- a/lib/logging.cpp
+++ b/lib/logging.cpp
@@ -17,4 +17,5 @@ LOGGING_CATEGORY(E2EE, "quotient.e2ee")
LOGGING_CATEGORY(JOBS, "quotient.jobs")
LOGGING_CATEGORY(SYNCJOB, "quotient.jobs.sync")
LOGGING_CATEGORY(THUMBNAILJOB, "quotient.jobs.thumbnail")
+LOGGING_CATEGORY(NETWORK, "quotient.network")
LOGGING_CATEGORY(PROFILER, "quotient.profiler")
diff --git a/lib/logging.h b/lib/logging.h
index 264215e1..7e0da975 100644
--- a/lib/logging.h
+++ b/lib/logging.h
@@ -17,6 +17,7 @@ Q_DECLARE_LOGGING_CATEGORY(E2EE)
Q_DECLARE_LOGGING_CATEGORY(JOBS)
Q_DECLARE_LOGGING_CATEGORY(SYNCJOB)
Q_DECLARE_LOGGING_CATEGORY(THUMBNAILJOB)
+Q_DECLARE_LOGGING_CATEGORY(NETWORK)
Q_DECLARE_LOGGING_CATEGORY(PROFILER)
namespace Quotient {
@@ -67,8 +68,6 @@ inline qint64 profilerMinNsecs()
* 1000;
}
} // namespace Quotient
-/// \deprecated Use namespace Quotient instead
-namespace QMatrixClient = Quotient;
inline QDebug operator<<(QDebug debug_object, const QElapsedTimer& et)
{
diff --git a/lib/mxcreply.cpp b/lib/mxcreply.cpp
new file mode 100644
index 00000000..0b6643fc
--- /dev/null
+++ b/lib/mxcreply.cpp
@@ -0,0 +1,70 @@
+// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "mxcreply.h"
+
+#include "room.h"
+
+using namespace Quotient;
+
+class MxcReply::Private
+{
+public:
+ explicit Private(QNetworkReply* r = nullptr)
+ : m_reply(r)
+ {}
+ QNetworkReply* m_reply;
+};
+
+MxcReply::MxcReply(QNetworkReply* reply)
+ : d(std::make_unique<Private>(reply))
+{
+ reply->setParent(this);
+ connect(d->m_reply, &QNetworkReply::finished, this, [this]() {
+ setError(d->m_reply->error(), d->m_reply->errorString());
+ setOpenMode(ReadOnly);
+ Q_EMIT finished();
+ });
+}
+
+MxcReply::MxcReply(QNetworkReply* reply, Room* room, const QString &eventId)
+ : d(std::make_unique<Private>(reply))
+{
+ reply->setParent(this);
+ connect(d->m_reply, &QNetworkReply::finished, this, [this, room, eventId]() {
+ setError(d->m_reply->error(), d->m_reply->errorString());
+ setOpenMode(ReadOnly);
+ emit finished();
+ });
+}
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+#define ERROR_SIGNAL errorOccurred
+#else
+#define ERROR_SIGNAL error
+#endif
+
+MxcReply::MxcReply()
+{
+ static const auto BadRequestPhrase = tr("Bad Request");
+ QMetaObject::invokeMethod(this, [this]() {
+ setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 400);
+ setAttribute(QNetworkRequest::HttpReasonPhraseAttribute,
+ BadRequestPhrase);
+ setError(QNetworkReply::ProtocolInvalidOperationError,
+ BadRequestPhrase);
+ setFinished(true);
+ emit ERROR_SIGNAL(QNetworkReply::ProtocolInvalidOperationError);
+ emit finished();
+ }, Qt::QueuedConnection);
+}
+
+qint64 MxcReply::readData(char *data, qint64 maxSize)
+{
+ return d->m_reply->read(data, maxSize);
+}
+
+void MxcReply::abort()
+{
+ d->m_reply->abort();
+}
diff --git a/lib/mxcreply.h b/lib/mxcreply.h
new file mode 100644
index 00000000..efaf01c6
--- /dev/null
+++ b/lib/mxcreply.h
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include <QtNetwork/QNetworkReply>
+#include <memory>
+
+namespace Quotient {
+class Room;
+
+class MxcReply : public QNetworkReply
+{
+public:
+ explicit MxcReply();
+ explicit MxcReply(QNetworkReply *reply);
+ MxcReply(QNetworkReply* reply, Room* room, const QString& eventId);
+
+public Q_SLOTS:
+ void abort() override;
+
+protected:
+ qint64 readData(char *data, qint64 maxSize) override;
+
+private:
+ class Private;
+ std::unique_ptr<Private> d;
+};
+}
diff --git a/lib/networkaccessmanager.cpp b/lib/networkaccessmanager.cpp
index a94ead34..57618329 100644
--- a/lib/networkaccessmanager.cpp
+++ b/lib/networkaccessmanager.cpp
@@ -3,18 +3,43 @@
#include "networkaccessmanager.h"
+#include "connection.h"
+#include "room.h"
+#include "accountregistry.h"
+#include "mxcreply.h"
+
#include <QtCore/QCoreApplication>
+#include <QtCore/QThreadStorage>
+#include <QtCore/QSettings>
#include <QtNetwork/QNetworkReply>
using namespace Quotient;
class NetworkAccessManager::Private {
public:
+ explicit Private(NetworkAccessManager* q)
+ : q(q)
+ {}
+
+ QNetworkReply* createImplRequest(Operation op,
+ const QNetworkRequest& outerRequest,
+ Connection* connection)
+ {
+ Q_ASSERT(outerRequest.url().scheme() == "mxc");
+ QNetworkRequest r(outerRequest);
+ r.setUrl(QUrl(QStringLiteral("%1/_matrix/media/r0/download/%2")
+ .arg(connection->homeserver().toString(),
+ outerRequest.url().authority()
+ + outerRequest.url().path())));
+ return q->createRequest(op, r);
+ }
+
+ NetworkAccessManager* q;
QList<QSslError> ignoredSslErrors;
};
NetworkAccessManager::NetworkAccessManager(QObject* parent)
- : QNetworkAccessManager(parent), d(std::make_unique<Private>())
+ : QNetworkAccessManager(parent), d(std::make_unique<Private>(this))
{}
QList<QSslError> NetworkAccessManager::ignoredSslErrors() const
@@ -34,7 +59,7 @@ void NetworkAccessManager::clearIgnoredSslErrors()
static NetworkAccessManager* createNam()
{
- auto nam = new NetworkAccessManager(QCoreApplication::instance());
+ auto nam = new NetworkAccessManager();
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
// See #109; in newer Qt, bearer management is deprecated altogether
NetworkAccessManager::connect(nam,
@@ -47,8 +72,11 @@ static NetworkAccessManager* createNam()
NetworkAccessManager* NetworkAccessManager::instance()
{
- static auto* nam = createNam();
- return nam;
+ static QThreadStorage<NetworkAccessManager*> storage;
+ if(!storage.hasLocalData()) {
+ storage.setLocalData(createNam());
+ }
+ return storage.localData();
}
NetworkAccessManager::~NetworkAccessManager() = default;
@@ -56,7 +84,49 @@ NetworkAccessManager::~NetworkAccessManager() = default;
QNetworkReply* NetworkAccessManager::createRequest(
Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
+ const auto& mxcUrl = request.url();
+ if (mxcUrl.scheme() == "mxc") {
+ const QUrlQuery query(mxcUrl.query());
+ const auto accountId = query.queryItemValue(QStringLiteral("user_id"));
+ if (accountId.isEmpty()) {
+ // Using QSettings here because Quotient::NetworkSettings
+ // doesn't provide multithreading guarantees
+ static thread_local QSettings s;
+ if (!s.value("Network/allow_direct_media_requests").toBool()) {
+ qCWarning(NETWORK) << "No connection specified";
+ return new MxcReply();
+ }
+ // TODO: Make the best effort with a direct unauthenticated request
+ // to the media server
+ } else {
+ auto* const connection = AccountRegistry::instance().get(accountId);
+ if (!connection) {
+ qCWarning(NETWORK) << "Connection" << accountId << "not found";
+ return new MxcReply();
+ }
+ const auto roomId = query.queryItemValue(QStringLiteral("room_id"));
+ if (!roomId.isEmpty()) {
+ auto room = connection->room(roomId);
+ if (!room) {
+ qCWarning(NETWORK) << "Room" << roomId << "not found";
+ return new MxcReply();
+ }
+ return new MxcReply(
+ d->createImplRequest(op, request, connection), room,
+ query.queryItemValue(QStringLiteral("event_id")));
+ }
+ return new MxcReply(
+ d->createImplRequest(op, request, connection));
+ }
+ }
auto reply = QNetworkAccessManager::createRequest(op, request, outgoingData);
reply->ignoreSslErrors(d->ignoredSslErrors);
return reply;
}
+
+QStringList NetworkAccessManager::supportedSchemesImplementation() const
+{
+ auto schemes = QNetworkAccessManager::supportedSchemesImplementation();
+ schemes += QStringLiteral("mxc");
+ return schemes;
+}
diff --git a/lib/networkaccessmanager.h b/lib/networkaccessmanager.h
index 47729a1b..87bc12a1 100644
--- a/lib/networkaccessmanager.h
+++ b/lib/networkaccessmanager.h
@@ -8,6 +8,8 @@
#include <memory>
namespace Quotient {
+class Room;
+class Connection;
class NetworkAccessManager : public QNetworkAccessManager {
Q_OBJECT
public:
@@ -21,6 +23,9 @@ public:
/** Get a pointer to the singleton */
static NetworkAccessManager* instance();
+public Q_SLOTS:
+ QStringList supportedSchemesImplementation() const;
+
private:
QNetworkReply* createRequest(Operation op, const QNetworkRequest& request,
QIODevice* outgoingData = Q_NULLPTR) override;
diff --git a/lib/qt_connection_util.h b/lib/qt_connection_util.h
index c6fa037a..46294499 100644
--- a/lib/qt_connection_util.h
+++ b/lib/qt_connection_util.h
@@ -19,12 +19,7 @@ namespace _impl {
decorated_slot_tt<ArgTs...> decoratedSlot,
Qt::ConnectionType connType)
{
- // See https://bugreports.qt.io/browse/QTBUG-60339
-#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
- auto pc = std::make_shared<QMetaObject::Connection>();
-#else
auto pc = std::make_unique<QMetaObject::Connection>();
-#endif
auto& c = *pc; // Resolve a reference before pc is moved to lambda
// Perfect forwarding doesn't work through signal-slot connections -
@@ -73,6 +68,17 @@ namespace _impl {
}),
connType);
}
+
+ // TODO: get rid of it as soon as Apple Clang gets proper deduction guides
+ // for std::function<>
+ // ...or consider using QtPrivate magic used by QObject::connect()
+ // ...for inspiration, also check a possible std::not_fn implementation
+ // at https://en.cppreference.com/w/cpp/utility/functional/not_fn
+ template <typename FnT>
+ inline auto wrap_in_function(FnT&& f)
+ {
+ return typename function_traits<FnT>::function_type(std::forward<FnT>(f));
+ }
} // namespace _impl
/*! \brief Create a connection that self-disconnects when its "slot" returns true
@@ -90,7 +96,7 @@ inline auto connectUntil(SenderT* sender, SignalT signal, ContextT* context,
const FunctorT& slot,
Qt::ConnectionType connType = Qt::AutoConnection)
{
- return _impl::connectUntil(sender, signal, context, wrap_in_function(slot),
+ return _impl::connectUntil(sender, signal, context, _impl::wrap_in_function(slot),
connType);
}
@@ -100,8 +106,13 @@ inline auto connectSingleShot(SenderT* sender, SignalT signal,
ContextT* context, const FunctorT& slot,
Qt::ConnectionType connType = Qt::AutoConnection)
{
+#if QT_VERSION_MAJOR >= 6
+ return QObject::connect(sender, signal, context, slot,
+ Qt::ConnectionType(connType
+ | Qt::SingleShotConnection));
+#else
return _impl::connectSingleShot(
- sender, signal, context, wrap_in_function(slot), connType);
+ sender, signal, context, _impl::wrap_in_function(slot), connType);
}
// Specialisation for usual Qt slots passed as pointers-to-members.
@@ -114,11 +125,12 @@ inline auto connectSingleShot(SenderT* sender, SignalT signal,
{
// TODO: when switching to C++20, use std::bind_front() instead
return _impl::connectSingleShot(sender, signal, receiver,
- wrap_in_function(
+ _impl::wrap_in_function(
[receiver, slot](const ArgTs&... args) {
(receiver->*slot)(args...);
}),
connType);
+#endif
}
/*! \brief A guard pointer that disconnects an interested object upon destruction
diff --git a/lib/quotient_common.h b/lib/quotient_common.h
index d225ad63..13bf7246 100644
--- a/lib/quotient_common.h
+++ b/lib/quotient_common.h
@@ -10,22 +10,17 @@
namespace Quotient {
Q_NAMESPACE
-namespace impl {
- template <class T, std::size_t N, std::size_t... I>
- constexpr std::array<std::remove_cv_t<T>, N>
- to_array_impl(T (&&a)[N], std::index_sequence<I...>)
- {
- return { {std::move(a[I])...} };
- }
-}
// std::array {} needs explicit template parameters on macOS because
-// Apple stdlib doesn't have deduction guides for std::array; to alleviate that,
-// to_array() is borrowed from C++20 (thanks to cppreference for the possible
-// implementation: https://en.cppreference.com/w/cpp/container/array/to_array)
-template <typename T, size_t N>
-constexpr auto to_array(T (&& items)[N])
+// Apple stdlib doesn't have deduction guides for std::array. C++20 has
+// to_array() but that can't be borrowed, this time because of MSVC:
+// https://developercommunity.visualstudio.com/t/vc-ice-p1-initc-line-3652-from-stdto-array/1464038
+// Therefore a simpler (but also slightly more wobbly - it resolves the element
+// type using std::common_type<>) make_array facility is implemented here.
+template <typename... Ts>
+constexpr auto make_array(Ts&&... items)
{
- return impl::to_array_impl(std::move(items), std::make_index_sequence<N>{});
+ return std::array<std::common_type_t<Ts...>, sizeof...(items)>(
+ { std::forward<Ts>(items)... });
}
// TODO: code like this should be generated from the CS API definition
@@ -49,9 +44,9 @@ enum class Membership : unsigned int {
Q_DECLARE_FLAGS(MembershipMask, Membership)
Q_FLAG_NS(MembershipMask)
-constexpr inline auto MembershipStrings = to_array(
+constexpr inline auto MembershipStrings = make_array(
// The order MUST be the same as the order in the original enum
- { "join", "leave", "invite", "knock", "ban" });
+ "join", "leave", "invite", "knock", "ban");
//! \brief Local user join-state names
//!
@@ -68,10 +63,10 @@ enum class JoinState : std::underlying_type_t<Membership> {
Q_DECLARE_FLAGS(JoinStates, JoinState)
Q_FLAG_NS(JoinStates)
-constexpr inline auto JoinStateStrings = to_array({
+constexpr inline auto JoinStateStrings = make_array(
MembershipStrings[0], MembershipStrings[1], MembershipStrings[2],
MembershipStrings[3] /* same as MembershipStrings, sans "ban" */
-});
+);
//! \brief Network job running policy flags
//!
@@ -93,6 +88,16 @@ enum UriResolveResult : short {
};
Q_ENUM_NS(UriResolveResult)
+enum RoomType {
+ Space,
+ Undefined,
+};
+Q_ENUM_NS(RoomType)
+
+constexpr inline auto RoomTypeStrings = make_array(
+ "m.space"
+);
+
} // namespace Quotient
Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::MembershipMask)
Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::JoinStates)
diff --git a/lib/room.cpp b/lib/room.cpp
index 8462902f..a2b99039 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -101,8 +101,8 @@ public:
UnorderedMap<StateEventKey, StateEventPtr> baseState;
/// State event stubs - events without content, just type and state key
static decltype(baseState) stubbedState;
- /// The state of the room at timeline position after-maxTimelineIndex()
- /// \sa Room::syncEdge
+ /// The state of the room at syncEdge()
+ /// \sa syncEdge
QHash<StateEventKey, const StateEventBase*> currentState;
/// Servers with aliases for this room except the one of the local user
/// \sa Room::remoteAliases
@@ -198,6 +198,8 @@ public:
/// A point in the timeline corresponding to baseState
rev_iter_t timelineBase() const { return q->findInTimeline(-1); }
+ rev_iter_t historyEdge() const { return timeline.crend(); }
+ Timeline::const_iterator syncEdge() const { return timeline.cend(); }
void getPreviousContent(int limit = 10, const QString &filter = {});
@@ -548,6 +550,11 @@ QString Room::canonicalAlias() const
QString Room::displayName() const { return d->displayname; }
+QString Room::displayNameForHtml() const
+{
+ return displayName().toHtmlEscaped();
+}
+
void Room::refreshDisplayName() { d->updateDisplayname(); }
QString Room::topic() const
@@ -589,9 +596,14 @@ JoinState Room::memberJoinState(User* user) const
: JoinState::Leave;
}
-Membership Room::memberState(User* user) const
+Membership Room::memberState(const QString& userId) const
+{
+ return d->getCurrentState<RoomMemberEvent>(userId)->membership();
+}
+
+bool Room::isMember(const QString& userId) const
{
- return d->getCurrentState<RoomMemberEvent>(user->id())->membership();
+ return memberState(userId) == Membership::Join;
}
JoinState Room::joinState() const { return d->joinState; }
@@ -616,7 +628,7 @@ void Room::Private::setLastReadReceipt(User* u, rev_iter_t newMarker,
qCCritical(MAIN) << "Empty user, skipping read receipt registration";
return; // For Release builds
}
- if (q->memberJoinState(u) != JoinState::Join) {
+ if (!q->isMember(u->id())) {
qCWarning(EPHEMERAL)
<< "Won't record read receipt for non-member" << u->id();
return;
@@ -674,7 +686,7 @@ Room::Changes Room::Private::updateUnreadCount(const rev_iter_t& from,
if (fullyReadMarker < from)
return NoChange; // What's arrived is already fully read
- if (fullyReadMarker == timeline.crend() && q->allHistoryLoaded())
+ if (fullyReadMarker == historyEdge() && q->allHistoryLoaded())
--fullyReadMarker; // No read marker in the whole room, initialise it
if (fullyReadMarker < to) {
// Catch a special case when the last fully read event id refers to an
@@ -763,7 +775,7 @@ Room::Changes Room::Private::setFullyReadMarker(const QString& eventId)
emit q->readMarkerMoved(prevFullyReadId, fullyReadUntilEventId);
Changes changes = ReadMarkerChange;
- if (const auto rm = q->fullyReadMarker(); rm != timeline.crend()) {
+ if (const auto rm = q->fullyReadMarker(); rm != historyEdge()) {
// Pull read receipt if it's behind
setLastReadReceipt(q->localUser(), rm);
changes |= recalculateUnreadCount(); // TODO: updateUnreadCount()?
@@ -822,12 +834,9 @@ bool Room::hasUnreadMessages() const { return unreadCount() >= 0; }
int Room::unreadCount() const { return d->unreadMessages; }
-Room::rev_iter_t Room::historyEdge() const { return d->timeline.crend(); }
+Room::rev_iter_t Room::historyEdge() const { return d->historyEdge(); }
-Room::Timeline::const_iterator Room::syncEdge() const
-{
- return d->timeline.cend();
-}
+Room::Timeline::const_iterator Room::syncEdge() const { return d->syncEdge(); }
TimelineItem::index_t Room::minTimelineIndex() const
{
@@ -906,7 +915,7 @@ void Room::Private::getAllMembers()
// the full members list was requested.
if (!timeline.empty())
for (auto it = q->findInTimeline(nextIndex).base();
- it != timeline.cend(); ++it)
+ it != syncEdge(); ++it)
if (is<RoomMemberEvent>(**it))
roomChanges |= q->processStateEvent(**it);
if (roomChanges & MembersChange)
@@ -1164,6 +1173,17 @@ QList<User*> Room::directChatUsers() const
return connection()->directChatUsers(this);
}
+QUrl Room::makeMediaUrl(const QString& eventId, const QUrl& mxcUrl) const
+{
+ auto url = connection()->makeMediaUrl(mxcUrl);
+ QUrlQuery q(url.query());
+ Q_ASSERT(q.hasQueryItem("user_id"));
+ q.addQueryItem("room_id", id());
+ q.addQueryItem("event_id", eventId);
+ url.setQuery(q);
+ return url;
+}
+
QString safeFileName(QString rawName)
{
return rawName.replace(QRegularExpression("[/\\<>|\"*?:]"), "_");
@@ -1217,9 +1237,8 @@ QUrl Room::urlToThumbnail(const QString& eventId) const
if (event->hasThumbnail()) {
auto* thumbnail = event->content()->thumbnailInfo();
Q_ASSERT(thumbnail != nullptr);
- return MediaThumbnailJob::makeRequestUrl(connection()->homeserver(),
- thumbnail->url,
- thumbnail->imageSize);
+ return connection()->getUrlForApi<MediaThumbnailJob>(
+ thumbnail->url, thumbnail->imageSize);
}
qCDebug(MAIN) << "Event" << eventId << "has no thumbnail";
return {};
@@ -1230,8 +1249,7 @@ QUrl Room::urlToDownload(const QString& eventId) const
if (auto* event = d->getEventWithFile(eventId)) {
auto* fileInfo = event->content()->fileInfo();
Q_ASSERT(fileInfo != nullptr);
- return DownloadFileJob::makeRequestUrl(connection()->homeserver(),
- fileInfo->url);
+ return connection()->getUrlForApi<DownloadFileJob>(fileInfo->url);
}
return {};
}
@@ -1294,7 +1312,7 @@ QList<User*> Room::membersLeft() const { return d->membersLeft; }
QList<User*> Room::users() const { return d->membersMap.values(); }
-[[deprecated]] QStringList Room::memberNames() const
+QStringList Room::memberNames() const
{
return safeMemberNames();
}
@@ -1565,7 +1583,7 @@ QString Room::disambiguatedMemberName(const QString& mxId) const
QString Room::safeMemberName(const QString& userId) const
{
- return sanitized(roomMembername(userId));
+ return sanitized(disambiguatedMemberName(userId));
}
QString Room::htmlSafeMemberName(const QString& userId) const
@@ -1756,6 +1774,12 @@ QString Room::retryMessage(const QString& txnId)
return d->doSendEvent(it->event());
}
+// Lambda defers actual tr() invocation to the moment when translations are
+// initialised
+const auto FileTransferCancelledMsg = [] {
+ return Room::tr("File transfer cancelled");
+};
+
void Room::discardMessage(const QString& txnId)
{
auto it = std::find_if(d->unsyncedEvents.begin(), d->unsyncedEvents.end(),
@@ -1770,7 +1794,7 @@ void Room::discardMessage(const QString& txnId)
if (isJobPending(transferIt->job)) {
transferIt->status = FileTransferInfo::Cancelled;
transferIt->job->abandon();
- emit fileTransferFailed(txnId, tr("File upload cancelled"));
+ emit fileTransferFailed(txnId, FileTransferCancelledMsg());
} else if (transferIt->status == FileTransferInfo::Completed) {
qCWarning(MAIN)
<< "File for transaction" << txnId
@@ -1838,7 +1862,7 @@ QString Room::Private::doPostFile(RoomEventPtr&& msgEvent, const QUrl& localUrl)
"cancelled";
}
});
- connect(q, &Room::fileTransferCancelled, transferJob,
+ connect(q, &Room::fileTransferFailed, transferJob,
[this, txnId](const QString& tId) {
if (tId != txnId)
return;
@@ -2127,16 +2151,16 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
void Room::cancelFileTransfer(const QString& id)
{
- const auto it = d->fileTransfers.constFind(id);
- if (it == d->fileTransfers.cend()) {
+ const auto it = d->fileTransfers.find(id);
+ if (it == d->fileTransfers.end()) {
qCWarning(MAIN) << "No information on file transfer" << id << "in room"
<< d->id;
return;
}
if (isJobPending(it->job))
it->job->abandon();
- d->fileTransfers.remove(id);
- emit fileTransferCancelled(id);
+ it->status = FileTransferInfo::Cancelled;
+ emit fileTransferFailed(id, FileTransferCancelledMsg());
}
void Room::Private::dropDuplicateEvents(RoomEvents& events) const
@@ -2414,7 +2438,7 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
emit q->aboutToAddNewMessages(eventsSpan);
auto insertedSize = moveEventsToTimeline(eventsSpan, Newer);
totalInserted += insertedSize;
- auto firstInserted = timeline.cend() - insertedSize;
+ auto firstInserted = syncEdge() - insertedSize;
q->onAddNewTimelineEvents(firstInserted);
emit q->addedMessages(firstInserted->index(),
timeline.back().index());
@@ -2444,20 +2468,20 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
unsyncedEvents.erase(unsyncedEvents.begin() + pendingEvtIdx);
if (auto insertedSize = moveEventsToTimeline({ remoteEcho, it }, Newer)) {
totalInserted += insertedSize;
- q->onAddNewTimelineEvents(timeline.cend() - insertedSize);
+ q->onAddNewTimelineEvents(syncEdge() - insertedSize);
}
emit q->pendingEventMerged();
}
// Events merged and transferred from `events` to `timeline` now.
- const auto from = timeline.cend() - totalInserted;
+ const auto from = syncEdge() - totalInserted;
if (q->supportsCalls())
- for (auto it = from; it != timeline.cend(); ++it)
+ for (auto it = from; it != syncEdge(); ++it)
if (const auto* evt = it->viewAs<CallEventBase>())
emit q->callEvent(q, evt);
if (totalInserted > 0) {
- for (auto it = from; it != timeline.cend(); ++it) {
+ for (auto it = from; it != syncEdge(); ++it) {
if (const auto* reaction = it->viewAs<ReactionEvent>()) {
const auto& relation = reaction->relation();
relations[{ relation.eventId, relation.type }] << reaction;
@@ -2517,25 +2541,25 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events)
emit q->aboutToAddHistoricalMessages(events);
const auto insertedSize = moveEventsToTimeline(events, Older);
- const auto from = timeline.crend() - insertedSize;
+ const auto from = historyEdge() - insertedSize;
qCDebug(STATE) << "Room" << displayname << "received" << insertedSize
<< "past events; the oldest event is now" << timeline.front();
q->onAddHistoricalTimelineEvents(from);
emit q->addedMessages(timeline.front().index(), from->index());
- for (auto it = from; it != timeline.crend(); ++it) {
+ for (auto it = from; it != historyEdge(); ++it) {
if (const auto* reaction = it->viewAs<ReactionEvent>()) {
const auto& relation = reaction->relation();
relations[{ relation.eventId, relation.type }] << reaction;
emit q->updatedEvent(relation.eventId);
}
}
- updateUnreadCount(from, timeline.crend());
+ updateUnreadCount(from, historyEdge());
// When there are no unread messages and the read marker is within the
// known timeline, unreadMessages == -1
// (see https://github.com/quotient-im/libQuotient/wiki/unread_count).
- Q_ASSERT(unreadMessages != 0 || q->fullyReadMarker() == timeline.crend());
+ Q_ASSERT(unreadMessages != 0 || q->fullyReadMarker() == historyEdge());
Q_ASSERT(timeline.size() == timelineSize + insertedSize);
if (insertedSize > 9 || et.nsecsElapsed() >= profilerMinNsecs())
@@ -2758,11 +2782,10 @@ Room::Changes Room::processEphemeralEvent(EventPtr&& event)
et.start();
if (auto* evt = eventCast<TypingEvent>(event)) {
d->usersTyping.clear();
- for (const auto& userId : evt->users()) {
- auto* const u = user(userId);
- if (memberJoinState(u) == JoinState::Join)
- d->usersTyping.append(u);
- }
+ for (const auto& userId : evt->users())
+ if (isMember(userId))
+ d->usersTyping.append(user(userId));
+
if (evt->users().size() > 3 || et.nsecsElapsed() >= profilerMinNsecs())
qCDebug(PROFILER) << "*** Room::processEphemeralEvent(typing):"
<< evt->users().size() << "users," << et;
@@ -2786,8 +2809,7 @@ Room::Changes Room::processEphemeralEvent(EventPtr&& event)
qCDebug(EPHEMERAL) << "Event of the read receipt(s) is not "
"found; saving them anyway";
for (const Receipt& r : p.receipts)
- if (auto* const u = user(r.userId);
- memberJoinState(u) == JoinState::Join) {
+ if (isMember(r.userId)) {
// If the event is not found (most likely, because it's
// too old and hasn't been fetched from the server yet)
// but there is a previous marker for a user, keep
@@ -2795,7 +2817,7 @@ Room::Changes Room::processEphemeralEvent(EventPtr&& event)
// supposed to move backwards. Otherwise, blindly
// store the event id for this user and update the read
// marker when/if the event is fetched later on.
- d->setLastReadReceipt(u, newMarker,
+ d->setLastReadReceipt(user(r.userId), newMarker,
{ p.evtId, r.timestamp });
}
}
@@ -3065,3 +3087,12 @@ bool MemberSorter::operator()(User* u1, QStringView u2name) const
return n1.localeAwareCompare(n2) < 0;
}
+
+void Room::activateEncryption()
+{
+ if(usesEncryption()) {
+ qCWarning(E2EE) << "Room" << objectName() << "is already encrypted";
+ return;
+ }
+ setState<EncryptionEvent>(EncryptionEventContent::MegolmV1AesSha2);
+}
diff --git a/lib/room.h b/lib/room.h
index a8c3cac2..ca9f36cb 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -107,6 +107,7 @@ class Room : public QObject {
Q_PROPERTY(QStringList altAliases READ altAliases NOTIFY namesChanged)
Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
Q_PROPERTY(QString displayName READ displayName NOTIFY displaynameChanged)
+ Q_PROPERTY(QString displayNameForHtml READ displayNameForHtml NOTIFY displaynameChanged)
Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
STORED false)
@@ -131,7 +132,7 @@ class Room : public QObject {
Q_PROPERTY(QString lastFullyReadEventId READ lastFullyReadEventId WRITE
markMessagesAsRead NOTIFY fullyReadMarkerMoved)
Q_PROPERTY(bool hasUnreadMessages READ hasUnreadMessages NOTIFY
- unreadMessagesChanged)
+ unreadMessagesChanged STORED false)
Q_PROPERTY(int unreadCount READ unreadCount NOTIFY unreadMessagesChanged)
Q_PROPERTY(int highlightCount READ highlightCount NOTIFY
highlightCountChanged RESET resetHighlightCount)
@@ -140,8 +141,8 @@ class Room : public QObject {
Q_PROPERTY(bool allHistoryLoaded READ allHistoryLoaded NOTIFY addedMessages
STORED false)
Q_PROPERTY(QStringList tagNames READ tagNames NOTIFY tagsChanged)
- Q_PROPERTY(bool isFavourite READ isFavourite NOTIFY tagsChanged)
- Q_PROPERTY(bool isLowPriority READ isLowPriority NOTIFY tagsChanged)
+ Q_PROPERTY(bool isFavourite READ isFavourite NOTIFY tagsChanged STORED false)
+ Q_PROPERTY(bool isLowPriority READ isLowPriority NOTIFY tagsChanged STORED false)
Q_PROPERTY(GetRoomEventsJob* eventsHistoryJob READ eventsHistoryJob NOTIFY
eventsHistoryJobChanged)
@@ -207,6 +208,7 @@ public:
//! Get a list of both canonical and alternative aliases
QStringList aliases() const;
QString displayName() const;
+ QString displayNameForHtml() const;
QString topic() const;
QString avatarMediaId() const;
QUrl avatarUrl() const;
@@ -216,7 +218,7 @@ public:
QList<User*> membersLeft() const;
Q_INVOKABLE QList<Quotient::User*> users() const;
- [[deprecated("Use safeMemberNames() or htmlSafeMemberNames() instead")]]
+ Q_DECL_DEPRECATED_X("Use safeMemberNames() or htmlSafeMemberNames() instead") //
QStringList memberNames() const;
QStringList safeMemberNames() const;
QStringList htmlSafeMemberNames() const;
@@ -259,37 +261,32 @@ public:
/**
* \brief Check the join state of a given user in this room
*
- * \deprecated Use memberState and check against a mask
- *
* \note Banned and invited users are not tracked separately for now (Leave
* will be returned for them).
*
* \return Join if the user is a room member; Leave otherwise
*/
+ Q_DECL_DEPRECATED_X("Use isMember() instead")
Q_INVOKABLE Quotient::JoinState memberJoinState(Quotient::User* user) const;
//! \brief Check the join state of a given user in this room
//!
//! \return the given user's state with respect to the room
- Q_INVOKABLE Quotient::Membership memberState(User* user) const;
+ Q_INVOKABLE Quotient::Membership memberState(const QString& userId) const;
+
+ //! Check whether a user with the given id is a member of the room
+ Q_INVOKABLE bool isMember(const QString& userId) const;
//! \brief Get a display name (without disambiguation) for the given member
//!
//! \sa safeMemberName, htmlSafeMemberName
Q_INVOKABLE QString memberName(const QString& mxId) const;
- /*!
- * \brief Get a disambiguated name for the given user in the room context
- *
- * \deprecated use safeMemberName() instead
- */
+ //! \brief Get a disambiguated name for the given user in the room context
+ Q_DECL_DEPRECATED_X("Use safeMemberName() instead")
Q_INVOKABLE QString roomMembername(const Quotient::User* u) const;
- /*!
- * \brief Get a disambiguated name for a user with this id in the room
- * context
- *
- * \deprecated use safeMemberName() instead
- */
+ //! \brief Get a disambiguated name for a user with this id in the room
+ Q_DECL_DEPRECATED_X("Use safeMemberName() instead")
Q_INVOKABLE QString roomMembername(const QString& userId) const;
/*!
@@ -549,6 +546,9 @@ public:
/// Get the list of users this room is a direct chat with
QList<User*> directChatUsers() const;
+ Q_INVOKABLE QUrl makeMediaUrl(const QString& eventId,
+ const QUrl &mxcUrl) const;
+
Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId) const;
Q_INVOKABLE QUrl urlToDownload(const QString& eventId) const;
@@ -640,7 +640,7 @@ public Q_SLOTS:
QString postFile(const QString& plainText, EventContent::TypedBase* content);
#if QT_VERSION_MAJOR < 6
- /// \deprecated Use postFile(QString, MessageEventType, EventContent) instead
+ Q_DECL_DEPRECATED_X("Use postFile(QString, MessageEventType, EventContent)") //
QString postFile(const QString& plainText, const QUrl& localPath,
bool asGenericFile = false);
#endif
@@ -700,6 +700,12 @@ public Q_SLOTS:
void answerCall(const QString& callId, const QString& sdp);
void hangupCall(const QString& callId);
+ /**
+ * Activates encryption for this room.
+ * Warning: Cannot be undone
+ */
+ void activateEncryption();
+
Q_SIGNALS:
/// Initial set of state events has been loaded
/**
@@ -811,7 +817,8 @@ Q_SIGNALS:
void fileTransferProgress(QString id, qint64 progress, qint64 total);
void fileTransferCompleted(QString id, QUrl localFile, QUrl mxcUrl);
void fileTransferFailed(QString id, QString errorMessage = {});
- void fileTransferCancelled(QString id);
+ // fileTransferCancelled() is no more here; use fileTransferFailed() and
+ // check the transfer status instead
void callEvent(Quotient::Room* room, const Quotient::RoomEvent* event);
diff --git a/lib/settings.cpp b/lib/settings.cpp
index 1d36db27..ed9082b0 100644
--- a/lib/settings.cpp
+++ b/lib/settings.cpp
@@ -126,19 +126,6 @@ void AccountSettings::setHomeserver(const QUrl& url)
QString AccountSettings::userId() const { return group().section('/', -1); }
-QString AccountSettings::accessToken() const
-{
- return value(AccessTokenKey).toString();
-}
-
-void AccountSettings::setAccessToken(const QString& accessToken)
-{
- qCWarning(MAIN) << "Saving access_token to QSettings is insecure."
- " Developers, do it manually or contribute to share "
- "QtKeychain logic to libQuotient.";
- setValue(AccessTokenKey, accessToken);
-}
-
void AccountSettings::clearAccessToken()
{
legacySettings.remove(AccessTokenKey);
diff --git a/lib/settings.h b/lib/settings.h
index 84c54802..efd0d714 100644
--- a/lib/settings.h
+++ b/lib/settings.h
@@ -78,9 +78,8 @@ protected:
class SettingsGroup : public Settings {
public:
- template <typename... ArgTs>
- explicit SettingsGroup(QString path, ArgTs&&... qsettingsArgs)
- : Settings(std::forward<ArgTs>(qsettingsArgs)...)
+ explicit SettingsGroup(QString path, QObject* parent = nullptr)
+ : Settings(parent)
, groupPath(std::move(path))
{}
@@ -131,15 +130,11 @@ class AccountSettings : public SettingsGroup {
QTNT_DECLARE_SETTING(QString, deviceId, setDeviceId)
QTNT_DECLARE_SETTING(QString, deviceName, setDeviceName)
QTNT_DECLARE_SETTING(bool, keepLoggedIn, setKeepLoggedIn)
- /** \deprecated \sa setAccessToken */
- Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken)
Q_PROPERTY(QByteArray encryptionAccountPickle READ encryptionAccountPickle
WRITE setEncryptionAccountPickle)
public:
- template <typename... ArgTs>
- explicit AccountSettings(const QString& accountId, ArgTs&&... qsettingsArgs)
- : SettingsGroup("Accounts/" + accountId,
- std::forward<ArgTs>(qsettingsArgs)...)
+ explicit AccountSettings(const QString& accountId, QObject* parent = nullptr)
+ : SettingsGroup("Accounts/" + accountId, parent)
{}
QString userId() const;
@@ -147,11 +142,7 @@ public:
QUrl homeserver() const;
void setHomeserver(const QUrl& url);
- /** \deprecated \sa setToken */
- QString accessToken() const;
- /** \deprecated Storing accessToken in QSettings is unsafe,
- * see quotient-im/Quaternion#181 */
- void setAccessToken(const QString& accessToken);
+ Q_DECL_DEPRECATED_X("Access tokens are not stored in QSettings any more")
Q_INVOKABLE void clearAccessToken();
QByteArray encryptionAccountPickle();
diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp
index 3e0eff17..e86d3100 100644
--- a/lib/syncdata.cpp
+++ b/lib/syncdata.cpp
@@ -178,12 +178,7 @@ void SyncData::parseJson(const QJsonObject& json, const QString& baseDir)
auto rooms = json.value("rooms"_ls).toObject();
auto totalRooms = 0;
auto totalEvents = 0;
- // The first comparison shortcuts the loop when not all states are there
- // in the response (anything except "join" is only occasional, and "join"
- // intentionally comes first in the enum).
- for (size_t i = 0;
- static_cast<int>(i) < rooms.size() && i < JoinStateStrings.size(); ++i)
- {
+ for (size_t i = 0; i < JoinStateStrings.size(); ++i) {
// This assumes that MemberState values go over powers of 2: 1,2,4,...
const auto joinState = JoinState(1U << i);
const auto rs = rooms.value(JoinStateStrings[i]).toObject();
diff --git a/lib/user.cpp b/lib/user.cpp
index c97e33a4..88549e5d 100644
--- a/lib/user.cpp
+++ b/lib/user.cpp
@@ -65,7 +65,8 @@ User::~User() = default;
void User::load()
{
- auto *profileJob = connection()->callApi<GetUserProfileJob>(id());
+ auto* profileJob =
+ connection()->callApi<GetUserProfileJob>(QUrl::toPercentEncoding(id()));
connect(profileJob, &BaseJob::result, this, [this, profileJob] {
d->defaultName = profileJob->displayname();
d->defaultAvatar = Avatar(QUrl(profileJob->avatarUrl()));
@@ -81,7 +82,7 @@ bool User::isGuest() const
Q_ASSERT(!d->id.isEmpty() && d->id.startsWith('@'));
auto it = std::find_if_not(d->id.cbegin() + 1, d->id.cend(),
[](QChar c) { return c.isDigit(); });
- Q_ASSERT(it != d->id.end());
+ Q_ASSERT(it != d->id.cend());
return *it == ':';
}
@@ -92,8 +93,6 @@ QString User::name(const Room* room) const
return room ? room->memberName(id()) : d->defaultName;
}
-QString User::rawName(const Room* room) const { return name(room); }
-
void User::rename(const QString& newName)
{
const auto actualNewName = sanitized(newName);
@@ -134,17 +133,17 @@ template <typename SourceT>
inline bool User::doSetAvatar(SourceT&& source)
{
return d->defaultAvatar.upload(
- connection(), source, [this](const QString& contentUri) {
+ connection(), source, [this](const QUrl& contentUri) {
auto* j = connection()->callApi<SetAvatarUrlJob>(id(), contentUri);
connect(j, &BaseJob::success, this,
- [this, newUrl = QUrl(contentUri)] {
- if (newUrl == d->defaultAvatar.url()) {
- d->defaultAvatar.updateUrl(newUrl);
+ [this, contentUri] {
+ if (contentUri == d->defaultAvatar.url()) {
+ d->defaultAvatar.updateUrl(contentUri);
emit defaultAvatarChanged();
} else
qCWarning(MAIN) << "User" << id()
<< "already has avatar URL set to"
- << newUrl.toDisplayString();
+ << contentUri.toDisplayString();
});
});
}
@@ -161,7 +160,7 @@ bool User::setAvatar(QIODevice* source)
void User::removeAvatar()
{
- connection()->callApi<SetAvatarUrlJob>(id(), "");
+ connection()->callApi<SetAvatarUrlJob>(id(), QUrl());
}
void User::requestDirectChat() { connection()->requestDirectChat(this); }
@@ -184,8 +183,6 @@ QString User::fullName(const Room* room) const
return displayName.isEmpty() ? id() : (displayName % " (" % id() % ')');
}
-QString User::bridged() const { return {}; }
-
const Avatar& User::avatarObject(const Room* room) const
{
if (!room)
@@ -196,18 +193,18 @@ const Avatar& User::avatarObject(const Room* room) const
return d->otherAvatars.try_emplace(mediaId, url).first->second;
}
-QImage User::avatar(int dimension, const Room* room)
+QImage User::avatar(int dimension, const Room* room) const
{
return avatar(dimension, dimension, room);
}
-QImage User::avatar(int width, int height, const Room* room)
+QImage User::avatar(int width, int height, const Room* room) const
{
return avatar(width, height, room, [] {});
}
QImage User::avatar(int width, int height, const Room* room,
- const Avatar::get_callback_t& callback)
+ const Avatar::get_callback_t& callback) const
{
return avatarObject(room).get(connection(), width, height, callback);
}
diff --git a/lib/user.h b/lib/user.h
index e4560843..78b72bf2 100644
--- a/lib/user.h
+++ b/lib/user.h
@@ -22,7 +22,6 @@ class User : public QObject {
Q_PROPERTY(QString name READ name NOTIFY defaultNameChanged)
Q_PROPERTY(QString displayName READ displayname NOTIFY defaultNameChanged STORED false)
Q_PROPERTY(QString fullName READ fullName NOTIFY defaultNameChanged STORED false)
- Q_PROPERTY(QString bridgeName READ bridged NOTIFY defaultNameChanged STORED false)
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY defaultAvatarChanged STORED false)
Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY defaultAvatarChanged)
public:
@@ -40,18 +39,10 @@ public:
* This may be empty if the user didn't choose the name or cleared
* it. If the user is bridged, the bridge postfix (such as '(IRC)')
* is stripped out. No disambiguation for the room is done.
- * \sa displayName, rawName
+ * \sa displayName
*/
QString name(const Room* room = nullptr) const;
- /** Get the user name along with the bridge postfix
- * This function is similar to name() but appends the bridge postfix
- * (such as '(IRC)') to the user name. No disambiguation is done.
- * \sa name, displayName
- */
- [[deprecated("Bridge postfixes exist no more, use name() instead")]]
- QString rawName(const Room* room = nullptr) const;
-
/** Get the displayed user name
* When \p room is null, this method returns result of name() if
* the name is non-empty; otherwise it returns user id.
@@ -70,13 +61,6 @@ public:
*/
QString fullName(const Room* room = nullptr) const;
- /**
- * Returns the name of bridge the user is connected from or empty.
- */
- [[deprecated("Bridged status is no more supported; this always returns"
- " an empty string")]]
- QString bridged() const;
-
/** Whether the user is a guest
* As of now, the function relies on the convention used in Synapse
* that guests and only guests have all-numeric IDs. This may or
@@ -99,11 +83,11 @@ public:
*/
const Avatar& avatarObject(const Room* room = nullptr) const;
Q_INVOKABLE QImage avatar(int dimension,
- const Quotient::Room* room = nullptr);
+ const Quotient::Room* room = nullptr) const;
Q_INVOKABLE QImage avatar(int requestedWidth, int requestedHeight,
- const Quotient::Room* room = nullptr);
+ const Quotient::Room* room = nullptr) const;
QImage avatar(int width, int height, const Room* room,
- const Avatar::get_callback_t& callback);
+ const Avatar::get_callback_t& callback) const;
QString avatarMediaId(const Room* room = nullptr) const;
QUrl avatarUrl(const Room* room = nullptr) const;
diff --git a/lib/util.cpp b/lib/util.cpp
index 904bfd5a..2dfb09a6 100644
--- a/lib/util.cpp
+++ b/lib/util.cpp
@@ -14,9 +14,6 @@
static const auto RegExpOptions =
QRegularExpression::CaseInsensitiveOption
-#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
- | QRegularExpression::OptimizeOnFirstUsageOption // Default since 5.12
-#endif
| QRegularExpression::UseUnicodePropertiesOption;
// Converts all that looks like a URL into HTML links
@@ -33,7 +30,7 @@ void Quotient::linkifyUrls(QString& htmlEscapedText)
// comma or dot
static const QRegularExpression FullUrlRegExp(
QStringLiteral(
- R"(\b((www\.(?!\.)(?!(\w|\.|-)+@)|(https?|ftp|magnet|matrix):(//)?)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))"),
+ R"(\b((www\.(?!\.)(?!(\w|\.|-)+@)|(https?|ftp):(//)?\w|(magnet|matrix):)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))"),
RegExpOptions);
// email address:
// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
@@ -44,7 +41,7 @@ void Quotient::linkifyUrls(QString& htmlEscapedText)
// https://matrix.org/docs/spec/appendices.html#identifier-grammar
static const QRegularExpression MxIdRegExp(
QStringLiteral(
- R"((^|[^<>/])([!#@][-a-z0-9_=#/.]{1,252}:(?:\w|\.|-)+\.\w+(?::\d{1,5})?))"),
+ R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"),
RegExpOptions);
Q_ASSERT(FullUrlRegExp.isValid() && EmailAddressRegExp.isValid()
&& MxIdRegExp.isValid());
@@ -119,6 +116,26 @@ QString Quotient::serverPart(const QString& mxId)
return parser.match(mxId).captured(1);
}
+QString Quotient::versionString()
+{
+ return QStringLiteral(Quotient_VERSION_STRING);
+}
+
+int Quotient::majorVersion()
+{
+ return Quotient_VERSION_MAJOR;
+}
+
+int Quotient::minorVersion()
+{
+ return Quotient_VERSION_MINOR;
+}
+
+int Quotient::patchVersion()
+{
+ return Quotient_VERSION_PATCH;
+}
+
// Tests for function_traits<>
using namespace Quotient;
diff --git a/lib/util.h b/lib/util.h
index 78fc9ab7..c6171b91 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -219,18 +219,6 @@ template <typename FnT, int ArgN = 0>
using fn_arg_t =
std::tuple_element_t<ArgN, typename function_traits<FnT>::arg_types>;
-// TODO: get rid of it as soon as Apple Clang gets proper deduction guides
-// for std::function<>
-// ...or consider using QtPrivate magic used by QObject::connect()
-// since wrap_in_function() is actually made for qt_connection_util.h
-// ...for inspiration, also check a possible std::not_fn implementation at
-// https://en.cppreference.com/w/cpp/utility/functional/not_fn
-template <typename FnT>
-inline auto wrap_in_function(FnT&& f)
-{
- return typename function_traits<FnT>::function_type(std::forward<FnT>(f));
-}
-
inline constexpr auto operator"" _ls(const char* s, std::size_t size)
{
return QLatin1String(s, int(size));
@@ -318,4 +306,9 @@ qreal stringToHueF(const QString& s);
/** Extract the serverpart from MXID */
QString serverPart(const QString& mxId);
+
+QString versionString();
+int majorVersion();
+int minorVersion();
+int patchVersion();
} // namespace Quotient