aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2019-06-24 07:21:13 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2019-06-24 07:21:13 +0900
commit63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408 (patch)
tree2552f5049a6ef7ba0034483b25ca4ab33d1fcb13 /lib
parente083d327e6f6581210f8d077d8bbe1151e81e82c (diff)
parent93f0c8fe89f448d1d58caa757573f17102369471 (diff)
downloadlibquotient-63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408.tar.gz
libquotient-63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408.zip
Merge branch 'master' into clang-format
# Conflicts: # CMakeLists.txt # lib/avatar.cpp # lib/connection.cpp # lib/connection.h # lib/connectiondata.cpp # lib/csapi/account-data.cpp # lib/csapi/account-data.h # lib/csapi/capabilities.cpp # lib/csapi/capabilities.h # lib/csapi/content-repo.cpp # lib/csapi/create_room.cpp # lib/csapi/filter.cpp # lib/csapi/joining.cpp # lib/csapi/keys.cpp # lib/csapi/list_joined_rooms.cpp # lib/csapi/notifications.cpp # lib/csapi/openid.cpp # lib/csapi/presence.cpp # lib/csapi/pushrules.cpp # lib/csapi/registration.cpp # lib/csapi/room_upgrades.cpp # lib/csapi/room_upgrades.h # lib/csapi/search.cpp # lib/csapi/users.cpp # lib/csapi/versions.cpp # lib/csapi/whoami.cpp # lib/csapi/{{base}}.cpp.mustache # lib/events/accountdataevents.h # lib/events/eventcontent.h # lib/events/roommemberevent.cpp # lib/events/stateevent.cpp # lib/jobs/basejob.cpp # lib/jobs/basejob.h # lib/networkaccessmanager.cpp # lib/networksettings.cpp # lib/room.cpp # lib/room.h # lib/settings.cpp # lib/settings.h # lib/syncdata.cpp # lib/user.cpp # lib/user.h # lib/util.cpp
Diffstat (limited to 'lib')
-rw-r--r--lib/application-service/definitions/location.cpp6
-rw-r--r--lib/application-service/definitions/location.h36
-rw-r--r--lib/application-service/definitions/protocol.cpp6
-rw-r--r--lib/application-service/definitions/protocol.h133
-rw-r--r--lib/application-service/definitions/user.h36
-rw-r--r--lib/avatar.cpp30
-rw-r--r--lib/avatar.h67
-rw-r--r--lib/connection.cpp459
-rw-r--r--lib/connection.h1450
-rw-r--r--lib/connectiondata.cpp17
-rw-r--r--lib/connectiondata.h55
-rw-r--r--lib/converters.cpp12
-rw-r--r--lib/converters.h622
-rw-r--r--lib/csapi/account-data.cpp40
-rw-r--r--lib/csapi/account-data.h159
-rw-r--r--lib/csapi/admin.cpp72
-rw-r--r--lib/csapi/admin.h164
-rw-r--r--lib/csapi/administrative_contact.cpp101
-rw-r--r--lib/csapi/administrative_contact.h456
-rw-r--r--lib/csapi/appservice_room_directory.cpp11
-rw-r--r--lib/csapi/appservice_room_directory.h67
-rw-r--r--lib/csapi/banning.cpp3
-rw-r--r--lib/csapi/banning.h95
-rw-r--r--lib/csapi/capabilities.cpp82
-rw-r--r--lib/csapi/capabilities.h129
-rw-r--r--lib/csapi/content-repo.cpp72
-rw-r--r--lib/csapi/content-repo.h538
-rw-r--r--lib/csapi/create_room.cpp57
-rw-r--r--lib/csapi/create_room.h466
-rw-r--r--lib/csapi/definitions/auth_data.cpp16
-rw-r--r--lib/csapi/definitions/auth_data.h46
-rw-r--r--lib/csapi/definitions/client_device.cpp12
-rw-r--r--lib/csapi/definitions/client_device.h50
-rw-r--r--lib/csapi/definitions/device_keys.cpp15
-rw-r--r--lib/csapi/definitions/device_keys.h59
-rw-r--r--lib/csapi/definitions/event_filter.cpp15
-rw-r--r--lib/csapi/definitions/event_filter.h57
-rw-r--r--lib/csapi/definitions/public_rooms_response.cpp36
-rw-r--r--lib/csapi/definitions/public_rooms_response.h108
-rw-r--r--lib/csapi/definitions/push_condition.cpp15
-rw-r--r--lib/csapi/definitions/push_condition.h53
-rw-r--r--lib/csapi/definitions/push_rule.cpp12
-rw-r--r--lib/csapi/definitions/push_rule.h58
-rw-r--r--lib/csapi/definitions/push_ruleset.cpp15
-rw-r--r--lib/csapi/definitions/push_ruleset.h46
-rw-r--r--lib/csapi/definitions/room_event_filter.cpp15
-rw-r--r--lib/csapi/definitions/room_event_filter.h48
-rw-r--r--lib/csapi/definitions/sync_filter.cpp45
-rw-r--r--lib/csapi/definitions/sync_filter.h149
-rw-r--r--lib/csapi/definitions/user_identifier.cpp16
-rw-r--r--lib/csapi/definitions/user_identifier.h36
-rw-r--r--lib/csapi/definitions/wellknown/full.cpp19
-rw-r--r--lib/csapi/definitions/wellknown/full.h48
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.cpp15
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.h35
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.cpp15
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.h37
-rw-r--r--lib/csapi/device_management.cpp23
-rw-r--r--lib/csapi/device_management.h265
-rw-r--r--lib/csapi/directory.cpp18
-rw-r--r--lib/csapi/directory.h169
-rw-r--r--lib/csapi/event_context.cpp12
-rw-r--r--lib/csapi/event_context.h111
-rw-r--r--lib/csapi/filter.cpp24
-rw-r--r--lib/csapi/filter.h156
-rw-r--r--lib/csapi/inviting.h70
-rw-r--r--lib/csapi/joining.cpp96
-rw-r--r--lib/csapi/joining.h292
-rw-r--r--lib/csapi/keys.cpp85
-rw-r--r--lib/csapi/keys.h414
-rw-r--r--lib/csapi/kicking.h59
-rw-r--r--lib/csapi/leaving.cpp6
-rw-r--r--lib/csapi/leaving.h121
-rw-r--r--lib/csapi/list_joined_rooms.cpp12
-rw-r--r--lib/csapi/list_joined_rooms.h70
-rw-r--r--lib/csapi/list_public_rooms.cpp63
-rw-r--r--lib/csapi/list_public_rooms.h343
-rw-r--r--lib/csapi/login.cpp41
-rw-r--r--lib/csapi/login.h251
-rw-r--r--lib/csapi/logout.cpp9
-rw-r--r--lib/csapi/logout.h95
-rw-r--r--lib/csapi/message_pagination.cpp14
-rw-r--r--lib/csapi/message_pagination.h123
-rw-r--r--lib/csapi/notifications.cpp51
-rw-r--r--lib/csapi/notifications.h156
-rw-r--r--lib/csapi/openid.cpp17
-rw-r--r--lib/csapi/openid.h106
-rw-r--r--lib/csapi/peeking_events.cpp13
-rw-r--r--lib/csapi/peeking_events.h112
-rw-r--r--lib/csapi/presence.cpp16
-rw-r--r--lib/csapi/presence.h121
-rw-r--r--lib/csapi/profile.cpp43
-rw-r--r--lib/csapi/profile.h310
-rw-r--r--lib/csapi/pusher.cpp96
-rw-r--r--lib/csapi/pusher.h307
-rw-r--r--lib/csapi/pushrules.cpp83
-rw-r--r--lib/csapi/pushrules.h560
-rw-r--r--lib/csapi/read_markers.h51
-rw-r--r--lib/csapi/receipts.cpp5
-rw-r--r--lib/csapi/receipts.h53
-rw-r--r--lib/csapi/redaction.cpp8
-rw-r--r--lib/csapi/redaction.h90
-rw-r--r--lib/csapi/registration.cpp87
-rw-r--r--lib/csapi/registration.h911
-rw-r--r--lib/csapi/report_content.cpp5
-rw-r--r--lib/csapi/report_content.h52
-rw-r--r--lib/csapi/room_send.cpp8
-rw-r--r--lib/csapi/room_send.h104
-rw-r--r--lib/csapi/room_state.cpp19
-rw-r--r--lib/csapi/room_state.h234
-rw-r--r--lib/csapi/room_upgrades.cpp9
-rw-r--r--lib/csapi/room_upgrades.h68
-rw-r--r--lib/csapi/rooms.cpp104
-rw-r--r--lib/csapi/rooms.h482
-rw-r--r--lib/csapi/search.cpp256
-rw-r--r--lib/csapi/search.h349
-rw-r--r--lib/csapi/sso_login_redirect.cpp3
-rw-r--r--lib/csapi/sso_login_redirect.h54
-rw-r--r--lib/csapi/tags.cpp51
-rw-r--r--lib/csapi/tags.h200
-rw-r--r--lib/csapi/third_party_lookup.cpp72
-rw-r--r--lib/csapi/third_party_lookup.h475
-rw-r--r--lib/csapi/third_party_membership.h131
-rw-r--r--lib/csapi/to_device.cpp4
-rw-r--r--lib/csapi/to_device.h55
-rw-r--r--lib/csapi/typing.h56
-rw-r--r--lib/csapi/users.cpp44
-rw-r--r--lib/csapi/users.h134
-rw-r--r--lib/csapi/versions.cpp12
-rw-r--r--lib/csapi/versions.h105
-rw-r--r--lib/csapi/voip.cpp10
-rw-r--r--lib/csapi/voip.h72
-rw-r--r--lib/csapi/wellknown.cpp9
-rw-r--r--lib/csapi/wellknown.h89
-rw-r--r--lib/csapi/whoami.cpp13
-rw-r--r--lib/csapi/whoami.h84
-rw-r--r--lib/csapi/{{base}}.cpp.mustache2
-rw-r--r--lib/eventitem.cpp5
-rw-r--r--lib/eventitem.h238
-rw-r--r--lib/events/accountdataevents.h129
-rw-r--r--lib/events/callanswerevent.cpp29
-rw-r--r--lib/events/callanswerevent.h44
-rw-r--r--lib/events/callcandidatesevent.h45
-rw-r--r--lib/events/callhangupevent.cpp4
-rw-r--r--lib/events/callhangupevent.h23
-rw-r--r--lib/events/callinviteevent.cpp16
-rw-r--r--lib/events/callinviteevent.h44
-rw-r--r--lib/events/directchatevent.h27
-rw-r--r--lib/events/event.cpp13
-rw-r--r--lib/events/event.h669
-rw-r--r--lib/events/eventcontent.cpp45
-rw-r--r--lib/events/eventcontent.h454
-rw-r--r--lib/events/eventloader.h85
-rw-r--r--lib/events/receiptevent.cpp12
-rw-r--r--lib/events/receiptevent.h51
-rw-r--r--lib/events/redactionevent.h34
-rw-r--r--lib/events/roomavatarevent.h34
-rw-r--r--lib/events/roomcreateevent.h45
-rw-r--r--lib/events/roomevent.cpp14
-rw-r--r--lib/events/roomevent.h141
-rw-r--r--lib/events/roommemberevent.cpp50
-rw-r--r--lib/events/roommemberevent.h148
-rw-r--r--lib/events/roommessageevent.cpp80
-rw-r--r--lib/events/roommessageevent.h372
-rw-r--r--lib/events/roomtombstoneevent.h34
-rw-r--r--lib/events/simplestateevents.h94
-rw-r--r--lib/events/stateevent.cpp9
-rw-r--r--lib/events/stateevent.h189
-rw-r--r--lib/events/typingevent.cpp3
-rw-r--r--lib/events/typingevent.h25
-rw-r--r--lib/identity/definitions/request_email_validation.cpp4
-rw-r--r--lib/identity/definitions/request_email_validation.h58
-rw-r--r--lib/identity/definitions/request_msisdn_validation.cpp4
-rw-r--r--lib/identity/definitions/request_msisdn_validation.h65
-rw-r--r--lib/identity/definitions/sid.h32
-rw-r--r--lib/jobs/basejob.cpp115
-rw-r--r--lib/jobs/basejob.h645
-rw-r--r--lib/jobs/downloadfilejob.cpp25
-rw-r--r--lib/jobs/downloadfilejob.h40
-rw-r--r--lib/jobs/mediathumbnailjob.cpp12
-rw-r--r--lib/jobs/mediathumbnailjob.h43
-rw-r--r--lib/jobs/postreadmarkersjob.h12
-rw-r--r--lib/jobs/requestdata.cpp15
-rw-r--r--lib/jobs/requestdata.h54
-rw-r--r--lib/jobs/syncjob.cpp3
-rw-r--r--lib/jobs/syncjob.h32
-rw-r--r--lib/joinstate.h39
-rw-r--r--lib/logging.cpp5
-rw-r--r--lib/logging.h75
-rw-r--r--lib/networkaccessmanager.cpp13
-rw-r--r--lib/networkaccessmanager.h46
-rw-r--r--lib/networksettings.cpp4
-rw-r--r--lib/networksettings.h36
-rw-r--r--lib/qt_connection_util.h155
-rw-r--r--lib/room.cpp676
-rw-r--r--lib/room.h1189
-rw-r--r--lib/settings.cpp25
-rw-r--r--lib/settings.h225
-rw-r--r--lib/syncdata.cpp40
-rw-r--r--lib/syncdata.h185
-rw-r--r--lib/user.cpp121
-rw-r--r--lib/user.h269
-rw-r--r--lib/util.cpp91
-rw-r--r--lib/util.h500
204 files changed, 12521 insertions, 11572 deletions
diff --git a/lib/application-service/definitions/location.cpp b/lib/application-service/definitions/location.cpp
index 4da0e69d..2ab83ae9 100644
--- a/lib/application-service/definitions/location.cpp
+++ b/lib/application-service/definitions/location.cpp
@@ -7,15 +7,15 @@
using namespace QMatrixClient;
void JsonObjectConverter<ThirdPartyLocation>::dumpTo(
- QJsonObject& jo, const ThirdPartyLocation& pod)
+ QJsonObject& jo, const ThirdPartyLocation& pod)
{
addParam<>(jo, QStringLiteral("alias"), pod.alias);
addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
addParam<>(jo, QStringLiteral("fields"), pod.fields);
}
-void JsonObjectConverter<ThirdPartyLocation>::fillFrom(
- const QJsonObject& jo, ThirdPartyLocation& result)
+void JsonObjectConverter<ThirdPartyLocation>::fillFrom(const QJsonObject& jo,
+ ThirdPartyLocation& result)
{
fromJson(jo.value("alias"_ls), result.alias);
fromJson(jo.value("protocol"_ls), result.protocol);
diff --git a/lib/application-service/definitions/location.h b/lib/application-service/definitions/location.h
index f92fa8c5..caf28615 100644
--- a/lib/application-service/definitions/location.h
+++ b/lib/application-service/definitions/location.h
@@ -8,20 +8,26 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Data structures
-
- struct ThirdPartyLocation {
- /// An alias for a matrix room.
- QString alias;
- /// The protocol ID that the third party location is a part of.
- QString protocol;
- /// Information used to identify this third party location.
- QJsonObject fields;
- };
- template <> struct JsonObjectConverter<ThirdPartyLocation> {
- static void dumpTo(QJsonObject& jo, const ThirdPartyLocation& pod);
- static void fillFrom(const QJsonObject& jo, ThirdPartyLocation& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+struct ThirdPartyLocation
+{
+ /// An alias for a matrix room.
+ QString alias;
+ /// The protocol ID that the third party location is a part of.
+ QString protocol;
+ /// Information used to identify this third party location.
+ QJsonObject fields;
+};
+
+template <>
+struct JsonObjectConverter<ThirdPartyLocation>
+{
+ static void dumpTo(QJsonObject& jo, const ThirdPartyLocation& pod);
+ static void fillFrom(const QJsonObject& jo, ThirdPartyLocation& pod);
+};
} // namespace QMatrixClient
diff --git a/lib/application-service/definitions/protocol.cpp b/lib/application-service/definitions/protocol.cpp
index 4c148796..e87001fb 100644
--- a/lib/application-service/definitions/protocol.cpp
+++ b/lib/application-service/definitions/protocol.cpp
@@ -39,7 +39,7 @@ void JsonObjectConverter<ProtocolInstance>::fillFrom(const QJsonObject& jo,
}
void JsonObjectConverter<ThirdPartyProtocol>::dumpTo(
- QJsonObject& jo, const ThirdPartyProtocol& pod)
+ QJsonObject& jo, const ThirdPartyProtocol& pod)
{
addParam<>(jo, QStringLiteral("user_fields"), pod.userFields);
addParam<>(jo, QStringLiteral("location_fields"), pod.locationFields);
@@ -48,8 +48,8 @@ void JsonObjectConverter<ThirdPartyProtocol>::dumpTo(
addParam<>(jo, QStringLiteral("instances"), pod.instances);
}
-void JsonObjectConverter<ThirdPartyProtocol>::fillFrom(
- const QJsonObject& jo, ThirdPartyProtocol& result)
+void JsonObjectConverter<ThirdPartyProtocol>::fillFrom(const QJsonObject& jo,
+ ThirdPartyProtocol& result)
{
fromJson(jo.value("user_fields"_ls), result.userFields);
fromJson(jo.value("location_fields"_ls), result.locationFields);
diff --git a/lib/application-service/definitions/protocol.h b/lib/application-service/definitions/protocol.h
index 66012a13..0d227851 100644
--- a/lib/application-service/definitions/protocol.h
+++ b/lib/application-service/definitions/protocol.h
@@ -6,74 +6,83 @@
#include "converters.h"
-#include "converters.h"
#include <QtCore/QHash>
#include <QtCore/QJsonObject>
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Data structures
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Definition of valid values for a field.
+struct FieldType
+{
+ /// A regular expression for validation of a field's value. This may be
+ /// relativelycoarse to verify the value as the application service
+ /// providing this protocolmay apply additional validation or filtering.
+ QString regexp;
+ /// An placeholder serving as a valid example of the field value.
+ QString placeholder;
+};
+
+template <>
+struct JsonObjectConverter<FieldType>
+{
+ static void dumpTo(QJsonObject& jo, const FieldType& pod);
+ static void fillFrom(const QJsonObject& jo, FieldType& pod);
+};
+
+struct ProtocolInstance
+{
+ /// A human-readable description for the protocol, such as the name.
+ QString desc;
+ /// An optional content URI representing the protocol. Overrides the one
+ /// providedat the higher level Protocol object.
+ QString icon;
+ /// Preset values for ``fields`` the client may use to search by.
+ QJsonObject fields;
+ /// A unique identifier across all instances.
+ QString networkId;
+};
- /// Definition of valid values for a field.
- struct FieldType {
- /// A regular expression for validation of a field's value. This may be
- /// relatively coarse to verify the value as the application service
- /// providing this protocol may apply additional validation or
- /// filtering.
- QString regexp;
- /// An placeholder serving as a valid example of the field value.
- QString placeholder;
- };
- template <> struct JsonObjectConverter<FieldType> {
- static void dumpTo(QJsonObject& jo, const FieldType& pod);
- static void fillFrom(const QJsonObject& jo, FieldType& pod);
- };
+template <>
+struct JsonObjectConverter<ProtocolInstance>
+{
+ static void dumpTo(QJsonObject& jo, const ProtocolInstance& pod);
+ static void fillFrom(const QJsonObject& jo, ProtocolInstance& pod);
+};
- struct ProtocolInstance {
- /// A human-readable description for the protocol, such as the name.
- QString desc;
- /// An optional content URI representing the protocol. Overrides the one
- /// provided at the higher level Protocol object.
- QString icon;
- /// Preset values for ``fields`` the client may use to search by.
- QJsonObject fields;
- /// A unique identifier across all instances.
- QString networkId;
- };
- template <> struct JsonObjectConverter<ProtocolInstance> {
- static void dumpTo(QJsonObject& jo, const ProtocolInstance& pod);
- static void fillFrom(const QJsonObject& jo, ProtocolInstance& pod);
- };
+struct ThirdPartyProtocol
+{
+ /// Fields which may be used to identify a third party user. These should
+ /// beordered to suggest the way that entities may be grouped, where
+ /// highergroupings are ordered first. For example, the name of a network
+ /// should besearched before the nickname of a user.
+ QStringList userFields;
+ /// Fields which may be used to identify a third party location. These
+ /// should beordered to suggest the way that entities may be grouped, where
+ /// highergroupings are ordered first. For example, the name of a network
+ /// should besearched before the name of a channel.
+ QStringList locationFields;
+ /// A content URI representing an icon for the third party protocol.
+ QString icon;
+ /// The type definitions for the fields defined in the ``user_fields`` and
+ /// ``location_fields``. Each entry in those arrays MUST have an entry here.
+ /// The``string`` key for this object is field name itself.May be an empty
+ /// object if no fields are defined.
+ QHash<QString, FieldType> fieldTypes;
+ /// A list of objects representing independent instances of
+ /// configuration.For example, multiple networks on IRC if multiple are
+ /// provided by thesame application service.
+ QVector<ProtocolInstance> instances;
+};
- struct ThirdPartyProtocol {
- /// Fields which may be used to identify a third party user. These
- /// should be ordered to suggest the way that entities may be grouped,
- /// where higher groupings are ordered first. For example, the name of a
- /// network should be searched before the nickname of a user.
- QStringList userFields;
- /// Fields which may be used to identify a third party location. These
- /// should be ordered to suggest the way that entities may be grouped,
- /// where higher groupings are ordered first. For example, the name of a
- /// network should be searched before the name of a channel.
- QStringList locationFields;
- /// A content URI representing an icon for the third party protocol.
- QString icon;
- /// The type definitions for the fields defined in the ``user_fields``
- /// and
- /// ``location_fields``. Each entry in those arrays MUST have an entry
- /// here. The
- /// ``string`` key for this object is field name itself.
- ///
- /// May be an empty object if no fields are defined.
- QHash<QString, FieldType> fieldTypes;
- /// A list of objects representing independent instances of
- /// configuration. For example, multiple networks on IRC if multiple are
- /// provided by the same application service.
- QVector<ProtocolInstance> instances;
- };
- template <> struct JsonObjectConverter<ThirdPartyProtocol> {
- static void dumpTo(QJsonObject& jo, const ThirdPartyProtocol& pod);
- static void fillFrom(const QJsonObject& jo, ThirdPartyProtocol& pod);
- };
+template <>
+struct JsonObjectConverter<ThirdPartyProtocol>
+{
+ static void dumpTo(QJsonObject& jo, const ThirdPartyProtocol& pod);
+ static void fillFrom(const QJsonObject& jo, ThirdPartyProtocol& pod);
+};
} // namespace QMatrixClient
diff --git a/lib/application-service/definitions/user.h b/lib/application-service/definitions/user.h
index 9b314db1..3fd099d0 100644
--- a/lib/application-service/definitions/user.h
+++ b/lib/application-service/definitions/user.h
@@ -8,20 +8,26 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Data structures
-
- struct ThirdPartyUser {
- /// A Matrix User ID represting a third party user.
- QString userid;
- /// The protocol ID that the third party location is a part of.
- QString protocol;
- /// Information used to identify this third party location.
- QJsonObject fields;
- };
- template <> struct JsonObjectConverter<ThirdPartyUser> {
- static void dumpTo(QJsonObject& jo, const ThirdPartyUser& pod);
- static void fillFrom(const QJsonObject& jo, ThirdPartyUser& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+struct ThirdPartyUser
+{
+ /// A Matrix User ID represting a third party user.
+ QString userid;
+ /// The protocol ID that the third party location is a part of.
+ QString protocol;
+ /// Information used to identify this third party location.
+ QJsonObject fields;
+};
+
+template <>
+struct JsonObjectConverter<ThirdPartyUser>
+{
+ static void dumpTo(QJsonObject& jo, const ThirdPartyUser& pod);
+ static void fillFrom(const QJsonObject& jo, ThirdPartyUser& pod);
+};
} // namespace QMatrixClient
diff --git a/lib/avatar.cpp b/lib/avatar.cpp
index 5de43dd5..0e58a1ce 100644
--- a/lib/avatar.cpp
+++ b/lib/avatar.cpp
@@ -1,5 +1,3 @@
-#include <utility>
-
/******************************************************************************
* Copyright (C) 2017 Kitsune Ral <kitsune-ral@users.sf.net>
*
@@ -21,6 +19,7 @@
#include "avatar.h"
#include "connection.h"
+
#include "events/eventcontent.h"
#include "jobs/mediathumbnailjob.h"
@@ -35,8 +34,10 @@ using std::move;
class Avatar::Private
{
- public:
- explicit Private(QUrl url = {}) : _url(move(url)) {}
+public:
+ explicit Private(QUrl url = {})
+ : _url(move(url))
+ {}
~Private()
{
if (isJobRunning(_thumbnailRequest))
@@ -64,9 +65,13 @@ class Avatar::Private
mutable std::vector<get_callback_t> callbacks;
};
-Avatar::Avatar() : d(std::make_unique<Private>()) {}
+Avatar::Avatar()
+ : d(std::make_unique<Private>())
+{}
-Avatar::Avatar(QUrl url) : d(std::make_unique<Private>(std::move(url))) {}
+Avatar::Avatar(QUrl url)
+ : d(std::make_unique<Private>(std::move(url)))
+{}
Avatar::Avatar(Avatar&&) = default;
@@ -135,9 +140,8 @@ QImage Avatar::Private::get(Connection* connection, QSize size,
QObject::connect(_thumbnailRequest, &MediaThumbnailJob::success,
_thumbnailRequest, [this] {
_imageSource = Network;
- _originalImage =
- _thumbnailRequest->scaledThumbnail(
- _requestedSize);
+ _originalImage = _thumbnailRequest->scaledThumbnail(
+ _requestedSize);
_originalImage.save(localFile());
_scaledImages.clear();
for (const auto& n : callbacks)
@@ -150,9 +154,9 @@ QImage Avatar::Private::get(Connection* connection, QSize size,
if (p.first == size)
return p.second;
auto result = _originalImage.isNull()
- ? QImage()
- : _originalImage.scaled(size, Qt::KeepAspectRatio,
- Qt::SmoothTransformation);
+ ? QImage()
+ : _originalImage.scaled(size, Qt::KeepAspectRatio,
+ Qt::SmoothTransformation);
_scaledImages.emplace_back(size, result);
return result;
}
@@ -184,7 +188,7 @@ bool Avatar::Private::checkUrl(const QUrl& url) const
QString Avatar::Private::localFile() const
{
- static const auto cachePath = cacheLocation("avatars");
+ static const auto cachePath = cacheLocation(QStringLiteral("avatars"));
return cachePath % _url.authority() % '_' % _url.fileName() % ".png";
}
diff --git a/lib/avatar.h b/lib/avatar.h
index 2ca2c987..37991192 100644
--- a/lib/avatar.h
+++ b/lib/avatar.h
@@ -24,37 +24,38 @@
#include <functional>
#include <memory>
-namespace QMatrixClient {
- class Connection;
-
- class Avatar
- {
- public:
- explicit Avatar();
- explicit Avatar(QUrl url);
- Avatar(Avatar&&);
- ~Avatar();
- Avatar& operator=(Avatar&&);
-
- using get_callback_t = std::function<void()>;
- using upload_callback_t = std::function<void(QString)>;
-
- QImage get(Connection* connection, int dimension,
- get_callback_t callback) const;
- QImage get(Connection* connection, int w, int h,
- get_callback_t callback) const;
-
- bool upload(Connection* connection, const QString& fileName,
- upload_callback_t callback) const;
- bool upload(Connection* connection, QIODevice* source,
- upload_callback_t callback) const;
-
- QString mediaId() const;
- QUrl url() const;
- bool updateUrl(const QUrl& newUrl);
-
- private:
- class Private;
- std::unique_ptr<Private> d;
- };
+namespace QMatrixClient
+{
+class Connection;
+
+class Avatar
+{
+public:
+ explicit Avatar();
+ explicit Avatar(QUrl url);
+ Avatar(Avatar&&);
+ ~Avatar();
+ Avatar& operator=(Avatar&&);
+
+ using get_callback_t = std::function<void()>;
+ using upload_callback_t = std::function<void(QString)>;
+
+ QImage get(Connection* connection, int dimension,
+ get_callback_t callback) const;
+ QImage get(Connection* connection, int w, int h,
+ get_callback_t callback) const;
+
+ bool upload(Connection* connection, const QString& fileName,
+ upload_callback_t callback) const;
+ bool upload(Connection* connection, QIODevice* source,
+ upload_callback_t callback) const;
+
+ QString mediaId() const;
+ QUrl url() const;
+ bool updateUrl(const QUrl& newUrl);
+
+private:
+ class Private;
+ std::unique_ptr<Private> d;
+};
} // namespace QMatrixClient
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 2b1cc1b9..43681d12 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -17,7 +17,12 @@
*/
#include "connection.h"
+
#include "connectiondata.h"
+#include "room.h"
+#include "settings.h"
+#include "user.h"
+
#include "csapi/account-data.h"
#include "csapi/capabilities.h"
#include "csapi/joining.h"
@@ -28,14 +33,12 @@
#include "csapi/room_send.h"
#include "csapi/to_device.h"
#include "csapi/voip.h"
+
#include "events/directchatevent.h"
#include "events/eventloader.h"
#include "jobs/downloadfilejob.h"
#include "jobs/mediathumbnailjob.h"
#include "jobs/syncjob.h"
-#include "room.h"
-#include "settings.h"
-#include "user.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
@@ -66,21 +69,19 @@ HashT erase_if(HashT& hashMap, Pred pred)
class Connection::Private
{
- public:
+public:
explicit Private(std::unique_ptr<ConnectionData>&& connection)
: data(move(connection))
- {
- }
+ {}
Q_DISABLE_COPY(Private)
- Private(Private&&) = delete;
- Private operator=(Private&&) = delete;
+ DISABLE_MOVE(Private)
Connection* q = nullptr;
std::unique_ptr<ConnectionData> data;
// A complex key below is a pair of room name and whether its
// state is Invited. The spec mandates to keep Invited room state
- // separately so we should, e.g., keep objects for Invite and
- // Leave state of the same room.
+ // separately; specifically, we should keep objects for Invite and
+ // Leave state of the same room if the two happen to co-exist.
QHash<QPair<QString, bool>, Room*> roomMap;
// Mapping from aliases to room ids, as per the last sync
QHash<QString, QString> roomAliasMap;
@@ -90,6 +91,11 @@ class Connection::Private
QMap<QString, User*> userMap;
DirectChatsMap directChats;
DirectChatUsersMap directChatUsers;
+ // The below two variables track local changes between sync completions.
+ // See also:
+ // https://github.com/QMatrixClient/libqmatrixclient/wiki/Handling-direct-chat-events
+ DirectChatsMap dcLocalAdditions;
+ DirectChatsMap dcLocalRemovals;
std::unordered_map<QString, EventPtr> accountData;
QString userId;
int syncLoopTimeout = -1;
@@ -101,21 +107,20 @@ class Connection::Private
bool cacheState = true;
bool cacheToBinary =
- SettingsGroup("libqmatrixclient").value("cache_type").toString()
- != "json";
+ SettingsGroup("libqmatrixclient").value("cache_type").toString()
+ != "json";
bool lazyLoading = false;
void connectWithToken(const QString& user, const QString& accessToken,
const QString& deviceId);
- void broadcastDirectChatUpdates(const DirectChatsMap& additions,
- const DirectChatsMap& removals);
- template <typename EventT> EventT* unpackAccountData() const
+ template <typename EventT>
+ EventT* unpackAccountData() const
{
const auto& eventIt = accountData.find(EventT::matrixTypeId());
return eventIt == accountData.end()
- ? nullptr
- : weakPtrCast<EventT>(eventIt->second);
+ ? nullptr
+ : weakPtrCast<EventT>(eventIt->second);
}
void packAndSendAccountData(EventPtr&& event)
@@ -130,18 +135,24 @@ class Connection::Private
void packAndSendAccountData(ContentT&& content)
{
packAndSendAccountData(
- makeEvent<EventT>(std::forward<ContentT>(content)));
+ makeEvent<EventT>(std::forward<ContentT>(content)));
+ }
+ QString topLevelStatePath() const
+ {
+ return q->stateCacheDir().filePath("state.json");
}
};
Connection::Connection(const QUrl& server, QObject* parent)
- : QObject(parent),
- d(std::make_unique<Private>(std::make_unique<ConnectionData>(server)))
+ : QObject(parent)
+ , d(new Private(std::make_unique<ConnectionData>(server)))
{
d->q = this; // All d initialization should occur before this line
}
-Connection::Connection(QObject* parent) : Connection({}, parent) {}
+Connection::Connection(QObject* parent)
+ : Connection({}, parent)
+{}
Connection::~Connection()
{
@@ -156,20 +167,17 @@ void Connection::resolveServer(const QString& mxidOrDomain)
// Try to parse as an FQID; if there's no @ part, assume it's a domain name.
QRegularExpression parser(
- "^(@.+?:)?" // Optional username (allow everything for
- // compatibility)
- "(\\[[^]]+\\]|[^:@]+)" // Either IPv6 address or hostname/IPv4
- // address
- "(:\\d{1,5})?$", // Optional port
- QRegularExpression::UseUnicodePropertiesOption); // Because asian
- // digits
+ "^(@.+?:)?" // Optional username (allow everything for compatibility)
+ "(\\[[^]]+\\]|[^:@]+)" // Either IPv6 address or hostname/IPv4 address
+ "(:\\d{1,5})?$", // Optional port
+ QRegularExpression::UseUnicodePropertiesOption); // Because asian digits
auto match = parser.match(mxidOrDomain);
QUrl maybeBaseUrl = QUrl::fromUserInput(match.captured(2));
maybeBaseUrl.setScheme("https"); // Instead of the Qt-default "http"
if (!match.hasMatch() || !maybeBaseUrl.isValid()) {
emit resolveError(tr("%1 is not a valid homeserver address")
- .arg(maybeBaseUrl.toString()));
+ .arg(maybeBaseUrl.toString()));
return;
}
@@ -219,10 +227,10 @@ void Connection::doConnectToServer(const QString& user, const QString& password,
const QString& deviceId)
{
auto loginJob = callApi<LoginJob>(
- QStringLiteral("m.login.password"),
- UserIdentifier { QStringLiteral("m.id.user"),
- { { QStringLiteral("user"), user } } },
- password, /*token*/ "", deviceId, initialDeviceName);
+ QStringLiteral("m.login.password"),
+ UserIdentifier { QStringLiteral("m.id.user"),
+ { { QStringLiteral("user"), user } } },
+ password, /*token*/ "", deviceId, initialDeviceName);
connect(loginJob, &BaseJob::success, this, [this, loginJob] {
d->connectWithToken(loginJob->userId(), loginJob->accessToken(),
loginJob->deviceId());
@@ -238,9 +246,8 @@ void Connection::connectWithToken(const QString& userId,
const QString& accessToken,
const QString& deviceId)
{
- checkAndConnect(userId, [=] {
- d->connectWithToken(userId, accessToken, deviceId);
- });
+ checkAndConnect(userId,
+ [=] { d->connectWithToken(userId, accessToken, deviceId); });
}
void Connection::reloadCapabilities()
@@ -257,14 +264,12 @@ void Connection::reloadCapabilities()
d->capabilities.roomVersions = { "1", { { "1", "stable" } } };
} else {
qCDebug(MAIN) << "Room versions:" << defaultRoomVersion()
- << "is default, full list:"
- << availableRoomVersions();
+ << "is default, full list:" << availableRoomVersions();
}
Q_ASSERT(!d->capabilities.roomVersions.omitted());
emit capabilitiesLoaded();
for (auto* r : d->roomMap)
- if (r->joinState() == JoinState::Join && r->successorId().isEmpty())
- r->checkVersion();
+ r->checkVersion();
});
}
@@ -283,6 +288,7 @@ void Connection::Private::connectWithToken(const QString& user,
q->user(); // Creates a User object for the local user
data->setToken(accessToken.toLatin1());
data->setDeviceId(deviceId);
+ q->setObjectName(userId % '/' % deviceId);
qCDebug(MAIN) << "Using server" << data->baseUrl().toDisplayString()
<< "by user" << userId << "from device" << deviceId;
emit q->stateChanged();
@@ -299,24 +305,25 @@ void Connection::checkAndConnect(const QString& userId,
}
// Not good to go, try to fix the homeserver URL.
if (userId.startsWith('@') && userId.indexOf(':') != -1) {
- connectSingleShot(this, &Connection::homeserverChanged, this,
- connectFn);
+ connectSingleShot(this, &Connection::homeserverChanged, this, connectFn);
// NB: doResolveServer can emit resolveError, so this is a part of
// checkAndConnect function contract.
resolveServer(userId);
} else
emit resolveError(tr("%1 is an invalid homeserver URL")
- .arg(d->data->baseUrl().toString()));
+ .arg(d->data->baseUrl().toString()));
}
void Connection::logout()
{
auto job = callApi<LogoutJob>();
- connect(job, &LogoutJob::success, this, [this] {
- stopSync();
- d->data->setToken({});
- emit stateChanged();
- emit loggedOut();
+ connect(job, &LogoutJob::finished, this, [job, this] {
+ if (job->status().good() || job->error() == BaseJob::ContentAccessError) {
+ stopSync();
+ d->data->setToken({});
+ emit stateChanged();
+ emit loggedOut();
+ }
});
}
@@ -328,8 +335,9 @@ void Connection::sync(int timeout)
Filter filter;
filter.room->timeline->limit = 100;
filter.room->state->lazyLoadMembers = d->lazyLoading;
- auto job = d->syncJob = callApi<SyncJob>(
- BackgroundRequest, d->data->lastEvent(), filter, timeout);
+ auto job = d->syncJob = callApi<SyncJob>(BackgroundRequest,
+ d->data->lastEvent(), filter,
+ timeout);
connect(job, &SyncJob::success, this, [this, job] {
onSyncSuccess(job->takeData());
d->syncJob = nullptr;
@@ -343,8 +351,8 @@ void Connection::sync(int timeout)
connect(job, &SyncJob::failure, this, [this, job] {
d->syncJob = nullptr;
if (job->error() == BaseJob::ContentAccessError) {
- qCWarning(SYNCJOB) << "Sync job failed with ContentAccessError - "
- "login expired?";
+ qCWarning(SYNCJOB)
+ << "Sync job failed with ContentAccessError - login expired?";
emit loginError(job->errorString(), job->rawDataSample());
} else
emit syncError(job->errorString(), job->rawDataSample());
@@ -358,6 +366,19 @@ void Connection::syncLoop(int timeout)
syncLoopIteration(); // initial sync to start the loop
}
+QJsonObject toJson(const Connection::DirectChatsMap& directChats)
+{
+ QJsonObject json;
+ for (auto it = directChats.begin(); it != directChats.end();) {
+ QJsonArray roomIds;
+ const auto* user = it.key();
+ for (; it != directChats.end() && it.key() == user; ++it)
+ roomIds.append(*it);
+ json.insert(user->id(), roomIds);
+ }
+ return json;
+}
+
void Connection::onSyncSuccess(SyncData&& data, bool fromCache)
{
d->data->setLastEvent(data.nextBatch());
@@ -367,8 +388,8 @@ void Connection::onSyncSuccess(SyncData&& data, bool fromCache)
d->roomIdsToForget.removeAt(forgetIdx);
if (roomData.joinState == JoinState::Leave) {
qDebug(MAIN)
- << "Room" << roomData.roomId
- << "has been forgotten, ignoring /sync response for it";
+ << "Room" << roomData.roomId
+ << "has been forgotten, ignoring /sync response for it";
continue;
}
qWarning(MAIN) << "Room" << roomData.roomId
@@ -383,64 +404,92 @@ void Connection::onSyncSuccess(SyncData&& data, bool fromCache)
emit loadedRoomState(r);
if (!d->capabilities.roomVersions.omitted())
r->checkVersion();
- // Otherwise, the version will be checked in
- // reloadCapabilities()
+ // Otherwise, the version will be checked in reloadCapabilities()
}
}
// Let UI update itself after updating each room
QCoreApplication::processEvents();
}
- for (auto&& accountEvent : data.takeAccountData()) {
- if (is<DirectChatEvent>(*accountEvent)) {
- const auto usersToDCs = ptrCast<DirectChatEvent>(move(accountEvent))
- ->usersToDirectChats();
- DirectChatsMap removals =
- erase_if(d->directChats, [&usersToDCs](auto it) {
- return !usersToDCs.contains(it.key()->id(), it.value());
+ // After running this loop, the account data events not saved in
+ // d->accountData (see the end of the loop body) are auto-cleaned away
+ for (auto& eventPtr : data.takeAccountData()) {
+ visit(
+ *eventPtr,
+ [this](const DirectChatEvent& dce) {
+ // See
+ // https://github.com/QMatrixClient/libqmatrixclient/wiki/Handling-direct-chat-events
+ const auto& usersToDCs = dce.usersToDirectChats();
+ DirectChatsMap remoteRemovals =
+ erase_if(d->directChats, [&usersToDCs, this](auto it) {
+ return !(usersToDCs.contains(it.key()->id(), it.value())
+ || d->dcLocalAdditions.contains(it.key(),
+ it.value()));
});
- erase_if(d->directChatUsers, [&usersToDCs](auto it) {
- return !usersToDCs.contains(it.value()->id(), it.key());
- });
- if (MAIN().isDebugEnabled())
- for (auto it = removals.begin(); it != removals.end(); ++it)
- qCDebug(MAIN)
+ erase_if(d->directChatUsers, [&remoteRemovals](auto it) {
+ return remoteRemovals.contains(it.value(), it.key());
+ });
+ // Remove from dcLocalRemovals what the server already has.
+ erase_if(d->dcLocalRemovals, [&remoteRemovals](auto it) {
+ return remoteRemovals.contains(it.key(), it.value());
+ });
+ if (MAIN().isDebugEnabled())
+ for (auto it = remoteRemovals.begin();
+ it != remoteRemovals.end(); ++it) {
+ qCDebug(MAIN)
<< it.value() << "is no more a direct chat with"
<< it.key()->id();
-
- DirectChatsMap additions;
- for (auto it = usersToDCs.begin(); it != usersToDCs.end(); ++it) {
- if (auto* u = user(it.key())) {
- if (!d->directChats.contains(u, it.value())) {
- Q_ASSERT(!d->directChatUsers.contains(it.value(), u));
- additions.insert(u, it.value());
- d->directChats.insert(u, it.value());
- d->directChatUsers.insert(it.value(), u);
- qCDebug(MAIN) << "Marked room" << it.value()
- << "as a direct chat with" << u->id();
}
- } else
- qCWarning(MAIN)
- << "Couldn't get a user object for" << it.key();
- }
- if (!additions.isEmpty() || !removals.isEmpty())
- emit directChatsListChanged(additions, removals);
- continue;
- }
- if (is<IgnoredUsersEvent>(*accountEvent))
- qCDebug(MAIN) << "Users ignored by" << d->userId << "updated:"
- << QStringList::fromSet(ignoredUsers()).join(',');
-
- auto& currentData = d->accountData[accountEvent->matrixType()];
- // A polymorphic event-specific comparison might be a bit more
- // efficient; maaybe do it another day
- if (!currentData
- || currentData->contentJson() != accountEvent->contentJson()) {
- currentData = std::move(accountEvent);
- qCDebug(MAIN) << "Updated account data of type"
- << currentData->matrixType();
- emit accountDataChanged(currentData->matrixType());
- }
+ DirectChatsMap remoteAdditions;
+ for (auto it = usersToDCs.begin(); it != usersToDCs.end(); ++it) {
+ if (auto* u = user(it.key())) {
+ if (!d->directChats.contains(u, it.value())
+ && !d->dcLocalRemovals.contains(u, it.value())) {
+ Q_ASSERT(!d->directChatUsers.contains(it.value(), u));
+ remoteAdditions.insert(u, it.value());
+ d->directChats.insert(u, it.value());
+ d->directChatUsers.insert(it.value(), u);
+ qCDebug(MAIN) << "Marked room" << it.value()
+ << "as a direct chat with" << u->id();
+ }
+ } else
+ qCWarning(MAIN)
+ << "Couldn't get a user object for" << it.key();
+ }
+ // Remove from dcLocalAdditions what the server already has.
+ erase_if(d->dcLocalAdditions, [&remoteAdditions](auto it) {
+ return remoteAdditions.contains(it.key(), it.value());
+ });
+ if (!remoteAdditions.isEmpty() || !remoteRemovals.isEmpty())
+ emit directChatsListChanged(remoteAdditions, remoteRemovals);
+ },
+ // catch-all, passing eventPtr for a possible take-over
+ [this, &eventPtr](const Event& accountEvent) {
+ if (is<IgnoredUsersEvent>(accountEvent))
+ qCDebug(MAIN)
+ << "Users ignored by" << d->userId << "updated:"
+ << QStringList::fromSet(ignoredUsers()).join(',');
+
+ auto& currentData = d->accountData[accountEvent.matrixType()];
+ // A polymorphic event-specific comparison might be a bit more
+ // efficient; maaybe do it another day
+ if (!currentData
+ || currentData->contentJson() != accountEvent.contentJson()) {
+ currentData = std::move(eventPtr);
+ qCDebug(MAIN) << "Updated account data of type"
+ << currentData->matrixType();
+ emit accountDataChanged(currentData->matrixType());
+ }
+ });
+ }
+ if (!d->dcLocalAdditions.isEmpty() || !d->dcLocalRemovals.isEmpty()) {
+ qDebug(MAIN) << "Sending updated direct chats to the server:"
+ << d->dcLocalRemovals.size() << "removal(s),"
+ << d->dcLocalAdditions.size() << "addition(s)";
+ callApi<SetAccountDataJob>(d->userId, QStringLiteral("m.direct"),
+ toJson(d->directChats));
+ d->dcLocalAdditions.clear();
+ d->dcLocalRemovals.clear();
}
}
@@ -498,7 +547,7 @@ inline auto splitMediaId(const QString& mediaId)
auto idParts = mediaId.split('/');
Q_ASSERT_X(idParts.size() == 2, __FUNCTION__,
("'" + mediaId + "' doesn't look like 'serverName/localMediaId'")
- .toLatin1());
+ .toLatin1());
return idParts;
}
@@ -511,8 +560,7 @@ MediaThumbnailJob* Connection::getThumbnail(const QString& mediaId,
requestedSize);
}
-MediaThumbnailJob* Connection::getThumbnail(const QUrl& url,
- QSize requestedSize,
+MediaThumbnailJob* Connection::getThumbnail(const QUrl& url, QSize requestedSize,
RunningPolicy policy) const
{
return getThumbnail(url.authority() + url.path(), requestedSize, policy);
@@ -531,10 +579,9 @@ Connection::uploadContent(QIODevice* contentSource, const QString& filename,
{
auto contentType = overrideContentType;
if (contentType.isEmpty()) {
- contentType =
- QMimeDatabase()
- .mimeTypeForFileNameAndData(filename, contentSource)
- .name();
+ contentType = QMimeDatabase()
+ .mimeTypeForFileNameAndData(filename, contentSource)
+ .name();
contentSource->open(QIODevice::ReadOnly);
}
return callApi<UploadContentJob>(contentSource, filename, contentType);
@@ -584,13 +631,23 @@ Connection::createRoom(RoomVisibility visibility, const QString& alias,
const QJsonObject& creationContent)
{
invites.removeOne(d->userId); // The creator is by definition in the room
- auto job = callApi<CreateRoomJob>(
- visibility == PublishRoom ? QStringLiteral("public")
- : QStringLiteral("private"),
- alias, name, topic, invites, invite3pids, roomVersion,
- creationContent, initialState, presetName, isDirect);
- connect(job, &BaseJob::success, this, [this, job] {
- emit createdRoom(provideRoom(job->roomId(), JoinState::Join));
+ auto job = callApi<CreateRoomJob>(visibility == PublishRoom
+ ? QStringLiteral("public")
+ : QStringLiteral("private"),
+ alias, name, topic, invites, invite3pids,
+ roomVersion, creationContent,
+ initialState, presetName, isDirect);
+ connect(job, &BaseJob::success, this, [this, job, invites, isDirect] {
+ auto* room = provideRoom(job->roomId(), JoinState::Join);
+ if (!room) {
+ Q_ASSERT_X(room, "Connection::createRoom",
+ "Failed to create a room");
+ return;
+ }
+ emit createdRoom(room);
+ if (isDirect)
+ for (const auto& i : invites)
+ addToDirectChats(room, user(i));
});
return job;
}
@@ -600,9 +657,9 @@ void Connection::requestDirectChat(const QString& userId)
if (auto* u = user(userId))
requestDirectChat(u);
else
- qCCritical(MAIN) << "Connection::requestDirectChat: Couldn't get a "
- "user object for"
- << userId;
+ qCCritical(MAIN)
+ << "Connection::requestDirectChat: Couldn't get a user object for"
+ << userId;
}
void Connection::requestDirectChat(User* u)
@@ -617,8 +674,8 @@ void Connection::doInDirectChat(const QString& userId,
doInDirectChat(u, operation);
else
qCCritical(MAIN)
- << "Connection::doInDirectChat: Couldn't get a user object for"
- << userId;
+ << "Connection::doInDirectChat: Couldn't get a user object for"
+ << userId;
}
void Connection::doInDirectChat(User* u,
@@ -626,8 +683,8 @@ void Connection::doInDirectChat(User* u,
{
Q_ASSERT(u);
const auto& userId = u->id();
- // There can be more than one DC; find the first valid, and delete invalid
- // (left/forgotten) ones along the way.
+ // There can be more than one DC; find the first valid (existing and
+ // not left), and delete inexistent (forgotten?) ones along the way.
DirectChatsMap removals;
for (auto it = d->directChats.find(u);
it != d->directChats.end() && it.key() == u; ++it) {
@@ -648,8 +705,8 @@ void Connection::doInDirectChat(User* u,
connect(j, &BaseJob::success, this,
[this, roomId, userId, operation] {
qCDebug(MAIN)
- << "Joined the already invited direct chat with"
- << userId << "as" << roomId;
+ << "Joined the already invited direct chat with"
+ << userId << "as" << roomId;
operation(room(roomId, JoinState::Join));
});
return;
@@ -663,6 +720,8 @@ void Connection::doInDirectChat(User* u,
<< roomId << "is not valid and will be discarded";
// Postpone actual deletion until we finish iterating d->directChats.
removals.insert(it.key(), it.value());
+ // Add to the list of updates to send to the server upon the next sync.
+ d->dcLocalRemovals.insert(it.key(), it.value());
}
if (!removals.isEmpty()) {
for (auto it = removals.cbegin(); it != removals.cend(); ++it) {
@@ -670,7 +729,7 @@ void Connection::doInDirectChat(User* u,
d->directChatUsers.remove(it.value(),
const_cast<User*>(it.key())); // FIXME
}
- d->broadcastDirectChatUpdates({}, removals);
+ emit directChatsListChanged({}, removals);
}
auto j = createDirectChat(userId);
@@ -685,8 +744,8 @@ CreateRoomJob* Connection::createDirectChat(const QString& userId,
const QString& topic,
const QString& name)
{
- return createRoom(UnpublishRoom, "", name, topic, { userId },
- "trusted_private_chat", {}, true);
+ return createRoom(UnpublishRoom, {}, name, topic, { userId },
+ QStringLiteral("trusted_private_chat"), {}, true);
}
ForgetRoomJob* Connection::forgetRoom(const QString& id)
@@ -733,18 +792,18 @@ Connection::sendToDevices(const QString& eventType,
{
QHash<QString, QHash<QString, QJsonObject>> json;
json.reserve(int(eventsMap.size()));
- std::for_each(
- eventsMap.begin(), eventsMap.end(),
- [&json](const auto& userTodevicesToEvents) {
- auto& jsonUser = json[userTodevicesToEvents.first];
- const auto& devicesToEvents = userTodevicesToEvents.second;
- std::for_each(devicesToEvents.begin(), devicesToEvents.end(),
- [&jsonUser](const auto& deviceToEvents) {
- jsonUser.insert(
- deviceToEvents.first,
- deviceToEvents.second.contentJson());
- });
- });
+ std::for_each(eventsMap.begin(), eventsMap.end(),
+ [&json](const auto& userTodevicesToEvents) {
+ auto& jsonUser = json[userTodevicesToEvents.first];
+ const auto& devicesToEvents = userTodevicesToEvents.second;
+ std::for_each(devicesToEvents.begin(),
+ devicesToEvents.end(),
+ [&jsonUser](const auto& deviceToEvents) {
+ jsonUser.insert(
+ deviceToEvents.first,
+ deviceToEvents.second.contentJson());
+ });
+ });
return callApi<SendToDeviceJob>(BackgroundRequest, eventType,
generateTxnId(), json);
}
@@ -760,6 +819,8 @@ SendMessageJob* Connection::sendMessage(const QString& roomId,
QUrl Connection::homeserver() const { return d->data->baseUrl(); }
+QString Connection::domain() const { return d->userId.section(':', 1); }
+
Room* Connection::room(const QString& roomId, JoinStates states) const
{
Room* room = d->roomMap.value({ roomId, false }, nullptr);
@@ -794,19 +855,18 @@ void Connection::updateRoomAliases(const QString& roomId,
{
for (const auto& a : previousRoomAliases)
if (d->roomAliasMap.remove(a) == 0)
- qCWarning(MAIN)
- << "Alias" << a << "is not found (already deleted?)";
+ qCWarning(MAIN) << "Alias" << a << "is not found (already deleted?)";
for (const auto& a : roomAliases) {
auto& mappedId = d->roomAliasMap[a];
if (!mappedId.isEmpty()) {
if (mappedId == roomId)
- qCDebug(MAIN) << "Alias" << a << "is already mapped to room"
- << roomId;
+ qCDebug(MAIN)
+ << "Alias" << a << "is already mapped to room" << roomId;
else
qCWarning(MAIN)
- << "Alias" << a << "will be force-remapped from room"
- << mappedId << "to" << roomId;
+ << "Alias" << a << "will be force-remapped from room"
+ << mappedId << "to" << roomId;
}
mappedId = roomId;
}
@@ -901,7 +961,8 @@ QHash<QString, QVector<Room*>> Connection::tagsToRooms() const
{
QHash<QString, QVector<Room*>> result;
for (auto* r : qAsConst(d->roomMap)) {
- for (const auto& tagName : r->tagNames())
+ const auto& tagNames = r->tagNames();
+ for (const auto& tagName : tagNames)
result[tagName].push_back(r);
}
for (auto it = result.begin(); it != result.end(); ++it)
@@ -914,10 +975,12 @@ QHash<QString, QVector<Room*>> Connection::tagsToRooms() const
QStringList Connection::tagNames() const
{
QStringList tags({ FavouriteTag });
- for (auto* r : qAsConst(d->roomMap))
- for (const auto& tag : r->tagNames())
+ for (auto* r : qAsConst(d->roomMap)) {
+ const auto& tagNames = r->tagNames();
+ for (const auto& tag : tagNames)
if (tag != LowPriorityTag && !tags.contains(tag))
tags.push_back(tag);
+ }
tags.push_back(LowPriorityTag);
return tags;
}
@@ -925,8 +988,7 @@ QStringList Connection::tagNames() const
QVector<Room*> Connection::roomsWithTag(const QString& tagName) const
{
QVector<Room*> rooms;
- std::copy_if(d->roomMap.begin(), d->roomMap.end(),
- std::back_inserter(rooms),
+ std::copy_if(d->roomMap.begin(), d->roomMap.end(), std::back_inserter(rooms),
[&tagName](Room* r) { return r->tags().contains(tagName); });
return rooms;
}
@@ -936,27 +998,6 @@ Connection::DirectChatsMap Connection::directChats() const
return d->directChats;
}
-QJsonObject toJson(const Connection::DirectChatsMap& directChats)
-{
- QJsonObject json;
- for (auto it = directChats.begin(); it != directChats.end();) {
- QJsonArray roomIds;
- const auto* user = it.key();
- for (; it != directChats.end() && it.key() == user; ++it)
- roomIds.append(*it);
- json.insert(user->id(), roomIds);
- }
- return json;
-}
-
-void Connection::Private::broadcastDirectChatUpdates(
- const DirectChatsMap& additions, const DirectChatsMap& removals)
-{
- q->callApi<SetAccountDataJob>(userId, QStringLiteral("m.direct"),
- toJson(directChats));
- emit q->directChatsListChanged(additions, removals);
-}
-
void Connection::addToDirectChats(const Room* room, User* user)
{
Q_ASSERT(room != nullptr && user != nullptr);
@@ -965,8 +1006,8 @@ void Connection::addToDirectChats(const Room* room, User* user)
Q_ASSERT(!d->directChatUsers.contains(room->id(), user));
d->directChats.insert(user, room->id());
d->directChatUsers.insert(room->id(), user);
- DirectChatsMap additions { { user, room->id() } };
- d->broadcastDirectChatUpdates(additions, {});
+ d->dcLocalAdditions.insert(user, room->id());
+ emit directChatsListChanged({ { user, room->id() } }, {});
}
void Connection::removeFromDirectChats(const QString& roomId, User* user)
@@ -978,16 +1019,17 @@ void Connection::removeFromDirectChats(const QString& roomId, User* user)
DirectChatsMap removals;
if (user != nullptr) {
- removals.insert(user, roomId);
d->directChats.remove(user, roomId);
d->directChatUsers.remove(roomId, user);
+ removals.insert(user, roomId);
+ d->dcLocalRemovals.insert(user, roomId);
} else {
- removals = erase_if(d->directChats, [&roomId](auto it) {
- return it.value() == roomId;
- });
+ removals = erase_if(d->directChats,
+ [&roomId](auto it) { return it.value() == roomId; });
d->directChatUsers.remove(roomId);
+ d->dcLocalRemovals += removals;
}
- d->broadcastDirectChatUpdates({}, removals);
+ emit directChatsListChanged({}, removals);
}
bool Connection::isDirectChat(const QString& roomId) const
@@ -1094,6 +1136,9 @@ Room* Connection::provideRoom(const QString& id, Omittable<JoinState> joinState)
else if (joinState == JoinState::Leave)
emit leftRoom(room, prevInvite);
if (prevInvite) {
+ const auto dcUsers = prevInvite->directChatUsers();
+ for (auto* u : dcUsers)
+ addToDirectChats(room, u);
qCDebug(MAIN) << "Deleting Invite state for room"
<< prevInvite->id();
emit prevInvite->beforeDestruction(prevInvite);
@@ -1141,7 +1186,8 @@ void Connection::saveRoomState(Room* r) const
if (!d->cacheState)
return;
- QFile outRoomFile { stateCachePath() % SyncData::fileNameForRoom(r->id()) };
+ QFile outRoomFile { stateCacheDir().filePath(
+ SyncData::fileNameForRoom(r->id())) };
if (outRoomFile.open(QFile::WriteOnly)) {
QJsonDocument json { r->toJson() };
auto data = d->cacheToBinary ? json.toBinaryData()
@@ -1162,7 +1208,7 @@ void Connection::saveState() const
QElapsedTimer et;
et.start();
- QFile outFile { stateCachePath() % "state.json" };
+ QFile outFile { d->topLevelStatePath() };
if (!outFile.open(QFile::WriteOnly)) {
qCWarning(MAIN) << "Error opening" << outFile.fileName() << ":"
<< outFile.errorString();
@@ -1174,36 +1220,37 @@ void Connection::saveState() const
QJsonObject rootObj {
{ QStringLiteral("cache_version"),
QJsonObject {
- { QStringLiteral("major"), SyncData::cacheVersion().first },
- { QStringLiteral("minor"),
- SyncData::cacheVersion().second } } }
+ { QStringLiteral("major"), SyncData::cacheVersion().first },
+ { QStringLiteral("minor"), SyncData::cacheVersion().second } } }
};
{
QJsonObject rooms;
QJsonObject inviteRooms;
- for (const auto* i : roomMap()) // Pass on rooms in Leave state
+ const auto& rs = roomMap(); // Pass on rooms in Leave state
+ for (const auto* i : rs)
(i->joinState() == JoinState::Invite ? inviteRooms : rooms)
- .insert(i->id(), QJsonValue::Null);
+ .insert(i->id(), QJsonValue::Null);
QJsonObject roomObj;
if (!rooms.isEmpty())
- roomObj.insert("join", rooms);
+ roomObj.insert(QStringLiteral("join"), rooms);
if (!inviteRooms.isEmpty())
- roomObj.insert("invite", inviteRooms);
+ roomObj.insert(QStringLiteral("invite"), inviteRooms);
- rootObj.insert("next_batch", d->data->lastEvent());
- rootObj.insert("rooms", roomObj);
+ rootObj.insert(QStringLiteral("next_batch"), d->data->lastEvent());
+ rootObj.insert(QStringLiteral("rooms"), roomObj);
}
{
- QJsonArray accountDataEvents { basicEventJson(
- QStringLiteral("m.direct"), toJson(d->directChats)) };
+ QJsonArray accountDataEvents {
+ basicEventJson(QStringLiteral("m.direct"), toJson(d->directChats))
+ };
for (const auto& e : d->accountData)
accountDataEvents.append(
- basicEventJson(e.first, e.second->contentJson()));
+ basicEventJson(e.first, e.second->contentJson()));
- rootObj.insert("account_data",
- QJsonObject { { QStringLiteral("events"),
- accountDataEvents } });
+ rootObj.insert(QStringLiteral("account_data"),
+ QJsonObject {
+ { QStringLiteral("events"), accountDataEvents } });
}
QJsonDocument json { rootObj };
@@ -1223,7 +1270,7 @@ void Connection::loadState()
QElapsedTimer et;
et.start();
- SyncData sync { stateCachePath() % "state.json" };
+ SyncData sync { d->topLevelStatePath() };
if (sync.nextBatch().isEmpty()) // No token means no cache by definition
return;
@@ -1235,12 +1282,16 @@ void Connection::loadState()
// 1. Do initial sync on failed rooms without saving the nextBatch token
// 2. Do the sync across all rooms as normal
onSyncSuccess(std::move(sync), true);
- qCDebug(PROFILER) << "*** Cached state for" << userId() << "loaded in"
- << et;
+ qCDebug(PROFILER) << "*** Cached state for" << userId() << "loaded in" << et;
}
QString Connection::stateCachePath() const
{
+ return stateCacheDir().path() % '/';
+}
+
+QDir Connection::stateCacheDir() const
+{
auto safeUserId = userId();
safeUserId.replace(':', '_');
return cacheLocation(safeUserId);
@@ -1274,7 +1325,7 @@ void Connection::getTurnServers()
}
const QString Connection::SupportedRoomVersion::StableTag =
- QStringLiteral("stable");
+ QStringLiteral("stable");
QString Connection::defaultRoomVersion() const
{
@@ -1302,8 +1353,7 @@ inline bool roomVersionLess(const Connection::SupportedRoomVersion& v1,
return ok1 && ok2 ? vNum1 < vNum2 : v1.id < v2.id;
}
-QVector<Connection::SupportedRoomVersion>
-Connection::availableRoomVersions() const
+QVector<Connection::SupportedRoomVersion> Connection::availableRoomVersions() const
{
Q_ASSERT(!d->capabilities.roomVersions.omitted());
QVector<SupportedRoomVersion> result;
@@ -1313,9 +1363,8 @@ Connection::availableRoomVersions() const
result.push_back({ it.key(), it.value() });
// Put stable versions over unstable; within each group,
// sort numeric versions as numbers, the rest as strings.
- const auto mid =
- std::partition(result.begin(), result.end(),
- std::mem_fn(&SupportedRoomVersion::isStable));
+ const auto mid = std::partition(result.begin(), result.end(),
+ std::mem_fn(&SupportedRoomVersion::isStable));
std::sort(result.begin(), mid, roomVersionLess);
std::sort(mid, result.end(), roomVersionLess);
diff --git a/lib/connection.h b/lib/connection.h
index 50f7b71b..a13def10 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -18,754 +18,768 @@
#pragma once
-#include "csapi/create_room.h"
-#include "events/accountdataevents.h"
#include "joinstate.h"
#include "qt_connection_util.h"
+#include "csapi/create_room.h"
+
+#include "events/accountdataevents.h"
+
+#include <QtCore/QDir>
#include <QtCore/QObject>
#include <QtCore/QSize>
#include <QtCore/QUrl>
#include <functional>
-#include <memory>
-
-namespace QMatrixClient {
- class Room;
- class User;
- class ConnectionData;
- class RoomEvent;
-
- class SyncJob;
- class SyncData;
- class RoomMessagesJob;
- class PostReceiptJob;
- class ForgetRoomJob;
- class MediaThumbnailJob;
- class JoinRoomJob;
- class UploadContentJob;
- class GetContentJob;
- class DownloadFileJob;
- class SendToDeviceJob;
- class SendMessageJob;
- class LeaveRoomJob;
-
- class Connection;
-
- using room_factory_t =
- std::function<Room*(Connection*, const QString&, JoinState)>;
- using user_factory_t = std::function<User*(Connection*, const QString&)>;
-
- /** The default factory to create room objects
- *
- * Just a wrapper around operator new.
- * \sa Connection::setRoomFactory, Connection::setRoomType
+
+namespace QMatrixClient
+{
+class Room;
+class User;
+class ConnectionData;
+class RoomEvent;
+
+class SyncJob;
+class SyncData;
+class RoomMessagesJob;
+class PostReceiptJob;
+class ForgetRoomJob;
+class MediaThumbnailJob;
+class JoinRoomJob;
+class UploadContentJob;
+class GetContentJob;
+class DownloadFileJob;
+class SendToDeviceJob;
+class SendMessageJob;
+class LeaveRoomJob;
+
+class Connection;
+
+using room_factory_t =
+ std::function<Room*(Connection*, const QString&, JoinState)>;
+using user_factory_t = std::function<User*(Connection*, const QString&)>;
+
+/** The default factory to create room objects
+ *
+ * Just a wrapper around operator new.
+ * \sa Connection::setRoomFactory, Connection::setRoomType
+ */
+template <typename T = Room>
+static inline room_factory_t defaultRoomFactory()
+{
+ return [](Connection* c, const QString& id, JoinState js) {
+ return new T(c, id, js);
+ };
+}
+
+/** The default factory to create user objects
+ *
+ * Just a wrapper around operator new.
+ * \sa Connection::setUserFactory, Connection::setUserType
+ */
+template <typename T = User>
+static inline user_factory_t defaultUserFactory()
+{
+ return [](Connection* c, const QString& id) { return new T(id, c); };
+}
+
+/** Enumeration with flags defining the network job running policy
+ * So far only background/foreground flags are available.
+ *
+ * \sa Connection::callApi
+ */
+enum RunningPolicy
+{
+ ForegroundRequest = 0x0,
+ BackgroundRequest = 0x1
+};
+
+class Connection : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(User* localUser READ user NOTIFY stateChanged)
+ Q_PROPERTY(QString localUserId READ userId NOTIFY stateChanged)
+ Q_PROPERTY(QString deviceId READ deviceId NOTIFY stateChanged)
+ Q_PROPERTY(QByteArray accessToken READ accessToken NOTIFY stateChanged)
+ Q_PROPERTY(QString defaultRoomVersion READ defaultRoomVersion NOTIFY
+ capabilitiesLoaded)
+ Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver NOTIFY
+ homeserverChanged)
+ Q_PROPERTY(QString domain READ domain NOTIFY homeserverChanged)
+ Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY
+ cacheStateChanged)
+ Q_PROPERTY(bool lazyLoading READ lazyLoading WRITE setLazyLoading NOTIFY
+ lazyLoadingChanged)
+
+public:
+ // Room ids, rather than room pointers, are used in the direct chat
+ // map types because the library keeps Invite rooms separate from
+ // rooms in Join and Leave state; and direct chats in account data
+ // are stored with no regard to their state.
+ using DirectChatsMap = QMultiHash<const User*, QString>;
+ using DirectChatUsersMap = QMultiHash<QString, User*>;
+ using IgnoredUsersList = IgnoredUsersEvent::content_type;
+
+ using UsersToDevicesToEvents =
+ std::unordered_map<QString, std::unordered_map<QString, const Event&>>;
+
+ enum RoomVisibility
+ {
+ PublishRoom,
+ UnpublishRoom
+ }; // FIXME: Should go inside CreateRoomJob
+
+ explicit Connection(QObject* parent = nullptr);
+ explicit Connection(const QUrl& server, QObject* parent = nullptr);
+ virtual ~Connection();
+
+ /** 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
*/
- template <typename T = Room>
- static inline room_factory_t defaultRoomFactory()
+ QHash<QPair<QString, bool>, Room*> roomMap() const;
+
+ /** Check whether the account has data of the given type
+ * Direct chats map is not supported by this method _yet_.
+ */
+ bool hasAccountData(const QString& type) const;
+
+ /** Get a generic account data event of the given type
+ * This returns an account data event of the given type
+ * stored on the server. Direct chats map cannot be retrieved
+ * using this method _yet_; use directChats() instead.
+ */
+ const EventPtr& accountData(const QString& type) const;
+
+ /** Get a generic account data event of the given type
+ * This returns an account data event of the given type
+ * stored on the server. Direct chats map cannot be retrieved
+ * using this method _yet_; use directChats() instead.
+ */
+ template <typename EventT>
+ const typename EventT::content_type accountData() const
{
- return [](Connection* c, const QString& id, JoinState js) {
- return new T(c, id, js);
- };
+ if (const auto& eventPtr = accountData(EventT::matrixTypeId()))
+ return eventPtr->content();
+ return {};
}
- /** The default factory to create user objects
+ /** Get account data as a JSON object
+ * This returns the content part of the account data event
+ * of the given type. Direct chats map cannot be retrieved using
+ * this method _yet_; use directChats() instead.
+ */
+ Q_INVOKABLE QJsonObject accountDataJson(const QString& type) const;
+
+ /** Set a generic account data event of the given type */
+ void setAccountData(EventPtr&& event);
+
+ Q_INVOKABLE void setAccountData(const QString& type,
+ const QJsonObject& content);
+
+ /** Get all Invited and Joined rooms grouped by tag
+ * \return a hashmap from tag name to a vector of room pointers,
+ * sorted by their order in the tag - details are at
+ * https://matrix.org/speculator/spec/drafts%2Fe2e/client_server/unstable.html#id95
+ */
+ QHash<QString, QVector<Room*>> tagsToRooms() const;
+
+ /** Get all room tags known on this connection */
+ QStringList tagNames() const;
+
+ /** Get the list of rooms with the specified tag */
+ QVector<Room*> roomsWithTag(const QString& tagName) const;
+
+ /** Mark the room as a direct chat with the user
+ * This function marks \p room as a direct chat with \p user.
+ * Emits the signal synchronously, without waiting to complete
+ * synchronisation with the server.
*
- * Just a wrapper around operator new.
- * \sa Connection::setUserFactory, Connection::setUserType
+ * \sa directChatsListChanged
*/
- template <typename T = User>
- static inline user_factory_t defaultUserFactory()
- {
- return [](Connection* c, const QString& id) { return new T(id, c); };
- }
+ void addToDirectChats(const Room* room, User* user);
+
+ /** Unmark the room from direct chats
+ * This function removes the room id from direct chats either for
+ * a specific \p user or for all users if \p user in nullptr.
+ * The room id is used to allow removal of, e.g., ids of forgotten
+ * rooms; a Room object need not exist. Emits the signal
+ * immediately, without waiting to complete synchronisation with
+ * the server.
+ *
+ * \sa directChatsListChanged
+ */
+ void removeFromDirectChats(const QString& roomId, User* user = nullptr);
+
+ /** Check whether the room id corresponds to a direct chat */
+ bool isDirectChat(const QString& roomId) const;
- /** Enumeration with flags defining the network job running policy
- * So far only background/foreground flags are available.
+ /** Get the whole map from users to direct chat rooms */
+ DirectChatsMap directChats() const;
+
+ /** Retrieve the list of users the room is a direct chat with
+ * @return The list of users for which this room is marked as
+ * a direct chat; an empty list if the room is not a direct chat
+ */
+ QList<User*> directChatUsers(const Room* room) const;
+
+ /** Check whether a particular user is in the ignore list */
+ Q_INVOKABLE bool isIgnored(const User* user) const;
+
+ /** Get the whole list of ignored users */
+ Q_INVOKABLE IgnoredUsersList ignoredUsers() const;
+
+ /** Add the user to the ignore list
+ * The change signal is emitted synchronously, without waiting
+ * to complete synchronisation with the server.
*
- * \sa Connection::callApi
+ * \sa ignoredUsersListChanged
*/
- enum RunningPolicy { ForegroundRequest = 0x0, BackgroundRequest = 0x1 };
+ Q_INVOKABLE void addToIgnoredUsers(const User* user);
- class Connection : public QObject
+ /** Remove the user from the ignore list */
+ /** Similar to adding, the change signal is emitted synchronously.
+ *
+ * \sa ignoredUsersListChanged
+ */
+ Q_INVOKABLE void removeFromIgnoredUsers(const User* user);
+
+ /** Get the full list of users known to this account */
+ QMap<QString, User*> users() const;
+
+ /** Get the base URL of the homeserver to connect to */
+ QUrl homeserver() const;
+ /** Get the domain name used for ids/aliases on the server */
+ QString domain() const;
+ /** Find a room by its id and a mask of applicable states */
+ Q_INVOKABLE Room* room(const QString& roomId,
+ JoinStates states = JoinState::Invite
+ | JoinState::Join) const;
+ /** Find a room by its alias and a mask of applicable states */
+ Q_INVOKABLE Room* roomByAlias(const QString& roomAlias,
+ JoinStates states = JoinState::Invite
+ | JoinState::Join) const;
+ /** Update the internal map of room aliases to IDs */
+ /// This is used for internal bookkeeping of rooms. Do NOT use
+ /// it to try change aliases, use Room::setAliases instead
+ void updateRoomAliases(const QString& roomId,
+ const QStringList& previousRoomAliases,
+ const QStringList& roomAliases);
+ Q_INVOKABLE Room* invitation(const QString& roomId) const;
+ Q_INVOKABLE User* user(const QString& userId);
+ const User* user() const;
+ User* user();
+ QString userId() const;
+ QString deviceId() const;
+ QByteArray accessToken() const;
+ Q_INVOKABLE SyncJob* syncJob() const;
+ Q_INVOKABLE int millisToReconnect() const;
+
+ [[deprecated("Use accessToken() instead")]] Q_INVOKABLE QString token() const;
+ Q_INVOKABLE void getTurnServers();
+
+ struct SupportedRoomVersion
{
- Q_OBJECT
-
- /** Whether or not the rooms state should be cached locally
- * \sa loadState(), saveState()
- */
- Q_PROPERTY(User* localUser READ user NOTIFY stateChanged)
- Q_PROPERTY(QString localUserId READ userId NOTIFY stateChanged)
- Q_PROPERTY(QString deviceId READ deviceId NOTIFY stateChanged)
- Q_PROPERTY(QByteArray accessToken READ accessToken NOTIFY stateChanged)
- Q_PROPERTY(QString defaultRoomVersion READ defaultRoomVersion NOTIFY
- capabilitiesLoaded)
- Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver NOTIFY
- homeserverChanged)
- Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY
- cacheStateChanged)
- Q_PROPERTY(bool lazyLoading READ lazyLoading WRITE setLazyLoading NOTIFY
- lazyLoadingChanged)
-
- public:
- // Room ids, rather than room pointers, are used in the direct chat
- // map types because the library keeps Invite rooms separate from
- // rooms in Join and Leave state; and direct chats in account data
- // are stored with no regard to their state.
- using DirectChatsMap = QMultiHash<const User*, QString>;
- using DirectChatUsersMap = QMultiHash<QString, User*>;
- using IgnoredUsersList = IgnoredUsersEvent::content_type;
-
- using UsersToDevicesToEvents =
- std::unordered_map<QString,
- std::unordered_map<QString, const Event&>>;
-
- enum RoomVisibility {
- PublishRoom,
- UnpublishRoom
- }; // FIXME: Should go inside CreateRoomJob
-
- explicit Connection(QObject* parent = nullptr);
- explicit Connection(const QUrl& server, QObject* parent = nullptr);
- virtual ~Connection();
-
- /** 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
- */
- QHash<QPair<QString, bool>, Room*> roomMap() const;
-
- /** Check whether the account has data of the given type
- * Direct chats map is not supported by this method _yet_.
- */
- bool hasAccountData(const QString& type) const;
-
- /** Get a generic account data event of the given type
- * This returns an account data event of the given type
- * stored on the server. Direct chats map cannot be retrieved
- * using this method _yet_; use directChats() instead.
- */
- const EventPtr& accountData(const QString& type) const;
-
- /** Get a generic account data event of the given type
- * This returns an account data event of the given type
- * stored on the server. Direct chats map cannot be retrieved
- * using this method _yet_; use directChats() instead.
- */
- template <typename EventT>
- const typename EventT::content_type accountData() const
- {
- if (const auto& eventPtr = accountData(EventT::matrixTypeId()))
- return eventPtr->content();
- return {};
- }
+ QString id;
+ QString status;
- /** Get account data as a JSON object
- * This returns the content part of the account data event
- * of the given type. Direct chats map cannot be retrieved using
- * this method _yet_; use directChats() instead.
- */
- Q_INVOKABLE QJsonObject accountDataJson(const QString& type) const;
-
- /** Set a generic account data event of the given type */
- void setAccountData(EventPtr&& event);
-
- Q_INVOKABLE void setAccountData(const QString& type,
- const QJsonObject& content);
-
- /** Get all Invited and Joined rooms grouped by tag
- * \return a hashmap from tag name to a vector of room pointers,
- * sorted by their order in the tag - details are at
- * https://matrix.org/speculator/spec/drafts%2Fe2e/client_server/unstable.html#id95
- */
- QHash<QString, QVector<Room*>> tagsToRooms() const;
-
- /** Get all room tags known on this connection */
- QStringList tagNames() const;
-
- /** Get the list of rooms with the specified tag */
- QVector<Room*> roomsWithTag(const QString& tagName) const;
-
- /** Mark the room as a direct chat with the user
- * This function marks \p room as a direct chat with \p user.
- * Emits the signal synchronously, without waiting to complete
- * synchronisation with the server.
- *
- * \sa directChatsListChanged
- */
- void addToDirectChats(const Room* room, User* user);
-
- /** Unmark the room from direct chats
- * This function removes the room id from direct chats either for
- * a specific \p user or for all users if \p user in nullptr.
- * The room id is used to allow removal of, e.g., ids of forgotten
- * rooms; a Room object need not exist. Emits the signal
- * immediately, without waiting to complete synchronisation with
- * the server.
- *
- * \sa directChatsListChanged
- */
- void removeFromDirectChats(const QString& roomId, User* user = nullptr);
-
- /** Check whether the room id corresponds to a direct chat */
- bool isDirectChat(const QString& roomId) const;
-
- /** Get the whole map from users to direct chat rooms */
- DirectChatsMap directChats() const;
-
- /** Retrieve the list of users the room is a direct chat with
- * @return The list of users for which this room is marked as
- * a direct chat; an empty list if the room is not a direct chat
- */
- QList<User*> directChatUsers(const Room* room) const;
-
- /** Check whether a particular user is in the ignore list */
- bool isIgnored(const User* user) const;
-
- /** Get the whole list of ignored users */
- IgnoredUsersList ignoredUsers() const;
-
- /** Add the user to the ignore list
- * The change signal is emitted synchronously, without waiting
- * to complete synchronisation with the server.
- *
- * \sa ignoredUsersListChanged
- */
- void addToIgnoredUsers(const User* user);
-
- /** Remove the user from the ignore list */
- /** Similar to adding, the change signal is emitted synchronously.
- *
- * \sa ignoredUsersListChanged
- */
- void removeFromIgnoredUsers(const User* user);
-
- /** Get the full list of users known to this account */
- QMap<QString, User*> users() const;
-
- QUrl homeserver() const;
- /** Find a room by its id and a mask of applicable states */
- Q_INVOKABLE Room* room(const QString& roomId,
- JoinStates states = JoinState::Invite
- | JoinState::Join) const;
- /** Find a room by its alias and a mask of applicable states */
- Q_INVOKABLE Room* roomByAlias(const QString& roomAlias,
- JoinStates states = JoinState::Invite
- | JoinState::Join) const;
- /** Update the internal map of room aliases to IDs */
- /// This is used for internal bookkeeping of rooms. Do NOT use
- /// it to try change aliases, use Room::setAliases instead
- void updateRoomAliases(const QString& roomId,
- const QStringList& previousRoomAliases,
- const QStringList& roomAliases);
- Q_INVOKABLE Room* invitation(const QString& roomId) const;
- Q_INVOKABLE User* user(const QString& userId);
- const User* user() const;
- User* user();
- QString userId() const;
- QString deviceId() const;
- QByteArray accessToken() const;
- Q_INVOKABLE SyncJob* syncJob() const;
- Q_INVOKABLE int millisToReconnect() const;
-
- [[deprecated("Use accessToken() instead")]] Q_INVOKABLE QString
- token() const;
- Q_INVOKABLE void getTurnServers();
-
- struct SupportedRoomVersion {
- QString id;
- QString status;
-
- static const QString StableTag; // "stable", as of CS API 0.5
- bool isStable() const { return status == StableTag; }
-
- friend QDebug operator<<(QDebug dbg, const SupportedRoomVersion& v)
- {
- QDebugStateSaver _(dbg);
- return dbg.nospace() << v.id << '/' << v.status;
- }
- };
-
- /// Get the room version recommended by the server
- /** Only works after server capabilities have been loaded.
- * \sa loadingCapabilities */
- QString defaultRoomVersion() const;
- /// Get the room version considered stable by the server
- /** Only works after server capabilities have been loaded.
- * \sa loadingCapabilities */
- QStringList stableRoomVersions() const;
- /// Get all room versions supported by the server
- /** Only works after server capabilities have been loaded.
- * \sa loadingCapabilities */
- QVector<SupportedRoomVersion> availableRoomVersions() const;
-
- /**
- * Call this before first sync to load from previously saved file.
- *
- * \param fromFile A local path to read the state from. Uses QUrl
- * to be QML-friendly. Empty parameter means using a path
- * defined by stateCachePath().
- */
- Q_INVOKABLE void loadState();
- /**
- * This method saves the current state of rooms (but not messages
- * in them) to a local cache file, so that it could be loaded by
- * loadState() on a next run of the client.
- *
- * \param toFile A local path to save the state to. Uses QUrl to be
- * QML-friendly. Empty parameter means using a path defined by
- * stateCachePath().
- */
- Q_INVOKABLE void saveState() const;
-
- /// This method saves the current state of a single room.
- void saveRoomState(Room* r) const;
-
- /**
- * The default path to store the cached room state, defined as
- * follows:
- * QStandardPaths::writeableLocation(QStandardPaths::CacheLocation)
- * + _safeUserId + "_state.json" where `_safeUserId` is userId() with
- * `:` (colon) replaced with
- * `_` (underscore)
- * /see loadState(), saveState()
- */
- Q_INVOKABLE QString stateCachePath() const;
-
- bool cacheState() const;
- void setCacheState(bool newValue);
-
- bool lazyLoading() const;
- void setLazyLoading(bool newValue);
-
- /** Start a job of a specified type with specified arguments and policy
- *
- * This is a universal method to start a job of a type passed
- * as a template parameter. The policy allows to fine-tune the way
- * the job is executed - as of this writing it means a choice
- * between "foreground" and "background".
- *
- * \param runningPolicy controls how the job is executed
- * \param jobArgs arguments to the job constructor
- *
- * \sa BaseJob::isBackground.
- * QNetworkRequest::BackgroundRequestAttribute
- */
- template <typename JobT, typename... JobArgTs>
- JobT* callApi(RunningPolicy runningPolicy, JobArgTs&&... jobArgs) const
- {
- auto job = new JobT(std::forward<JobArgTs>(jobArgs)...);
- connect(job, &BaseJob::failure, this, &Connection::requestFailed);
- job->start(connectionData(), runningPolicy & BackgroundRequest);
- return job;
- }
+ static const QString StableTag; // "stable", as of CS API 0.5
+ bool isStable() const { return status == StableTag; }
- /** Start a job of a specified type with specified arguments
- *
- * This is an overload that calls the job with "foreground" policy.
- */
- template <typename JobT, typename... JobArgTs>
- JobT* callApi(JobArgTs&&... jobArgs) const
+ friend QDebug operator<<(QDebug dbg, const SupportedRoomVersion& v)
{
- return callApi<JobT>(ForegroundRequest,
- std::forward<JobArgTs>(jobArgs)...);
+ QDebugStateSaver _(dbg);
+ return dbg.nospace() << v.id << '/' << v.status;
}
+ };
- /** Generate a new transaction id. Transaction id's are unique within
- * a single Connection object
- */
- Q_INVOKABLE QByteArray generateTxnId() const;
+ /// Get the room version recommended by the server
+ /** Only works after server capabilities have been loaded.
+ * \sa loadingCapabilities */
+ QString defaultRoomVersion() const;
+ /// Get the room version considered stable by the server
+ /** Only works after server capabilities have been loaded.
+ * \sa loadingCapabilities */
+ QStringList stableRoomVersions() const;
+ /// Get all room versions supported by the server
+ /** Only works after server capabilities have been loaded.
+ * \sa loadingCapabilities */
+ QVector<SupportedRoomVersion> availableRoomVersions() const;
+
+ /**
+ * Call this before first sync to load from previously saved file.
+ *
+ * \param fromFile A local path to read the state from. Uses QUrl
+ * to be QML-friendly. Empty parameter means saving to the directory
+ * defined by stateCachePath() / stateCacheDir().
+ */
+ Q_INVOKABLE void loadState();
+ /**
+ * This method saves the current state of rooms (but not messages
+ * in them) to a local cache file, so that it could be loaded by
+ * loadState() on a next run of the client.
+ *
+ * \param toFile A local path to save the state to. Uses QUrl to be
+ * QML-friendly. Empty parameter means saving to the directory
+ * defined by stateCachePath() / stateCacheDir().
+ */
+ Q_INVOKABLE void saveState() const;
+
+ /// This method saves the current state of a single room.
+ void saveRoomState(Room* r) const;
+
+ /// Get the default directory path to save the room state to
+ /** \sa stateCacheDir */
+ Q_INVOKABLE QString stateCachePath() const;
+
+ /// Get the default directory to save the room state to
+ /**
+ * This function returns the default directory to store the cached
+ * room state, defined as follows:
+ * \code
+ * QStandardPaths::writeableLocation(QStandardPaths::CacheLocation) +
+ * _safeUserId + "_state.json" \endcode where `_safeUserId` is userId() with
+ * `:` (colon) replaced by
+ * `_` (underscore), as colons are reserved characters on Windows.
+ * \sa loadState, saveState, stateCachePath
+ */
+ QDir stateCacheDir() const;
- /// Set a room factory function
- static void setRoomFactory(room_factory_t f);
+ /** Whether or not the rooms state should be cached locally
+ * \sa loadState(), saveState()
+ */
+ bool cacheState() const;
+ void setCacheState(bool newValue);
- /// Set a user factory function
- static void setUserFactory(user_factory_t f);
+ bool lazyLoading() const;
+ void setLazyLoading(bool newValue);
- /// Get a room factory function
- static room_factory_t roomFactory();
+ /** Start a job of a specified type with specified arguments and policy
+ *
+ * This is a universal method to start a job of a type passed
+ * as a template parameter. The policy allows to fine-tune the way
+ * the job is executed - as of this writing it means a choice
+ * between "foreground" and "background".
+ *
+ * \param runningPolicy controls how the job is executed
+ * \param jobArgs arguments to the job constructor
+ *
+ * \sa BaseJob::isBackground. QNetworkRequest::BackgroundRequestAttribute
+ */
+ template <typename JobT, typename... JobArgTs>
+ JobT* callApi(RunningPolicy runningPolicy, JobArgTs&&... jobArgs) const
+ {
+ auto job = new JobT(std::forward<JobArgTs>(jobArgs)...);
+ connect(job, &BaseJob::failure, this, &Connection::requestFailed);
+ job->start(connectionData(), runningPolicy & BackgroundRequest);
+ return job;
+ }
+
+ /** Start a job of a specified type with specified arguments
+ *
+ * This is an overload that calls the job with "foreground" policy.
+ */
+ template <typename JobT, typename... JobArgTs>
+ JobT* callApi(JobArgTs&&... jobArgs) const
+ {
+ return callApi<JobT>(ForegroundRequest,
+ std::forward<JobArgTs>(jobArgs)...);
+ }
- /// Get a user factory function
- static user_factory_t userFactory();
+ /** Generate a new transaction id. Transaction id's are unique within
+ * a single Connection object
+ */
+ Q_INVOKABLE QByteArray generateTxnId() const;
- /// Set the room factory to default with the overriden room type
- template <typename T> static void setRoomType()
- {
- setRoomFactory(defaultRoomFactory<T>());
- }
+ /// Set a room factory function
+ static void setRoomFactory(room_factory_t f);
- /// Set the user factory to default with the overriden user type
- template <typename T> static void setUserType()
- {
- setUserFactory(defaultUserFactory<T>());
- }
+ /// Set a user factory function
+ static void setUserFactory(user_factory_t f);
- public slots:
- /** Set the homeserver base URL */
- void setHomeserver(const QUrl& baseUrl);
-
- /** Determine and set the homeserver from domain or MXID */
- void resolveServer(const QString& mxidOrDomain);
-
- void connectToServer(const QString& user, const QString& password,
- const QString& initialDeviceName,
- const QString& deviceId = {});
- void connectWithToken(const QString& userId, const QString& accessToken,
- const QString& 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);
- void syncLoop(int timeout = -1);
-
- void stopSync();
- QString nextBatchToken() const;
-
- virtual MediaThumbnailJob*
- getThumbnail(const QString& mediaId, QSize requestedSize,
- RunningPolicy policy = BackgroundRequest) const;
- MediaThumbnailJob*
- getThumbnail(const QUrl& url, QSize requestedSize,
- RunningPolicy policy = BackgroundRequest) const;
- MediaThumbnailJob*
- getThumbnail(const QUrl& url, int requestedWidth, int requestedHeight,
- RunningPolicy policy = BackgroundRequest) const;
-
- // QIODevice* should already be open
- UploadContentJob*
- uploadContent(QIODevice* contentSource, const QString& filename = {},
- const QString& overrideContentType = {}) const;
- UploadContentJob* uploadFile(const QString& fileName,
- const QString& overrideContentType = {});
- GetContentJob* getContent(const QString& mediaId) const;
- GetContentJob* getContent(const QUrl& url) const;
- // If localFilename is empty, a temporary file will be created
- DownloadFileJob* downloadFile(const QUrl& url,
- const QString& localFilename = {}) const;
-
- /**
- * \brief Create a room (generic method)
- * This method allows to customize room entirely to your liking,
- * providing all the attributes the original CS API provides.
- */
- CreateRoomJob*
- createRoom(RoomVisibility visibility, const QString& alias,
- const QString& name, const QString& topic,
- QStringList invites, const QString& presetName = {},
- const QString& roomVersion = {}, bool isDirect = false,
- const QVector<CreateRoomJob::StateEvent>& initialState = {},
- const QVector<CreateRoomJob::Invite3pid>& invite3pids = {},
- const QJsonObject& creationContent = {});
-
- /** Get a direct chat with a single user
- * This method may return synchronously or asynchoronously depending
- * on whether a direct chat room with the respective person exists
- * already.
- *
- * \sa directChatAvailable
- */
- void requestDirectChat(const QString& userId);
-
- /** Get a direct chat with a single user
- * This method may return synchronously or asynchoronously depending
- * on whether a direct chat room with the respective person exists
- * already.
- *
- * \sa directChatAvailable
- */
- void requestDirectChat(User* u);
-
- /** Run an operation in a direct chat with the user
- * This method may return synchronously or asynchoronously depending
- * on whether a direct chat room with the respective person exists
- * already. Instead of emitting a signal it executes the passed
- * function object with the direct chat room as its parameter.
- */
- void doInDirectChat(const QString& userId,
- const std::function<void(Room*)>& operation);
-
- /** Run an operation in a direct chat with the user
- * This method may return synchronously or asynchoronously depending
- * on whether a direct chat room with the respective person exists
- * already. Instead of emitting a signal it executes the passed
- * function object with the direct chat room as its parameter.
- */
- void doInDirectChat(User* u,
- const std::function<void(Room*)>& operation);
-
- /** Create a direct chat with a single user, optional name and topic
- * A room will always be created, unlike in requestDirectChat.
- * It is advised to use requestDirectChat as a default way of getting
- * one-on-one with a person, and only use createDirectChat when
- * a new creation is explicitly desired.
- */
- CreateRoomJob* createDirectChat(const QString& userId,
- const QString& topic = {},
- const QString& name = {});
-
- virtual JoinRoomJob* joinRoom(const QString& roomAlias,
- const QStringList& serverNames = {});
-
- /** Sends /forget to the server and also deletes room locally.
- * This method is in Connection, not in Room, since it's a
- * room lifecycle operation, and Connection is an acting room manager.
- * It ensures that the local user is not a member of a room (running
- * /leave, if necessary) then issues a /forget request and if that one
- * doesn't fail deletion of the local Room object is ensured. \param id
- * - the room id to forget \return - the ongoing /forget request to the
- * server; note that the success() signal of this request is connected
- * to deleteLater() of a respective room so by the moment this finishes,
- * there might be no Room object anymore.
- */
- ForgetRoomJob* forgetRoom(const QString& id);
-
- SendToDeviceJob*
- sendToDevices(const QString& eventType,
- const UsersToDevicesToEvents& eventsMap) const;
-
- /** \deprecated This method is experimental and may be removed any time
- */
- SendMessageJob* sendMessage(const QString& roomId,
- const RoomEvent& event) const;
-
- /** \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) const;
- 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
- * homeserverChanged() instead of resolved(). You can also use
- * connectToServer and connectWithToken without the HS URL set in
- * advance (i.e. without calling resolveServer), as they now trigger
- * server name resolution from MXID if the server URL is not valid.
- */
- void resolved();
- void resolveError(QString error);
-
- void homeserverChanged(QUrl baseUrl);
- void capabilitiesLoaded();
-
- void connected();
- void reconnected(); //< \deprecated Use connected() instead
- void loggedOut();
- /** Login data or state have changed
- *
- * This is a common change signal for userId, deviceId and
- * accessToken - these properties normally only change at
- * a successful login and logout and are constant at other times.
- */
- void stateChanged();
- void loginError(QString message, QString details);
-
- /** A network request (job) failed
- *
- * @param request - the pointer to the failed job
- */
- void requestFailed(BaseJob* request);
-
- /** A network request (job) failed due to network problems
- *
- * This is _only_ emitted when the job will retry on its own;
- * once it gives up, requestFailed() will be emitted.
- *
- * @param message - message about the network problem
- * @param details - raw error details, if any available
- * @param retriesTaken - how many retries have already been taken
- * @param nextRetryInMilliseconds - when the job will retry again
- */
- void networkError(QString message, QString details, int retriesTaken,
- int nextRetryInMilliseconds);
-
- void syncDone();
- void syncError(QString message, QString details);
-
- void newUser(User* user);
-
- /**
- * \group Signals emitted on room transitions
- *
- * Note: Rooms in Invite state are always stored separately from
- * rooms in Join/Leave state, because of special treatment of
- * invite_state in Matrix CS API (see The Spec on /sync for details).
- * Therefore, objects below are: r - room in Join/Leave state;
- * i - room in Invite state
- *
- * 1. none -> Invite: newRoom(r), invitedRoom(r,nullptr)
- * 2. none -> Join: newRoom(r), joinedRoom(r,nullptr)
- * 3. none -> Leave: newRoom(r), leftRoom(r,nullptr)
- * 4. Invite -> Join:
- * newRoom(r), joinedRoom(r,i), aboutToDeleteRoom(i)
- * 4a. Leave and Invite -> Join:
- * joinedRoom(r,i), aboutToDeleteRoom(i)
- * 5. Invite -> Leave:
- * newRoom(r), leftRoom(r,i), aboutToDeleteRoom(i)
- * 5a. Leave and Invite -> Leave:
- * leftRoom(r,i), aboutToDeleteRoom(i)
- * 6. Join -> Leave: leftRoom(r)
- * 7. Leave -> Invite: newRoom(i), invitedRoom(i,r)
- * 8. Leave -> Join: joinedRoom(r)
- * The following transitions are only possible via forgetRoom()
- * so far; if a room gets forgotten externally, sync won't tell
- * about it:
- * 9. any -> none: as any -> Leave, then aboutToDeleteRoom(r)
- */
-
- /** A new room object has been created */
- void newRoom(Room* room);
-
- /** A room invitation is seen for the first time
- *
- * If the same room is in Left state, it's passed in prev. Beware
- * that initial sync will trigger this signal for all rooms in
- * Invite state.
- */
- void invitedRoom(Room* room, Room* prev);
-
- /** A joined room is seen for the first time
- *
- * It's not the same as receiving a room in "join" section of sync
- * response (rooms will be there even after joining); it's also
- * not (exactly) the same as actual joining action of a user (all
- * rooms coming in initial sync will trigger this signal too). If
- * this room was in Invite state before, the respective object is
- * passed in prev (and it will be deleted shortly afterwards).
- */
- void joinedRoom(Room* room, Room* prev);
-
- /** A room has just been left
- *
- * If this room has been in Invite state (as in case of rejecting
- * an invitation), the respective object will be passed in prev
- * (and will be deleted shortly afterwards). Note that, similar
- * to invitedRoom and joinedRoom, this signal is triggered for all
- * Left rooms upon initial sync (not only those that were left
- * right before the sync).
- */
- void leftRoom(Room* room, Room* prev);
-
- /** The room object is about to be deleted */
- void aboutToDeleteRoom(Room* room);
-
- /** The room has just been created by createRoom or requestDirectChat
- *
- * This signal is not emitted in usual room state transitions,
- * only as an outcome of room creation operations invoked by
- * the client.
- * \note requestDirectChat doesn't necessarily create a new chat;
- * use directChatAvailable signal if you just need to obtain
- * a direct chat room.
- */
- void createdRoom(Room* room);
-
- /** The first sync for the room has been completed
- *
- * This signal is emitted after the room has been synced the first
- * time. This is the right signal to connect to if you need to
- * access the room state (name, aliases, members); state transition
- * signals (newRoom, joinedRoom etc.) come earlier, when the room
- * has just been created.
- */
- void loadedRoomState(Room* room);
-
- /** Account data (except direct chats) have changed */
- void accountDataChanged(QString type);
-
- /** The direct chat room is ready for using
- * This signal is emitted upon any successful outcome from
- * requestDirectChat.
- */
- void directChatAvailable(Room* directChat);
-
- /** The list of direct chats has changed
- * This signal is emitted every time when the mapping of users
- * to direct chat rooms is changed (because of either local updates
- * or a different list arrived from the server).
- */
- void directChatsListChanged(DirectChatsMap additions,
- DirectChatsMap removals);
-
- void ignoredUsersListChanged(IgnoredUsersList additions,
- IgnoredUsersList removals);
-
- void cacheStateChanged();
- void lazyLoadingChanged();
- void turnServersChanged(const QJsonObject& servers);
-
- protected:
- /**
- * @brief Access the underlying ConnectionData class
- */
- const ConnectionData* connectionData() const;
-
- /** Get a Room object for the given id in the given state
- *
- * Use this method when you need a Room object in the local list
- * of rooms, with the given state. Note that this does not interact
- * with the server; in particular, does not automatically create
- * rooms on the server. This call performs necessary join state
- * transitions; e.g., if it finds a room in Invite but
- * `joinState == JoinState::Join` then the Invite room object
- * will be deleted and a new room object with Join state created.
- * In contrast, switching between Join and Leave happens within
- * the same object.
- * \param roomId room id (not alias!)
- * \param joinState desired (target) join state of the room; if
- * omitted, any state will be found and return unchanged, or a
- * new Join room created.
- * @return a pointer to a Room object with the specified id and the
- * specified state; nullptr if roomId is empty or if roomFactory()
- * failed to create a Room object.
- */
- Room* provideRoom(const QString& roomId,
- Omittable<JoinState> joinState = none);
-
- /**
- * Completes loading sync data.
- */
- void onSyncSuccess(SyncData&& data, bool fromCache = false);
-
- protected slots:
- void syncLoopIteration();
-
- private:
- class Private;
- std::unique_ptr<Private> d;
-
- /**
- * A single entry for functions that need to check whether the
- * homeserver is valid before running. May either execute connectFn
- * synchronously or asynchronously (if tryResolve is true and
- * a DNS lookup is initiated); in case of errors, emits resolveError
- * if the homeserver URL is not valid and cannot be resolved from
- * userId.
- *
- * @param userId - fully-qualified MXID to resolve HS from
- * @param connectFn - a function to execute once the HS URL is good
- */
- void checkAndConnect(const QString& userId,
- std::function<void()> connectFn);
- void doConnectToServer(const QString& user, const QString& password,
- const QString& initialDeviceName,
- const QString& deviceId = {});
-
- static room_factory_t _roomFactory;
- static user_factory_t _userFactory;
- };
+ /// Get a room factory function
+ static room_factory_t roomFactory();
+
+ /// Get a user factory function
+ static user_factory_t userFactory();
+
+ /// Set the room factory to default with the overriden room type
+ template <typename T>
+ static void setRoomType()
+ {
+ setRoomFactory(defaultRoomFactory<T>());
+ }
+
+ /// Set the user factory to default with the overriden user type
+ template <typename T>
+ static void setUserType()
+ {
+ setUserFactory(defaultUserFactory<T>());
+ }
+
+public slots:
+ /** Set the homeserver base URL */
+ void setHomeserver(const QUrl& baseUrl);
+
+ /** Determine and set the homeserver from domain or MXID */
+ void resolveServer(const QString& mxidOrDomain);
+
+ void connectToServer(const QString& user, const QString& password,
+ const QString& initialDeviceName,
+ const QString& deviceId = {});
+ void connectWithToken(const QString& userId, const QString& accessToken,
+ const QString& 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);
+ void syncLoop(int timeout = -1);
+
+ void stopSync();
+ QString nextBatchToken() const;
+
+ virtual MediaThumbnailJob*
+ getThumbnail(const QString& mediaId, QSize requestedSize,
+ RunningPolicy policy = BackgroundRequest) const;
+ MediaThumbnailJob*
+ getThumbnail(const QUrl& url, QSize requestedSize,
+ RunningPolicy policy = BackgroundRequest) const;
+ MediaThumbnailJob*
+ getThumbnail(const QUrl& url, int requestedWidth, int requestedHeight,
+ RunningPolicy policy = BackgroundRequest) const;
+
+ // QIODevice* should already be open
+ UploadContentJob*
+ uploadContent(QIODevice* contentSource, const QString& filename = {},
+ const QString& overrideContentType = {}) const;
+ UploadContentJob* uploadFile(const QString& fileName,
+ const QString& overrideContentType = {});
+ GetContentJob* getContent(const QString& mediaId) const;
+ GetContentJob* getContent(const QUrl& url) const;
+ // If localFilename is empty, a temporary file will be created
+ DownloadFileJob* downloadFile(const QUrl& url,
+ const QString& localFilename = {}) const;
+
+ /**
+ * \brief Create a room (generic method)
+ * This method allows to customize room entirely to your liking,
+ * providing all the attributes the original CS API provides.
+ */
+ CreateRoomJob*
+ createRoom(RoomVisibility visibility, const QString& alias,
+ const QString& name, const QString& topic, QStringList invites,
+ const QString& presetName = {}, const QString& roomVersion = {},
+ bool isDirect = false,
+ const QVector<CreateRoomJob::StateEvent>& initialState = {},
+ const QVector<CreateRoomJob::Invite3pid>& invite3pids = {},
+ const QJsonObject& creationContent = {});
+
+ /** Get a direct chat with a single user
+ * This method may return synchronously or asynchoronously depending
+ * on whether a direct chat room with the respective person exists
+ * already.
+ *
+ * \sa directChatAvailable
+ */
+ void requestDirectChat(const QString& userId);
+
+ /** Get a direct chat with a single user
+ * This method may return synchronously or asynchoronously depending
+ * on whether a direct chat room with the respective person exists
+ * already.
+ *
+ * \sa directChatAvailable
+ */
+ void requestDirectChat(User* u);
+
+ /** Run an operation in a direct chat with the user
+ * This method may return synchronously or asynchoronously depending
+ * on whether a direct chat room with the respective person exists
+ * already. Instead of emitting a signal it executes the passed
+ * function object with the direct chat room as its parameter.
+ */
+ void doInDirectChat(const QString& userId,
+ const std::function<void(Room*)>& operation);
+
+ /** Run an operation in a direct chat with the user
+ * This method may return synchronously or asynchoronously depending
+ * on whether a direct chat room with the respective person exists
+ * already. Instead of emitting a signal it executes the passed
+ * function object with the direct chat room as its parameter.
+ */
+ void doInDirectChat(User* u, const std::function<void(Room*)>& operation);
+
+ /** Create a direct chat with a single user, optional name and topic
+ * A room will always be created, unlike in requestDirectChat.
+ * It is advised to use requestDirectChat as a default way of getting
+ * one-on-one with a person, and only use createDirectChat when
+ * a new creation is explicitly desired.
+ */
+ CreateRoomJob* createDirectChat(const QString& userId,
+ const QString& topic = {},
+ const QString& name = {});
+
+ virtual JoinRoomJob* joinRoom(const QString& roomAlias,
+ const QStringList& serverNames = {});
+
+ /** Sends /forget to the server and also deletes room locally.
+ * This method is in Connection, not in Room, since it's a
+ * room lifecycle operation, and Connection is an acting room manager.
+ * It ensures that the local user is not a member of a room (running /leave,
+ * if necessary) then issues a /forget request and if that one doesn't fail
+ * deletion of the local Room object is ensured.
+ * \param id - the room id to forget
+ * \return - the ongoing /forget request to the server; note that the
+ * success() signal of this request is connected to deleteLater()
+ * of a respective room so by the moment this finishes, there might be no
+ * Room object anymore.
+ */
+ ForgetRoomJob* forgetRoom(const QString& id);
+
+ SendToDeviceJob* sendToDevices(const QString& eventType,
+ const UsersToDevicesToEvents& eventsMap) const;
+
+ /** \deprecated This method is experimental and may be removed any time */
+ SendMessageJob* sendMessage(const QString& roomId,
+ const RoomEvent& event) const;
+
+ /** \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) const;
+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
+ * homeserverChanged() instead of resolved(). You can also use
+ * connectToServer and connectWithToken without the HS URL set in
+ * advance (i.e. without calling resolveServer), as they now trigger
+ * server name resolution from MXID if the server URL is not valid.
+ */
+ void resolved();
+ void resolveError(QString error);
+
+ void homeserverChanged(QUrl baseUrl);
+ void capabilitiesLoaded();
+
+ void connected();
+ void reconnected(); //< \deprecated Use connected() instead
+ void loggedOut();
+ /** Login data or state have changed
+ *
+ * This is a common change signal for userId, deviceId and
+ * accessToken - these properties normally only change at
+ * a successful login and logout and are constant at other times.
+ */
+ void stateChanged();
+ void loginError(QString message, QString details);
+
+ /** A network request (job) failed
+ *
+ * @param request - the pointer to the failed job
+ */
+ void requestFailed(BaseJob* request);
+
+ /** A network request (job) failed due to network problems
+ *
+ * This is _only_ emitted when the job will retry on its own;
+ * once it gives up, requestFailed() will be emitted.
+ *
+ * @param message - message about the network problem
+ * @param details - raw error details, if any available
+ * @param retriesTaken - how many retries have already been taken
+ * @param nextRetryInMilliseconds - when the job will retry again
+ */
+ void networkError(QString message, QString details, int retriesTaken,
+ int nextRetryInMilliseconds);
+
+ void syncDone();
+ void syncError(QString message, QString details);
+
+ void newUser(User* user);
+
+ /**
+ * \group Signals emitted on room transitions
+ *
+ * Note: Rooms in Invite state are always stored separately from
+ * rooms in Join/Leave state, because of special treatment of
+ * invite_state in Matrix CS API (see The Spec on /sync for details).
+ * Therefore, objects below are: r - room in Join/Leave state;
+ * i - room in Invite state
+ *
+ * 1. none -> Invite: newRoom(r), invitedRoom(r,nullptr)
+ * 2. none -> Join: newRoom(r), joinedRoom(r,nullptr)
+ * 3. none -> Leave: newRoom(r), leftRoom(r,nullptr)
+ * 4. Invite -> Join:
+ * newRoom(r), joinedRoom(r,i), aboutToDeleteRoom(i)
+ * 4a. Leave and Invite -> Join:
+ * joinedRoom(r,i), aboutToDeleteRoom(i)
+ * 5. Invite -> Leave:
+ * newRoom(r), leftRoom(r,i), aboutToDeleteRoom(i)
+ * 5a. Leave and Invite -> Leave:
+ * leftRoom(r,i), aboutToDeleteRoom(i)
+ * 6. Join -> Leave: leftRoom(r)
+ * 7. Leave -> Invite: newRoom(i), invitedRoom(i,r)
+ * 8. Leave -> Join: joinedRoom(r)
+ * The following transitions are only possible via forgetRoom()
+ * so far; if a room gets forgotten externally, sync won't tell
+ * about it:
+ * 9. any -> none: as any -> Leave, then aboutToDeleteRoom(r)
+ */
+
+ /** A new room object has been created */
+ void newRoom(Room* room);
+
+ /** A room invitation is seen for the first time
+ *
+ * If the same room is in Left state, it's passed in prev. Beware
+ * that initial sync will trigger this signal for all rooms in
+ * Invite state.
+ */
+ void invitedRoom(Room* room, Room* prev);
+
+ /** A joined room is seen for the first time
+ *
+ * It's not the same as receiving a room in "join" section of sync
+ * response (rooms will be there even after joining); it's also
+ * not (exactly) the same as actual joining action of a user (all
+ * rooms coming in initial sync will trigger this signal too). If
+ * this room was in Invite state before, the respective object is
+ * passed in prev (and it will be deleted shortly afterwards).
+ */
+ void joinedRoom(Room* room, Room* prev);
+
+ /** A room has just been left
+ *
+ * If this room has been in Invite state (as in case of rejecting
+ * an invitation), the respective object will be passed in prev
+ * (and will be deleted shortly afterwards). Note that, similar
+ * to invitedRoom and joinedRoom, this signal is triggered for all
+ * Left rooms upon initial sync (not only those that were left
+ * right before the sync).
+ */
+ void leftRoom(Room* room, Room* prev);
+
+ /** The room object is about to be deleted */
+ void aboutToDeleteRoom(Room* room);
+
+ /** The room has just been created by createRoom or requestDirectChat
+ *
+ * This signal is not emitted in usual room state transitions,
+ * only as an outcome of room creation operations invoked by
+ * the client.
+ * \note requestDirectChat doesn't necessarily create a new chat;
+ * use directChatAvailable signal if you just need to obtain
+ * a direct chat room.
+ */
+ void createdRoom(Room* room);
+
+ /** The first sync for the room has been completed
+ *
+ * This signal is emitted after the room has been synced the first
+ * time. This is the right signal to connect to if you need to
+ * access the room state (name, aliases, members); state transition
+ * signals (newRoom, joinedRoom etc.) come earlier, when the room
+ * has just been created.
+ */
+ void loadedRoomState(Room* room);
+
+ /** Account data (except direct chats) have changed */
+ void accountDataChanged(QString type);
+
+ /** The direct chat room is ready for using
+ * This signal is emitted upon any successful outcome from
+ * requestDirectChat.
+ */
+ void directChatAvailable(Room* directChat);
+
+ /** The list of direct chats has changed
+ * This signal is emitted every time when the mapping of users
+ * to direct chat rooms is changed (because of either local updates
+ * or a different list arrived from the server).
+ */
+ void directChatsListChanged(DirectChatsMap additions,
+ DirectChatsMap removals);
+
+ void ignoredUsersListChanged(IgnoredUsersList additions,
+ IgnoredUsersList removals);
+
+ void cacheStateChanged();
+ void lazyLoadingChanged();
+ void turnServersChanged(const QJsonObject& servers);
+
+protected:
+ /**
+ * @brief Access the underlying ConnectionData class
+ */
+ const ConnectionData* connectionData() const;
+
+ /** Get a Room object for the given id in the given state
+ *
+ * Use this method when you need a Room object in the local list
+ * of rooms, with the given state. Note that this does not interact
+ * with the server; in particular, does not automatically create
+ * rooms on the server. This call performs necessary join state
+ * transitions; e.g., if it finds a room in Invite but
+ * `joinState == JoinState::Join` then the Invite room object
+ * will be deleted and a new room object with Join state created.
+ * In contrast, switching between Join and Leave happens within
+ * the same object.
+ * \param roomId room id (not alias!)
+ * \param joinState desired (target) join state of the room; if
+ * omitted, any state will be found and return unchanged, or a
+ * new Join room created.
+ * @return a pointer to a Room object with the specified id and the
+ * specified state; nullptr if roomId is empty or if roomFactory()
+ * failed to create a Room object.
+ */
+ Room* provideRoom(const QString& roomId,
+ Omittable<JoinState> joinState = none);
+
+ /**
+ * Completes loading sync data.
+ */
+ void onSyncSuccess(SyncData&& data, bool fromCache = false);
+
+protected slots:
+ void syncLoopIteration();
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+
+ /**
+ * A single entry for functions that need to check whether the
+ * homeserver is valid before running. May either execute connectFn
+ * synchronously or asynchronously (if tryResolve is true and
+ * a DNS lookup is initiated); in case of errors, emits resolveError
+ * if the homeserver URL is not valid and cannot be resolved from
+ * userId.
+ *
+ * @param userId - fully-qualified MXID to resolve HS from
+ * @param connectFn - a function to execute once the HS URL is good
+ */
+ void checkAndConnect(const QString& userId, std::function<void()> connectFn);
+ void doConnectToServer(const QString& user, const QString& password,
+ const QString& initialDeviceName,
+ const QString& deviceId = {});
+
+ static room_factory_t _roomFactory;
+ static user_factory_t _userFactory;
+};
} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::Connection*)
diff --git a/lib/connectiondata.cpp b/lib/connectiondata.cpp
index 513e497e..c157565f 100644
--- a/lib/connectiondata.cpp
+++ b/lib/connectiondata.cpp
@@ -23,8 +23,11 @@
using namespace QMatrixClient;
-struct ConnectionData::Private {
- explicit Private(const QUrl& url) : baseUrl(url) {}
+struct ConnectionData::Private
+{
+ explicit Private(QUrl url)
+ : baseUrl(std::move(url))
+ {}
QUrl baseUrl;
QByteArray accessToken;
@@ -36,9 +39,8 @@ struct ConnectionData::Private {
};
ConnectionData::ConnectionData(QUrl baseUrl)
- : d(std::make_unique<Private>(baseUrl))
-{
-}
+ : d(std::make_unique<Private>(std::move(baseUrl)))
+{}
ConnectionData::~ConnectionData() = default;
@@ -86,11 +88,10 @@ QString ConnectionData::lastEvent() const { return d->lastEvent; }
void ConnectionData::setLastEvent(QString identifier)
{
- d->lastEvent = identifier;
+ d->lastEvent = std::move(identifier);
}
QByteArray ConnectionData::generateTxnId() const
{
- return QByteArray::number(d->id) + 'q'
- + QByteArray::number(++d->txnCounter);
+ return QByteArray::number(d->id) + 'q' + QByteArray::number(++d->txnCounter);
}
diff --git a/lib/connectiondata.h b/lib/connectiondata.h
index fcb67e2d..6f9f090c 100644
--- a/lib/connectiondata.h
+++ b/lib/connectiondata.h
@@ -24,31 +24,32 @@
class QNetworkAccessManager;
-namespace QMatrixClient {
- class ConnectionData
- {
- public:
- explicit ConnectionData(QUrl baseUrl);
- virtual ~ConnectionData();
-
- QByteArray accessToken() const;
- QUrl baseUrl() const;
- const QString& deviceId() const;
-
- QNetworkAccessManager* nam() const;
- void setBaseUrl(QUrl baseUrl);
- void setToken(QByteArray accessToken);
- void setHost(QString host);
- void setPort(int port);
- void setDeviceId(const QString& deviceId);
-
- QString lastEvent() const;
- void setLastEvent(QString identifier);
-
- QByteArray generateTxnId() const;
-
- private:
- struct Private;
- std::unique_ptr<Private> d;
- };
+namespace QMatrixClient
+{
+class ConnectionData
+{
+public:
+ explicit ConnectionData(QUrl baseUrl);
+ virtual ~ConnectionData();
+
+ QByteArray accessToken() const;
+ QUrl baseUrl() const;
+ const QString& deviceId() const;
+
+ QNetworkAccessManager* nam() const;
+ void setBaseUrl(QUrl baseUrl);
+ void setToken(QByteArray accessToken);
+ void setHost(QString host);
+ void setPort(int port);
+ void setDeviceId(const QString& deviceId);
+
+ QString lastEvent() const;
+ void setLastEvent(QString identifier);
+
+ QByteArray generateTxnId() const;
+
+private:
+ struct Private;
+ std::unique_ptr<Private> d;
+};
} // namespace QMatrixClient
diff --git a/lib/converters.cpp b/lib/converters.cpp
index 8f45ba3b..ef58c85e 100644
--- a/lib/converters.cpp
+++ b/lib/converters.cpp
@@ -36,20 +36,20 @@ QJsonObject JsonConverter<variant_map_t>::dump(const variant_map_t& map)
{
return
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
- QJsonObject::fromVariantHash
+ QJsonObject::fromVariantHash
#else
- QJsonObject::fromVariantMap
+ QJsonObject::fromVariantMap
#endif
- (map);
+ (map);
}
variant_map_t JsonConverter<QVariantHash>::load(const QJsonValue& jv)
{
return jv.toObject().
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
- toVariantHash
+ toVariantHash
#else
- toVariantMap
+ toVariantMap
#endif
- ();
+ ();
}
diff --git a/lib/converters.h b/lib/converters.h
index 68a841cf..3ba65c22 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -31,343 +31,385 @@
#include <unordered_map>
#include <vector>
#if 0 // Waiting for C++17
-#include <experimental/optional>
+# include <experimental/optional>
template <typename T>
using optional = std::experimental::optional<T>;
#endif
// Enable std::unordered_map<QString, T>
-namespace std {
- template <> struct hash<QString> {
- size_t operator()(const QString& s) const Q_DECL_NOEXCEPT
- {
- return qHash(s
+namespace std
+{
+template <>
+struct hash<QString>
+{
+ size_t operator()(const QString& s) const Q_DECL_NOEXCEPT
+ {
+ return qHash(s
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- ,
- uint(qGlobalQHashSeed())
+ ,
+ uint(qGlobalQHashSeed())
#endif
- );
- }
- };
-}
+ );
+ }
+};
+} // namespace std
class QVariant;
-namespace QMatrixClient {
- template <typename T> struct JsonObjectConverter {
- static void dumpTo(QJsonObject& jo, const T& pod) { jo = pod; }
- static void fillFrom(const QJsonObject& jo, T& pod) { pod = jo; }
- };
-
- template <typename T> struct JsonConverter {
- static QJsonObject dump(const T& pod)
- {
- QJsonObject jo;
- JsonObjectConverter<T>::dumpTo(jo, pod);
- return jo;
- }
- static T doLoad(const QJsonObject& jo)
- {
- T pod;
- JsonObjectConverter<T>::fillFrom(jo, pod);
- return pod;
- }
- static T load(const QJsonValue& jv) { return doLoad(jv.toObject()); }
- static T load(const QJsonDocument& jd) { return doLoad(jd.object()); }
- };
+namespace QMatrixClient
+{
+template <typename T>
+struct JsonObjectConverter
+{
+ static void dumpTo(QJsonObject& jo, const T& pod) { jo = pod; }
+ static void fillFrom(const QJsonObject& jo, T& pod) { pod = jo; }
+};
- template <typename T> inline auto toJson(const T& pod)
+template <typename T>
+struct JsonConverter
+{
+ static QJsonObject dump(const T& pod)
{
- return JsonConverter<T>::dump(pod);
+ QJsonObject jo;
+ JsonObjectConverter<T>::dumpTo(jo, pod);
+ return jo;
}
-
- template <typename T> inline auto fillJson(QJsonObject& json, const T& data)
+ static T doLoad(const QJsonObject& jo)
{
- JsonObjectConverter<T>::dumpTo(json, data);
+ T pod;
+ JsonObjectConverter<T>::fillFrom(jo, pod);
+ return pod;
}
+ static T load(const QJsonValue& jv) { return doLoad(jv.toObject()); }
+ static T load(const QJsonDocument& jd) { return doLoad(jd.object()); }
+};
+
+template <typename T>
+inline auto toJson(const T& pod)
+{
+ return JsonConverter<T>::dump(pod);
+}
+
+template <typename T>
+inline auto fillJson(QJsonObject& json, const T& data)
+{
+ JsonObjectConverter<T>::dumpTo(json, data);
+}
+
+template <typename T>
+inline auto fromJson(const QJsonValue& jv)
+{
+ return JsonConverter<T>::load(jv);
+}
+
+template <typename T>
+inline T fromJson(const QJsonDocument& jd)
+{
+ return JsonConverter<T>::load(jd);
+}
+
+template <typename T>
+inline void fromJson(const QJsonValue& jv, T& pod)
+{
+ if (!jv.isUndefined())
+ pod = fromJson<T>(jv);
+}
+
+template <typename T>
+inline void fromJson(const QJsonDocument& jd, T& pod)
+{
+ pod = fromJson<T>(jd);
+}
+
+// Unfolds Omittable<>
+template <typename T>
+inline void fromJson(const QJsonValue& jv, Omittable<T>& pod)
+{
+ if (jv.isUndefined())
+ pod = none;
+ else
+ pod = fromJson<T>(jv);
+}
+
+template <typename T>
+inline void fillFromJson(const QJsonValue& jv, T& pod)
+{
+ if (jv.isObject())
+ JsonObjectConverter<T>::fillFrom(jv.toObject(), pod);
+}
- template <typename T> inline auto fromJson(const QJsonValue& jv)
+// JsonConverter<> specialisations
+
+template <typename T>
+struct TrivialJsonDumper
+{
+ // Works for: QJsonValue (and all things it can consume),
+ // QJsonObject, QJsonArray
+ static auto dump(const T& val) { return val; }
+};
+
+template <>
+struct JsonConverter<bool> : public TrivialJsonDumper<bool>
+{
+ static auto load(const QJsonValue& jv) { return jv.toBool(); }
+};
+
+template <>
+struct JsonConverter<int> : public TrivialJsonDumper<int>
+{
+ static auto load(const QJsonValue& jv) { return jv.toInt(); }
+};
+
+template <>
+struct JsonConverter<double> : public TrivialJsonDumper<double>
+{
+ static auto load(const QJsonValue& jv) { return jv.toDouble(); }
+};
+
+template <>
+struct JsonConverter<float> : public TrivialJsonDumper<float>
+{
+ static auto load(const QJsonValue& jv) { return float(jv.toDouble()); }
+};
+
+template <>
+struct JsonConverter<qint64> : public TrivialJsonDumper<qint64>
+{
+ static auto load(const QJsonValue& jv) { return qint64(jv.toDouble()); }
+};
+
+template <>
+struct JsonConverter<QString> : public TrivialJsonDumper<QString>
+{
+ static auto load(const QJsonValue& jv) { return jv.toString(); }
+};
+
+template <>
+struct JsonConverter<QDateTime>
+{
+ static auto dump(const QDateTime& val) = delete; // not provided yet
+ static auto load(const QJsonValue& jv)
{
- return JsonConverter<T>::load(jv);
+ return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv), Qt::UTC);
}
+};
- template <typename T> inline T fromJson(const QJsonDocument& jd)
+template <>
+struct JsonConverter<QDate>
+{
+ static auto dump(const QDate& val) = delete; // not provided yet
+ static auto load(const QJsonValue& jv)
{
- return JsonConverter<T>::load(jd);
+ return fromJson<QDateTime>(jv).date();
}
-
- template <typename T> inline void fromJson(const QJsonValue& jv, T& pod)
+};
+
+template <>
+struct JsonConverter<QJsonArray> : public TrivialJsonDumper<QJsonArray>
+{
+ static auto load(const QJsonValue& jv) { return jv.toArray(); }
+};
+
+template <>
+struct JsonConverter<QByteArray>
+{
+ static QString dump(const QByteArray& ba) { return ba.constData(); }
+ static auto load(const QJsonValue& jv)
{
- if (!jv.isUndefined())
- pod = fromJson<T>(jv);
+ return fromJson<QString>(jv).toLatin1();
}
-
- template <typename T> inline void fromJson(const QJsonDocument& jd, T& pod)
+};
+
+template <>
+struct JsonConverter<QVariant>
+{
+ static QJsonValue dump(const QVariant& v);
+ static QVariant load(const QJsonValue& jv);
+};
+
+template <typename VectorT, typename T = typename VectorT::value_type>
+struct JsonArrayConverter
+{
+ static void dumpTo(QJsonArray& ar, const VectorT& vals)
{
- pod = fromJson<T>(jd);
+ for (const auto& v : vals)
+ ar.push_back(toJson(v));
}
-
- // Unfolds Omittable<>
- template <typename T>
- inline void fromJson(const QJsonValue& jv, Omittable<T>& pod)
+ static auto dump(const VectorT& vals)
{
- if (jv.isUndefined())
- pod = none;
- else
- pod = fromJson<T>(jv);
+ QJsonArray ja;
+ dumpTo(ja, vals);
+ return ja;
}
-
- template <typename T> inline void fillFromJson(const QJsonValue& jv, T& pod)
+ static auto load(const QJsonArray& ja)
{
- if (jv.isObject())
- JsonObjectConverter<T>::fillFrom(jv.toObject(), pod);
+ VectorT vect;
+ vect.reserve(typename VectorT::size_type(ja.size()));
+ for (const auto& i : ja)
+ vect.push_back(fromJson<T>(i));
+ return vect;
}
+ static auto load(const QJsonValue& jv) { return load(jv.toArray()); }
+ static auto load(const QJsonDocument& jd) { return load(jd.array()); }
+};
- // JsonConverter<> specialisations
-
- template <typename T> struct TrivialJsonDumper {
- // Works for: QJsonValue (and all things it can consume),
- // QJsonObject, QJsonArray
- static auto dump(const T& val) { return val; }
- };
-
- template <> struct JsonConverter<bool> : public TrivialJsonDumper<bool> {
- static auto load(const QJsonValue& jv) { return jv.toBool(); }
- };
-
- template <> struct JsonConverter<int> : public TrivialJsonDumper<int> {
- static auto load(const QJsonValue& jv) { return jv.toInt(); }
- };
-
- template <>
- struct JsonConverter<double> : public TrivialJsonDumper<double> {
- static auto load(const QJsonValue& jv) { return jv.toDouble(); }
- };
-
- template <> struct JsonConverter<float> : public TrivialJsonDumper<float> {
- static auto load(const QJsonValue& jv) { return float(jv.toDouble()); }
- };
+template <typename T>
+struct JsonConverter<std::vector<T>> : public JsonArrayConverter<std::vector<T>>
+{};
- template <>
- struct JsonConverter<qint64> : public TrivialJsonDumper<qint64> {
- static auto load(const QJsonValue& jv) { return qint64(jv.toDouble()); }
- };
+template <typename T>
+struct JsonConverter<QVector<T>> : public JsonArrayConverter<QVector<T>>
+{};
- template <>
- struct JsonConverter<QString> : public TrivialJsonDumper<QString> {
- static auto load(const QJsonValue& jv) { return jv.toString(); }
- };
+template <typename T>
+struct JsonConverter<QList<T>> : public JsonArrayConverter<QList<T>>
+{};
- template <> struct JsonConverter<QDateTime> {
- static auto dump(const QDateTime& val) = delete; // not provided yet
- static auto load(const QJsonValue& jv)
- {
- return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv),
- Qt::UTC);
- }
- };
+template <>
+struct JsonConverter<QStringList> : public JsonConverter<QList<QString>>
+{
+ static auto dump(const QStringList& sl)
+ {
+ return QJsonArray::fromStringList(sl);
+ }
+};
- template <> struct JsonConverter<QDate> {
- static auto dump(const QDate& val) = delete; // not provided yet
- static auto load(const QJsonValue& jv)
- {
- return fromJson<QDateTime>(jv).date();
- }
- };
+template <>
+struct JsonObjectConverter<QSet<QString>>
+{
+ static void dumpTo(QJsonObject& json, const QSet<QString>& s)
+ {
+ for (const auto& e : s)
+ json.insert(toJson(e), QJsonObject {});
+ }
+ static auto fillFrom(const QJsonObject& json, QSet<QString>& s)
+ {
+ s.reserve(s.size() + json.size());
+ for (auto it = json.begin(); it != json.end(); ++it)
+ s.insert(it.key());
+ return s;
+ }
+};
- template <>
- struct JsonConverter<QJsonArray> : public TrivialJsonDumper<QJsonArray> {
- static auto load(const QJsonValue& jv) { return jv.toArray(); }
- };
+template <typename HashMapT>
+struct HashMapFromJson
+{
+ static void dumpTo(QJsonObject& json, const HashMapT& hashMap)
+ {
+ for (auto it = hashMap.begin(); it != hashMap.end(); ++it)
+ json.insert(it.key(), toJson(it.value()));
+ }
+ static void fillFrom(const QJsonObject& jo, HashMapT& h)
+ {
+ h.reserve(jo.size());
+ for (auto it = jo.begin(); it != jo.end(); ++it)
+ h[it.key()] = fromJson<typename HashMapT::mapped_type>(it.value());
+ }
+};
- 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 <typename T>
+struct JsonObjectConverter<std::unordered_map<QString, T>>
+ : public HashMapFromJson<std::unordered_map<QString, T>>
+{};
- template <> struct JsonConverter<QVariant> {
- static QJsonValue dump(const QVariant& v);
- static QVariant load(const QJsonValue& jv);
- };
+template <typename T>
+struct JsonObjectConverter<QHash<QString, T>>
+ : public HashMapFromJson<QHash<QString, T>>
+{};
+
+// We could use std::conditional<> below but QT_VERSION* macros in C++ code
+// cause (kinda valid but useless and noisy) compiler warnings about
+// bitwise operations on signed integers; so use the preprocessor for now.
+using variant_map_t =
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
+ QVariantHash;
+#else
+ QVariantMap;
+#endif
+template <>
+struct JsonConverter<variant_map_t>
+{
+ static QJsonObject dump(const variant_map_t& vh);
+ static QVariantHash load(const QJsonValue& jv);
+};
+
+// Conditional insertion into a QJsonObject
+
+namespace _impl
+{
+ template <typename ValT>
+ inline void addTo(QJsonObject& o, const QString& k, ValT&& v)
+ {
+ o.insert(k, toJson(v));
+ }
- template <typename VectorT, typename T = typename VectorT::value_type>
- struct JsonArrayConverter {
- static void dumpTo(QJsonArray& ar, const VectorT& vals)
- {
- for (const auto& v : vals)
- ar.push_back(toJson(v));
- }
- static auto dump(const VectorT& vals)
- {
- QJsonArray ja;
- dumpTo(ja, vals);
- return ja;
- }
- static auto load(const QJsonArray& ja)
- {
- VectorT vect;
- vect.reserve(typename VectorT::size_type(ja.size()));
- for (const auto& i : ja)
- vect.push_back(fromJson<T>(i));
- return vect;
- }
- static auto load(const QJsonValue& jv) { return load(jv.toArray()); }
- static auto load(const QJsonDocument& jd) { return load(jd.array()); }
- };
+ template <typename ValT>
+ inline void addTo(QUrlQuery& q, const QString& k, ValT&& v)
+ {
+ q.addQueryItem(k, QStringLiteral("%1").arg(v));
+ }
- template <typename T>
- struct JsonConverter<std::vector<T>>
- : public JsonArrayConverter<std::vector<T>> {
- };
+ // OpenAPI is entirely JSON-based, which means representing bools as
+ // textual true/false, rather than 1/0.
+ inline void addTo(QUrlQuery& q, const QString& k, bool v)
+ {
+ q.addQueryItem(k, v ? QStringLiteral("true") : QStringLiteral("false"));
+ }
- template <typename T>
- struct JsonConverter<QVector<T>> : public JsonArrayConverter<QVector<T>> {
- };
+ inline void addTo(QUrlQuery& q, const QString& k, const QStringList& vals)
+ {
+ for (const auto& v : vals)
+ q.addQueryItem(k, v);
+ }
- template <typename T>
- struct JsonConverter<QList<T>> : public JsonArrayConverter<QList<T>> {
- };
+ inline void addTo(QUrlQuery& q, const QString&, const QJsonObject& vals)
+ {
+ for (auto it = vals.begin(); it != vals.end(); ++it)
+ q.addQueryItem(it.key(), it.value().toString());
+ }
- template <>
- struct JsonConverter<QStringList> : public JsonConverter<QList<QString>> {
- static auto dump(const QStringList& sl)
+ // This one is for types that don't have isEmpty()
+ template <typename ValT, bool Force = true, typename = bool>
+ struct AddNode
+ {
+ template <typename ContT, typename ForwardedT>
+ static void impl(ContT& container, const QString& key,
+ ForwardedT&& value)
{
- return QJsonArray::fromStringList(sl);
+ addTo(container, key, std::forward<ForwardedT>(value));
}
};
- template <> struct JsonObjectConverter<QSet<QString>> {
- static void dumpTo(QJsonObject& json, const QSet<QString>& s)
- {
- for (const auto& e : s)
- json.insert(toJson(e), QJsonObject {});
- }
- static auto fillFrom(const QJsonObject& json, QSet<QString>& s)
+ // This one is for types that have isEmpty()
+ template <typename ValT>
+ struct AddNode<ValT, false, decltype(std::declval<ValT>().isEmpty())>
+ {
+ template <typename ContT, typename ForwardedT>
+ static void impl(ContT& container, const QString& key,
+ ForwardedT&& value)
{
- s.reserve(s.size() + json.size());
- for (auto it = json.begin(); it != json.end(); ++it)
- s.insert(it.key());
- return s;
+ if (!value.isEmpty())
+ AddNode<ValT>::impl(container, key,
+ std::forward<ForwardedT>(value));
}
};
- template <typename HashMapT> struct HashMapFromJson {
- static void dumpTo(QJsonObject& json, const HashMapT& hashMap)
- {
- for (auto it = hashMap.begin(); it != hashMap.end(); ++it)
- json.insert(it.key(), toJson(it.value()));
- }
- static void fillFrom(const QJsonObject& jo, HashMapT& h)
+ // This is a special one that unfolds Omittable<>
+ template <typename ValT, bool Force>
+ struct AddNode<Omittable<ValT>, Force>
+ {
+ template <typename ContT, typename OmittableT>
+ static void impl(ContT& container, const QString& key,
+ const OmittableT& value)
{
- h.reserve(jo.size());
- for (auto it = jo.begin(); it != jo.end(); ++it)
- h[it.key()] =
- fromJson<typename HashMapT::mapped_type>(it.value());
+ if (!value.omitted())
+ AddNode<ValT>::impl(container, key, value.value());
+ else if (Force) // Edge case, no value but must put something
+ AddNode<ValT>::impl(container, key, QString {});
}
};
- template <typename T>
- struct JsonObjectConverter<std::unordered_map<QString, T>>
- : public HashMapFromJson<std::unordered_map<QString, T>> {
- };
-
- template <typename T>
- struct JsonObjectConverter<QHash<QString, T>>
- : public HashMapFromJson<QHash<QString, T>> {
- };
-
- // We could use std::conditional<> below but QT_VERSION* macros in C++ code
- // cause (kinda valid but useless and noisy) compiler warnings about
- // bitwise operations on signed integers; so use the preprocessor for now.
- using variant_map_t =
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
- QVariantHash;
-#else
- QVariantMap;
-#endif
- template <> struct JsonConverter<variant_map_t> {
- static QJsonObject dump(const variant_map_t& vh);
- static QVariantHash load(const QJsonValue& jv);
- };
-
- // Conditional insertion into a QJsonObject
-
- namespace _impl {
- template <typename ValT>
- inline void addTo(QJsonObject& o, const QString& k, ValT&& v)
- {
- o.insert(k, toJson(v));
- }
-
- template <typename ValT>
- inline void addTo(QUrlQuery& q, const QString& k, ValT&& v)
- {
- q.addQueryItem(k, QStringLiteral("%1").arg(v));
- }
-
- // OpenAPI is entirely JSON-based, which means representing bools as
- // textual true/false, rather than 1/0.
- inline void addTo(QUrlQuery& q, const QString& k, bool v)
- {
- q.addQueryItem(
- k, v ? QStringLiteral("true") : QStringLiteral("false"));
- }
-
- inline void addTo(QUrlQuery& q, const QString& k,
- const QStringList& vals)
- {
- for (const auto& v : vals)
- q.addQueryItem(k, v);
- }
-
- inline void addTo(QUrlQuery& q, const QString&, const QJsonObject& vals)
- {
- for (auto it = vals.begin(); it != vals.end(); ++it)
- q.addQueryItem(it.key(), it.value().toString());
- }
-
- // This one is for types that don't have isEmpty()
- template <typename ValT, bool Force = true, typename = bool>
- struct AddNode {
- template <typename ContT, typename ForwardedT>
- static void impl(ContT& container, const QString& key,
- ForwardedT&& value)
- {
- addTo(container, key, std::forward<ForwardedT>(value));
- }
- };
-
- // This one is for types that have isEmpty()
- template <typename ValT>
- struct AddNode<ValT, false, decltype(std::declval<ValT>().isEmpty())> {
- template <typename ContT, typename ForwardedT>
- static void impl(ContT& container, const QString& key,
- ForwardedT&& value)
- {
- if (!value.isEmpty())
- AddNode<ValT>::impl(container, key,
- std::forward<ForwardedT>(value));
- }
- };
-
- // This is a special one that unfolds Omittable<>
- template <typename ValT, bool Force>
- struct AddNode<Omittable<ValT>, Force> {
- template <typename ContT, typename OmittableT>
- static void impl(ContT& container, const QString& key,
- const OmittableT& value)
- {
- if (!value.omitted())
- AddNode<ValT>::impl(container, key, value.value());
- else if (Force) // Edge case, no value but must put something
- AddNode<ValT>::impl(container, key, QString {});
- }
- };
-
#if 0
// This is a special one that unfolds optional<>
template <typename ValT, bool Force>
@@ -385,14 +427,14 @@ namespace QMatrixClient {
};
#endif
- } // namespace _impl
+} // namespace _impl
- static constexpr bool IfNotEmpty = false;
+static constexpr bool IfNotEmpty = false;
- template <bool Force = true, typename ContT, typename ValT>
- inline void addParam(ContT& container, const QString& key, ValT&& value)
- {
- _impl::AddNode<std::decay_t<ValT>, Force>::impl(
- container, key, std::forward<ValT>(value));
- }
+template <bool Force = true, typename ContT, typename ValT>
+inline void addParam(ContT& container, const QString& key, ValT&& value)
+{
+ _impl::AddNode<std::decay_t<ValT>, Force>::impl(container, key,
+ std::forward<ValT>(value));
+}
} // namespace QMatrixClient
diff --git a/lib/csapi/account-data.cpp b/lib/csapi/account-data.cpp
index 40388673..7d4f1ad7 100644
--- a/lib/csapi/account-data.cpp
+++ b/lib/csapi/account-data.cpp
@@ -22,8 +22,23 @@ SetAccountDataJob::SetAccountDataJob(const QString& userId, const QString& type,
setRequestData(Data(toJson(content)));
}
+QUrl GetAccountDataJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
+ const QString& type)
+{
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ basePath % "/user/" % userId
+ % "/account_data/" % type);
+}
+
+static const auto GetAccountDataJobName = QStringLiteral("GetAccountDataJob");
+
+GetAccountDataJob::GetAccountDataJob(const QString& userId, const QString& type)
+ : BaseJob(HttpVerb::Get, GetAccountDataJobName,
+ basePath % "/user/" % userId % "/account_data/" % type)
+{}
+
static const auto SetAccountDataPerRoomJobName =
- QStringLiteral("SetAccountDataPerRoomJob");
+ QStringLiteral("SetAccountDataPerRoomJob");
SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId,
const QString& roomId,
@@ -31,7 +46,28 @@ SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId,
const QJsonObject& content)
: BaseJob(HttpVerb::Put, SetAccountDataPerRoomJobName,
basePath % "/user/" % userId % "/rooms/" % roomId
- % "/account_data/" % type)
+ % "/account_data/" % type)
{
setRequestData(Data(toJson(content)));
}
+
+QUrl GetAccountDataPerRoomJob::makeRequestUrl(QUrl baseUrl,
+ const QString& userId,
+ const QString& roomId,
+ const QString& type)
+{
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ basePath % "/user/" % userId % "/rooms/"
+ % roomId % "/account_data/" % type);
+}
+
+static const auto GetAccountDataPerRoomJobName =
+ QStringLiteral("GetAccountDataPerRoomJob");
+
+GetAccountDataPerRoomJob::GetAccountDataPerRoomJob(const QString& userId,
+ const QString& roomId,
+ const QString& type)
+ : BaseJob(HttpVerb::Get, GetAccountDataPerRoomJobName,
+ basePath % "/user/" % userId % "/rooms/" % roomId
+ % "/account_data/" % type)
+{}
diff --git a/lib/csapi/account-data.h b/lib/csapi/account-data.h
index 669a4e2c..75bb9ce3 100644
--- a/lib/csapi/account-data.h
+++ b/lib/csapi/account-data.h
@@ -8,49 +8,118 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
-
- /// Set some account_data for the user.
- ///
- /// Set some account_data for the client. This config is only visible to the
- /// user that set the account_data. The config will be synced to clients in
- /// the top-level ``account_data``.
- class SetAccountDataJob : public BaseJob
- {
- public:
- /*! Set some account_data for the user.
- * \param userId
- * The id of the user to set account_data for. The access token must
- * be authorized to make requests for this user id. \param type The
- * event type of the account_data to set. Custom types should be
- * namespaced to avoid clashes.
- * \param content
- * The content of the account_data
- */
- explicit SetAccountDataJob(const QString& userId, const QString& type,
- const QJsonObject& content = {});
- };
-
- /// Set some account_data for the user.
- ///
- /// Set some account_data for the client on a given room. This config is
- /// only visible to the user that set the account_data. The config will be
- /// synced to clients in the per-room ``account_data``.
- class SetAccountDataPerRoomJob : public BaseJob
- {
- public:
- /*! Set some account_data for the user.
- * \param userId
- * The id of the user to set account_data for. The access token must
- * be authorized to make requests for this user id. \param roomId The id
- * of the room to set account_data on. \param type The event type of the
- * account_data to set. Custom types should be namespaced to avoid
- * clashes. \param content The content of the account_data
- */
- explicit SetAccountDataPerRoomJob(const QString& userId,
- const QString& roomId,
- const QString& type,
- const QJsonObject& content = {});
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Set some account_data for the user.
+/*!
+ * Set some account_data for the client. This config is only visible to the user
+ * that set the account_data. The config will be synced to clients in the
+ * top-level ``account_data``.
+ */
+class SetAccountDataJob : public BaseJob
+{
+public:
+ /*! Set some account_data for the user.
+ * \param userId
+ * The ID of the user to set account_data for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param type
+ * The event type of the account_data to set. Custom types should be
+ * namespaced to avoid clashes.
+ * \param content
+ * The content of the account_data
+ */
+ explicit SetAccountDataJob(const QString& userId, const QString& type,
+ const QJsonObject& content = {});
+};
+
+/// Get some account_data for the user.
+/*!
+ * Get some account_data for the client. This config is only visible to the user
+ * that set the account_data.
+ */
+class GetAccountDataJob : public BaseJob
+{
+public:
+ /*! Get some account_data for the user.
+ * \param userId
+ * The ID of the user to get account_data for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param type
+ * The event type of the account_data to get. Custom types should be
+ * namespaced to avoid clashes.
+ */
+ explicit GetAccountDataJob(const QString& userId, const QString& type);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetAccountDataJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
+ const QString& type);
+};
+
+/// Set some account_data for the user.
+/*!
+ * Set some account_data for the client on a given room. This config is only
+ * visible to the user that set the account_data. The config will be synced to
+ * clients in the per-room ``account_data``.
+ */
+class SetAccountDataPerRoomJob : public BaseJob
+{
+public:
+ /*! Set some account_data for the user.
+ * \param userId
+ * The ID of the user to set account_data for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param roomId
+ * The ID of the room to set account_data on.
+ * \param type
+ * The event type of the account_data to set. Custom types should be
+ * namespaced to avoid clashes.
+ * \param content
+ * The content of the account_data
+ */
+ explicit SetAccountDataPerRoomJob(const QString& userId,
+ const QString& roomId, const QString& type,
+ const QJsonObject& content = {});
+};
+
+/// Get some account_data for the user.
+/*!
+ * Get some account_data for the client on a given room. This config is only
+ * visible to the user that set the account_data.
+ */
+class GetAccountDataPerRoomJob : public BaseJob
+{
+public:
+ /*! Get some account_data for the user.
+ * \param userId
+ * The ID of the user to set account_data for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param roomId
+ * The ID of the room to get account_data for.
+ * \param type
+ * The event type of the account_data to get. Custom types should be
+ * namespaced to avoid clashes.
+ */
+ explicit GetAccountDataPerRoomJob(const QString& userId,
+ const QString& roomId,
+ const QString& type);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetAccountDataPerRoomJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
+ const QString& roomId, const QString& type);
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/admin.cpp b/lib/csapi/admin.cpp
index 7922ffe3..58334118 100644
--- a/lib/csapi/admin.cpp
+++ b/lib/csapi/admin.cpp
@@ -12,39 +12,45 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<GetWhoIsJob::ConnectionInfo> {
- static void fillFrom(const QJsonObject& jo,
- GetWhoIsJob::ConnectionInfo& result)
- {
- fromJson(jo.value("ip"_ls), result.ip);
- fromJson(jo.value("last_seen"_ls), result.lastSeen);
- fromJson(jo.value("user_agent"_ls), result.userAgent);
- }
- };
-
- template <> struct JsonObjectConverter<GetWhoIsJob::SessionInfo> {
- static void fillFrom(const QJsonObject& jo,
- GetWhoIsJob::SessionInfo& result)
- {
- fromJson(jo.value("connections"_ls), result.connections);
- }
- };
-
- template <> struct JsonObjectConverter<GetWhoIsJob::DeviceInfo> {
- static void fillFrom(const QJsonObject& jo,
- GetWhoIsJob::DeviceInfo& result)
- {
- fromJson(jo.value("sessions"_ls), result.sessions);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetWhoIsJob::ConnectionInfo>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetWhoIsJob::ConnectionInfo& result)
+ {
+ fromJson(jo.value("ip"_ls), result.ip);
+ fromJson(jo.value("last_seen"_ls), result.lastSeen);
+ fromJson(jo.value("user_agent"_ls), result.userAgent);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetWhoIsJob::SessionInfo>
+{
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::SessionInfo& result)
+ {
+ fromJson(jo.value("connections"_ls), result.connections);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetWhoIsJob::DeviceInfo>
+{
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::DeviceInfo& result)
+ {
+ fromJson(jo.value("sessions"_ls), result.sessions);
+ }
+};
+
} // namespace QMatrixClient
class GetWhoIsJob::Private
{
- public:
+public:
QString userId;
QHash<QString, DeviceInfo> devices;
};
@@ -59,10 +65,9 @@ static const auto GetWhoIsJobName = QStringLiteral("GetWhoIsJob");
GetWhoIsJob::GetWhoIsJob(const QString& userId)
: BaseJob(HttpVerb::Get, GetWhoIsJobName,
- basePath % "/admin/whois/" % userId),
- d(new Private)
-{
-}
+ basePath % "/admin/whois/" % userId)
+ , d(new Private)
+{}
GetWhoIsJob::~GetWhoIsJob() = default;
@@ -78,5 +83,6 @@ BaseJob::Status GetWhoIsJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("user_id"_ls), d->userId);
fromJson(json.value("devices"_ls), d->devices);
+
return Success;
}
diff --git a/lib/csapi/admin.h b/lib/csapi/admin.h
index 3c21e2cb..bc27c025 100644
--- a/lib/csapi/admin.h
+++ b/lib/csapi/admin.h
@@ -4,92 +4,94 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QHash>
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
-
- /// Gets information about a particular user.
- ///
- /// Gets information about a particular user.
- ///
- /// This API may be restricted to only be called by the user being looked
- /// up, or by a server admin. Server-local administrator privileges are not
- /// specified in this document.
- class GetWhoIsJob : public BaseJob
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets information about a particular user.
+/*!
+ * Gets information about a particular user.
+ *
+ * This API may be restricted to only be called by the user being looked
+ * up, or by a server admin. Server-local administrator privileges are not
+ * specified in this document.
+ */
+class GetWhoIsJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// Gets information about a particular user.This API may be restricted to
+ /// only be called by the user being lookedup, or by a server admin.
+ /// Server-local administrator privileges are notspecified in this document.
+ struct ConnectionInfo
{
- public:
- // Inner data structures
-
- /// Gets information about a particular user.
- ///
- /// This API may be restricted to only be called by the user being
- /// looked up, or by a server admin. Server-local administrator
- /// privileges are not specified in this document.
- struct ConnectionInfo {
- /// Most recently seen IP address of the session.
- QString ip;
- /// Unix timestamp that the session was last active.
- Omittable<qint64> lastSeen;
- /// User agent string last seen in the session.
- QString userAgent;
- };
-
- /// Gets information about a particular user.
- ///
- /// This API may be restricted to only be called by the user being
- /// looked up, or by a server admin. Server-local administrator
- /// privileges are not specified in this document.
- struct SessionInfo {
- /// Information particular connections in the session.
- QVector<ConnectionInfo> connections;
- };
-
- /// Gets information about a particular user.
- ///
- /// This API may be restricted to only be called by the user being
- /// looked up, or by a server admin. Server-local administrator
- /// privileges are not specified in this document.
- struct DeviceInfo {
- /// A user's sessions (i.e. what they did with an access token from
- /// one login).
- QVector<SessionInfo> sessions;
- };
-
- // Construction/destruction
-
- /*! Gets information about a particular user.
- * \param userId
- * The user to look up.
- */
- explicit GetWhoIsJob(const QString& userId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetWhoIsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
-
- ~GetWhoIsJob() override;
-
- // Result properties
-
- /// The Matrix user ID of the user.
- const QString& userId() const;
- /// Each key is an identitfier for one of the user's devices.
- const QHash<QString, DeviceInfo>& devices() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// Most recently seen IP address of the session.
+ QString ip;
+ /// Unix timestamp that the session was last active.
+ Omittable<qint64> lastSeen;
+ /// User agent string last seen in the session.
+ QString userAgent;
};
+
+ /// Gets information about a particular user.This API may be restricted to
+ /// only be called by the user being lookedup, or by a server admin.
+ /// Server-local administrator privileges are notspecified in this document.
+ struct SessionInfo
+ {
+ /// Information particular connections in the session.
+ QVector<ConnectionInfo> connections;
+ };
+
+ /// Gets information about a particular user.This API may be restricted to
+ /// only be called by the user being lookedup, or by a server admin.
+ /// Server-local administrator privileges are notspecified in this document.
+ struct DeviceInfo
+ {
+ /// A user's sessions (i.e. what they did with an access token from one
+ /// login).
+ QVector<SessionInfo> sessions;
+ };
+
+ // Construction/destruction
+
+ /*! Gets information about a particular user.
+ * \param userId
+ * The user to look up.
+ */
+ explicit GetWhoIsJob(const QString& userId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetWhoIsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
+
+ ~GetWhoIsJob() override;
+
+ // Result properties
+
+ /// The Matrix user ID of the user.
+ const QString& userId() const;
+ /// Each key is an identitfier for one of the user's devices.
+ const QHash<QString, DeviceInfo>& devices() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/administrative_contact.cpp b/lib/csapi/administrative_contact.cpp
index f64f2723..067fb68a 100644
--- a/lib/csapi/administrative_contact.cpp
+++ b/lib/csapi/administrative_contact.cpp
@@ -12,25 +12,28 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <>
- struct JsonObjectConverter<GetAccount3PIDsJob::ThirdPartyIdentifier> {
- static void fillFrom(const QJsonObject& jo,
- GetAccount3PIDsJob::ThirdPartyIdentifier& result)
- {
- fromJson(jo.value("medium"_ls), result.medium);
- fromJson(jo.value("address"_ls), result.address);
- fromJson(jo.value("validated_at"_ls), result.validatedAt);
- fromJson(jo.value("added_at"_ls), result.addedAt);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetAccount3PIDsJob::ThirdPartyIdentifier>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetAccount3PIDsJob::ThirdPartyIdentifier& result)
+ {
+ fromJson(jo.value("medium"_ls), result.medium);
+ fromJson(jo.value("address"_ls), result.address);
+ fromJson(jo.value("validated_at"_ls), result.validatedAt);
+ fromJson(jo.value("added_at"_ls), result.addedAt);
+ }
+};
+
} // namespace QMatrixClient
class GetAccount3PIDsJob::Private
{
- public:
+public:
QVector<ThirdPartyIdentifier> threepids;
};
@@ -43,11 +46,9 @@ QUrl GetAccount3PIDsJob::makeRequestUrl(QUrl baseUrl)
static const auto GetAccount3PIDsJobName = QStringLiteral("GetAccount3PIDsJob");
GetAccount3PIDsJob::GetAccount3PIDsJob()
- : BaseJob(HttpVerb::Get, GetAccount3PIDsJobName,
- basePath % "/account/3pid"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetAccount3PIDsJobName, basePath % "/account/3pid")
+ , d(new Private)
+{}
GetAccount3PIDsJob::~GetAccount3PIDsJob() = default;
@@ -61,21 +62,26 @@ BaseJob::Status GetAccount3PIDsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("threepids"_ls), d->threepids);
+
return Success;
}
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<Post3PIDsJob::ThreePidCredentials> {
- static void dumpTo(QJsonObject& jo,
- const Post3PIDsJob::ThreePidCredentials& pod)
- {
- addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
- addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
- addParam<>(jo, QStringLiteral("sid"), pod.sid);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<Post3PIDsJob::ThreePidCredentials>
+{
+ static void dumpTo(QJsonObject& jo,
+ const Post3PIDsJob::ThreePidCredentials& pod)
+ {
+ addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
+ addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<>(jo, QStringLiteral("sid"), pod.sid);
+ }
+};
+
} // namespace QMatrixClient
static const auto Post3PIDsJobName = QStringLiteral("Post3PIDsJob");
@@ -91,7 +97,7 @@ Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds,
}
static const auto Delete3pidFromAccountJobName =
- QStringLiteral("Delete3pidFromAccountJob");
+ QStringLiteral("Delete3pidFromAccountJob");
Delete3pidFromAccountJob::Delete3pidFromAccountJob(const QString& medium,
const QString& address)
@@ -106,19 +112,19 @@ Delete3pidFromAccountJob::Delete3pidFromAccountJob(const QString& medium,
class RequestTokenTo3PIDEmailJob::Private
{
- public:
+public:
Sid data;
};
static const auto RequestTokenTo3PIDEmailJobName =
- QStringLiteral("RequestTokenTo3PIDEmailJob");
+ QStringLiteral("RequestTokenTo3PIDEmailJob");
RequestTokenTo3PIDEmailJob::RequestTokenTo3PIDEmailJob(
- const QString& clientSecret, const QString& email, int sendAttempt,
- const QString& idServer, const QString& nextLink)
+ const QString& clientSecret, const QString& email, int sendAttempt,
+ const QString& idServer, const QString& nextLink)
: BaseJob(HttpVerb::Post, RequestTokenTo3PIDEmailJobName,
- basePath % "/account/3pid/email/requestToken", false),
- d(new Private)
+ basePath % "/account/3pid/email/requestToken", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -141,20 +147,20 @@ BaseJob::Status RequestTokenTo3PIDEmailJob::parseJson(const QJsonDocument& data)
class RequestTokenTo3PIDMSISDNJob::Private
{
- public:
+public:
Sid data;
};
static const auto RequestTokenTo3PIDMSISDNJobName =
- QStringLiteral("RequestTokenTo3PIDMSISDNJob");
+ QStringLiteral("RequestTokenTo3PIDMSISDNJob");
RequestTokenTo3PIDMSISDNJob::RequestTokenTo3PIDMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt, const QString& idServer,
- const QString& nextLink)
+ const QString& clientSecret, const QString& country,
+ const QString& phoneNumber, int sendAttempt, const QString& idServer,
+ const QString& nextLink)
: BaseJob(HttpVerb::Post, RequestTokenTo3PIDMSISDNJobName,
- basePath % "/account/3pid/msisdn/requestToken", false),
- d(new Private)
+ basePath % "/account/3pid/msisdn/requestToken", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -170,8 +176,7 @@ RequestTokenTo3PIDMSISDNJob::~RequestTokenTo3PIDMSISDNJob() = default;
const Sid& RequestTokenTo3PIDMSISDNJob::data() const { return d->data; }
-BaseJob::Status
-RequestTokenTo3PIDMSISDNJob::parseJson(const QJsonDocument& data)
+BaseJob::Status RequestTokenTo3PIDMSISDNJob::parseJson(const QJsonDocument& data)
{
fromJson(data, d->data);
return Success;
diff --git a/lib/csapi/administrative_contact.h b/lib/csapi/administrative_contact.h
index d99fde42..7f2d0cdc 100644
--- a/lib/csapi/administrative_contact.h
+++ b/lib/csapi/administrative_contact.h
@@ -4,17 +4,71 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/../identity/definitions/sid.h"
+
+#include "jobs/basejob.h"
+
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets a list of a user's third party identifiers.
+/*!
+ * Gets a list of the third party identifiers that the homeserver has
+ * associated with the user's account.
+ *
+ * This is *not* the same as the list of third party identifiers bound to
+ * the user's Matrix ID in identity servers.
+ *
+ * Identifiers in this list may be used by the homeserver as, for example,
+ * identifiers that it will accept to reset the user's account password.
+ */
+class GetAccount3PIDsJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// Gets a list of the third party identifiers that the homeserver
+ /// hasassociated with the user's account.This is *not* the same as the list
+ /// of third party identifiers bound tothe user's Matrix ID in identity
+ /// servers.Identifiers in this list may be used by the homeserver as, for
+ /// example,identifiers that it will accept to reset the user's account
+ /// password.
+ struct ThirdPartyIdentifier
+ {
+ /// The medium of the third party identifier.
+ QString medium;
+ /// The third party identifier address.
+ QString address;
+ /// The timestamp, in milliseconds, when the identifier wasvalidated by
+ /// the identity server.
+ qint64 validatedAt;
+ /// The timestamp, in milliseconds, when the homeserver associated the
+ /// third party identifier with the user.
+ qint64 addedAt;
+ };
+
+ // Construction/destruction
+
+ explicit GetAccount3PIDsJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetAccount3PIDsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetAccount3PIDsJob() override;
+
+ // Result properties
- /// Gets a list of a user's third party identifiers.
- ///
/// Gets a list of the third party identifiers that the homeserver has
/// associated with the user's account.
///
@@ -23,227 +77,183 @@ namespace QMatrixClient {
///
/// Identifiers in this list may be used by the homeserver as, for example,
/// identifiers that it will accept to reset the user's account password.
- class GetAccount3PIDsJob : public BaseJob
- {
- public:
- // Inner data structures
-
- /// Gets a list of the third party identifiers that the homeserver has
- /// associated with the user's account.
- ///
- /// This is *not* the same as the list of third party identifiers bound
- /// to the user's Matrix ID in identity servers.
- ///
- /// Identifiers in this list may be used by the homeserver as, for
- /// example, identifiers that it will accept to reset the user's account
- /// password.
- struct ThirdPartyIdentifier {
- /// The medium of the third party identifier.
- QString medium;
- /// The third party identifier address.
- QString address;
- /// The timestamp, in milliseconds, when the identifier was
- /// validated by the identity server.
- qint64 validatedAt;
- /// The timestamp, in milliseconds, when the homeserver associated
- /// the third party identifier with the user.
- qint64 addedAt;
- };
-
- // Construction/destruction
-
- explicit GetAccount3PIDsJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetAccount3PIDsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetAccount3PIDsJob() override;
-
- // Result properties
-
- /// Gets a list of the third party identifiers that the homeserver has
- /// associated with the user's account.
- ///
- /// This is *not* the same as the list of third party identifiers bound
- /// to the user's Matrix ID in identity servers.
- ///
- /// Identifiers in this list may be used by the homeserver as, for
- /// example, identifiers that it will accept to reset the user's account
- /// password.
- const QVector<ThirdPartyIdentifier>& threepids() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ const QVector<ThirdPartyIdentifier>& threepids() const;
- /// Adds contact information to the user's account.
- ///
- /// Adds contact information to the user's account.
- class Post3PIDsJob : public BaseJob
- {
- public:
- // Inner data structures
-
- /// The third party credentials to associate with the account.
- struct ThreePidCredentials {
- /// The client secret used in the session with the identity server.
- QString clientSecret;
- /// The identity server to use.
- QString idServer;
- /// The session identifier given by the identity server.
- QString sid;
- };
-
- // Construction/destruction
-
- /*! Adds contact information to the user's account.
- * \param threePidCreds
- * The third party credentials to associate with the account.
- * \param bind
- * Whether the homeserver should also bind this third party
- * identifier to the account's Matrix ID with the passed identity
- * server. Default: ``false``.
- */
- explicit Post3PIDsJob(const ThreePidCredentials& threePidCreds,
- Omittable<bool> bind = none);
- };
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- /// Deletes a third party identifier from the user's account
- ///
- /// Removes a third party identifier from the user's account. This might not
- /// cause an unbind of the identifier from the identity server.
- class Delete3pidFromAccountJob : public BaseJob
- {
- public:
- /*! Deletes a third party identifier from the user's account
- * \param medium
- * The medium of the third party identifier being removed.
- * \param address
- * The third party address being removed.
- */
- explicit Delete3pidFromAccountJob(const QString& medium,
- const QString& address);
- };
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- /// Begins the validation process for an email address for association with
- /// the user's account.
- ///
- /// Proxies the Identity Service API ``validate/email/requestToken``, but
- /// first checks that the given email address is **not** already associated
- /// with an account on this homeserver. This API should be used to request
- /// validation tokens when adding an email address to an account. This API's
- /// parameters and response are identical to that of the
- /// |/register/email/requestToken|_ endpoint.
- class RequestTokenTo3PIDEmailJob : public BaseJob
- {
- public:
- /*! Begins the validation process for an email address for association with the user's account.
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the
- * characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- * it must not be empty. \param email The email address to validate.
- * \param sendAttempt
- * The server will only send an email if the ``send_attempt``
- * is a number greater than the most recent one which it has seen,
- * scoped to that ``email`` + ``client_secret`` pair. This is to
- * avoid repeatedly sending the same email in the case of request
- * retries between the POSTing user and the identity server.
- * The client should increment this value if they desire a new
- * email (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
- */
- explicit RequestTokenTo3PIDEmailJob(const QString& clientSecret,
- const QString& email,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
- ~RequestTokenTo3PIDEmailJob() override;
-
- // Result properties
-
- /// An email was sent to the given address.
- const Sid& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+/// Adds contact information to the user's account.
+/*!
+ * Adds contact information to the user's account.
+ */
+class Post3PIDsJob : public BaseJob
+{
+public:
+ // Inner data structures
- /// Begins the validation process for a phone number for association with
- /// the user's account.
- ///
- /// Proxies the Identity Service API ``validate/msisdn/requestToken``, but
- /// first checks that the given phone number is **not** already associated
- /// with an account on this homeserver. This API should be used to request
- /// validation tokens when adding a phone number to an account. This API's
- /// parameters and response are identical to that of the
- /// |/register/msisdn/requestToken|_ endpoint.
- class RequestTokenTo3PIDMSISDNJob : public BaseJob
+ /// The third party credentials to associate with the account.
+ struct ThreePidCredentials
{
- public:
- /*! Begins the validation process for a phone number for association with the user's account.
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the
- * characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- * it must not be empty. \param country The two-letter uppercase ISO
- * country code that the number in
- * ``phone_number`` should be parsed as if it were dialled from.
- * \param phoneNumber
- * The phone number to validate.
- * \param sendAttempt
- * The server will only send an SMS if the ``send_attempt`` is a
- * number greater than the most recent one which it has seen,
- * scoped to that ``country`` + ``phone_number`` + ``client_secret``
- * triple. This is to avoid repeatedly sending the same SMS in
- * the case of request retries between the POSTing user and the
- * identity server. The client should increment this value if
- * they desire a new SMS (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
- */
- explicit RequestTokenTo3PIDMSISDNJob(const QString& clientSecret,
- const QString& country,
- const QString& phoneNumber,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
- ~RequestTokenTo3PIDMSISDNJob() override;
-
- // Result properties
-
- /// An SMS message was sent to the given phone number.
- const Sid& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// The client secret used in the session with the identity server.
+ QString clientSecret;
+ /// The identity server to use.
+ QString idServer;
+ /// The session identifier given by the identity server.
+ QString sid;
};
+
+ // Construction/destruction
+
+ /*! Adds contact information to the user's account.
+ * \param threePidCreds
+ * The third party credentials to associate with the account.
+ * \param bind
+ * Whether the homeserver should also bind this third party
+ * identifier to the account's Matrix ID with the passed identity
+ * server. Default: ``false``.
+ */
+ explicit Post3PIDsJob(const ThreePidCredentials& threePidCreds,
+ Omittable<bool> bind = none);
+};
+
+/// Deletes a third party identifier from the user's account
+/*!
+ * Removes a third party identifier from the user's account. This might not
+ * cause an unbind of the identifier from the identity server.
+ */
+class Delete3pidFromAccountJob : public BaseJob
+{
+public:
+ /*! Deletes a third party identifier from the user's account
+ * \param medium
+ * The medium of the third party identifier being removed.
+ * \param address
+ * The third party address being removed.
+ */
+ explicit Delete3pidFromAccountJob(const QString& medium,
+ const QString& address);
+};
+
+/// Begins the validation process for an email address for association with the
+/// user's account.
+/*!
+ * Proxies the Identity Service API ``validate/email/requestToken``, but
+ * first checks that the given email address is **not** already associated
+ * with an account on this homeserver. This API should be used to request
+ * validation tokens when adding an email address to an account. This API's
+ * parameters and response are identical to that of the
+ * |/register/email/requestToken|_ endpoint.
+ */
+class RequestTokenTo3PIDEmailJob : public BaseJob
+{
+public:
+ /*! Begins the validation process for an email address for association with
+ * the user's account. \param clientSecret A unique string generated by the
+ * client, and used to identify the validation attempt. It must be a string
+ * consisting of the characters
+ * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
+ * must not be empty.
+ * \param email
+ * The email address to validate.
+ * \param sendAttempt
+ * The server will only send an email if the ``send_attempt``
+ * is a number greater than the most recent one which it has seen,
+ * scoped to that ``email`` + ``client_secret`` pair. This is to
+ * avoid repeatedly sending the same email in the case of request
+ * retries between the POSTing user and the identity server.
+ * The client should increment this value if they desire a new
+ * email (e.g. a reminder) to be sent.
+ * \param idServer
+ * The hostname of the identity server to communicate with. May
+ * optionally include a port.
+ * \param nextLink
+ * Optional. When the validation is completed, the identity
+ * server will redirect the user to this URL.
+ */
+ explicit RequestTokenTo3PIDEmailJob(const QString& clientSecret,
+ const QString& email, int sendAttempt,
+ const QString& idServer,
+ const QString& nextLink = {});
+
+ ~RequestTokenTo3PIDEmailJob() override;
+
+ // Result properties
+
+ /// An email was sent to the given address.
+ const Sid& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Begins the validation process for a phone number for association with the
+/// user's account.
+/*!
+ * Proxies the Identity Service API ``validate/msisdn/requestToken``, but
+ * first checks that the given phone number is **not** already associated
+ * with an account on this homeserver. This API should be used to request
+ * validation tokens when adding a phone number to an account. This API's
+ * parameters and response are identical to that of the
+ * |/register/msisdn/requestToken|_ endpoint.
+ */
+class RequestTokenTo3PIDMSISDNJob : public BaseJob
+{
+public:
+ /*! Begins the validation process for a phone number for association with
+ * the user's account. \param clientSecret A unique string generated by the
+ * client, and used to identify the validation attempt. It must be a string
+ * consisting of the characters
+ * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
+ * must not be empty.
+ * \param country
+ * The two-letter uppercase ISO country code that the number in
+ * ``phone_number`` should be parsed as if it were dialled from.
+ * \param phoneNumber
+ * The phone number to validate.
+ * \param sendAttempt
+ * The server will only send an SMS if the ``send_attempt`` is a
+ * number greater than the most recent one which it has seen,
+ * scoped to that ``country`` + ``phone_number`` + ``client_secret``
+ * triple. This is to avoid repeatedly sending the same SMS in
+ * the case of request retries between the POSTing user and the
+ * identity server. The client should increment this value if
+ * they desire a new SMS (e.g. a reminder) to be sent.
+ * \param idServer
+ * The hostname of the identity server to communicate with. May
+ * optionally include a port.
+ * \param nextLink
+ * Optional. When the validation is completed, the identity
+ * server will redirect the user to this URL.
+ */
+ explicit RequestTokenTo3PIDMSISDNJob(const QString& clientSecret,
+ const QString& country,
+ const QString& phoneNumber,
+ int sendAttempt,
+ const QString& idServer,
+ const QString& nextLink = {});
+
+ ~RequestTokenTo3PIDMSISDNJob() override;
+
+ // Result properties
+
+ /// An SMS message was sent to the given phone number.
+ const Sid& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/appservice_room_directory.cpp b/lib/csapi/appservice_room_directory.cpp
index cf76874c..74e037cd 100644
--- a/lib/csapi/appservice_room_directory.cpp
+++ b/lib/csapi/appservice_room_directory.cpp
@@ -13,15 +13,12 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
static const auto UpdateAppserviceRoomDirectoryVsibilityJobName =
- QStringLiteral("UpdateAppserviceRoomDirectoryVsibilityJob");
+ QStringLiteral("UpdateAppserviceRoomDirectoryVsibilityJob");
-UpdateAppserviceRoomDirectoryVsibilityJob::
- UpdateAppserviceRoomDirectoryVsibilityJob(const QString& networkId,
- const QString& roomId,
- const QString& visibility)
+UpdateAppserviceRoomDirectoryVsibilityJob::UpdateAppserviceRoomDirectoryVsibilityJob(
+ const QString& networkId, const QString& roomId, const QString& visibility)
: BaseJob(HttpVerb::Put, UpdateAppserviceRoomDirectoryVsibilityJobName,
- basePath % "/directory/list/appservice/" % networkId % "/"
- % roomId)
+ basePath % "/directory/list/appservice/" % networkId % "/" % roomId)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("visibility"), visibility);
diff --git a/lib/csapi/appservice_room_directory.h b/lib/csapi/appservice_room_directory.h
index 2ee680c9..d1c3f89f 100644
--- a/lib/csapi/appservice_room_directory.h
+++ b/lib/csapi/appservice_room_directory.h
@@ -6,37 +6,40 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Updates a room's visibility in the application service's room directory.
+/*!
+ * Updates the visibility of a given room on the application service's room
+ * directory.
+ *
+ * This API is similar to the room directory visibility API used by clients
+ * to update the homeserver's more general room directory.
+ *
+ * This API requires the use of an application service access token
+ * (``as_token``) instead of a typical client's access_token. This API cannot be
+ * invoked by users who are not identified as application services.
+ */
+class UpdateAppserviceRoomDirectoryVsibilityJob : public BaseJob
+{
+public:
+ /*! Updates a room's visibility in the application service's room directory.
+ * \param networkId
+ * The protocol (network) ID to update the room list for. This would
+ * have been provided by the application service as being listed as
+ * a supported protocol.
+ * \param roomId
+ * The room ID to add to the directory.
+ * \param visibility
+ * Whether the room should be visible (public) in the directory
+ * or not (private).
+ */
+ explicit UpdateAppserviceRoomDirectoryVsibilityJob(const QString& networkId,
+ const QString& roomId,
+ const QString& visibility);
+};
- /// Updates a room's visibility in the application service's room directory.
- ///
- /// Updates the visibility of a given room on the application service's room
- /// directory.
- ///
- /// This API is similar to the room directory visibility API used by clients
- /// to update the homeserver's more general room directory.
- ///
- /// This API requires the use of an application service access token
- /// (``as_token``) instead of a typical client's access_token. This API
- /// cannot be invoked by users who are not identified as application
- /// services.
- class UpdateAppserviceRoomDirectoryVsibilityJob : public BaseJob
- {
- public:
- /*! Updates a room's visibility in the application service's room directory.
- * \param networkId
- * The protocol (network) ID to update the room list for. This would
- * have been provided by the application service as being listed as
- * a supported protocol.
- * \param roomId
- * The room ID to add to the directory.
- * \param visibility
- * Whether the room should be visible (public) in the directory
- * or not (private).
- */
- explicit UpdateAppserviceRoomDirectoryVsibilityJob(
- const QString& networkId, const QString& roomId,
- const QString& visibility);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/banning.cpp b/lib/csapi/banning.cpp
index 201126c3..a46e78f1 100644
--- a/lib/csapi/banning.cpp
+++ b/lib/csapi/banning.cpp
@@ -16,8 +16,7 @@ static const auto BanJobName = QStringLiteral("BanJob");
BanJob::BanJob(const QString& roomId, const QString& userId,
const QString& reason)
- : BaseJob(HttpVerb::Post, BanJobName,
- basePath % "/rooms/" % roomId % "/ban")
+ : BaseJob(HttpVerb::Post, BanJobName, basePath % "/rooms/" % roomId % "/ban")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
diff --git a/lib/csapi/banning.h b/lib/csapi/banning.h
index e1886f0e..0aa5785b 100644
--- a/lib/csapi/banning.h
+++ b/lib/csapi/banning.h
@@ -6,51 +6,56 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
- /// Ban a user in the room.
- ///
- /// Ban a user in the room. If the user is currently in the room, also kick
- /// them.
- ///
- /// When a user is banned from a room, they may not join it or be invited to
- /// it until they are unbanned.
- ///
- /// The caller must have the required power level in order to perform this
- /// operation.
- class BanJob : public BaseJob
- {
- public:
- /*! Ban a user in the room.
- * \param roomId
- * The room identifier (not alias) from which the user should be
- * banned. \param userId The fully qualified user ID of the user being
- * banned. \param reason The reason the user has been banned. This will
- * be supplied as the ``reason`` on the target's updated
- * `m.room.member`_ event.
- */
- explicit BanJob(const QString& roomId, const QString& userId,
- const QString& reason = {});
- };
+// Operations
+
+/// Ban a user in the room.
+/*!
+ * Ban a user in the room. If the user is currently in the room, also kick them.
+ *
+ * When a user is banned from a room, they may not join it or be invited to it
+ * until they are unbanned.
+ *
+ * The caller must have the required power level in order to perform this
+ * operation.
+ */
+class BanJob : public BaseJob
+{
+public:
+ /*! Ban a user in the room.
+ * \param roomId
+ * The room identifier (not alias) from which the user should be banned.
+ * \param userId
+ * The fully qualified user ID of the user being banned.
+ * \param reason
+ * The reason the user has been banned. This will be supplied as the
+ * ``reason`` on the target's updated `m.room.member`_ event.
+ */
+ explicit BanJob(const QString& roomId, const QString& userId,
+ const QString& reason = {});
+};
+
+/// Unban a user from the room.
+/*!
+ * Unban a user from the room. This allows them to be invited to the room,
+ * and join if they would otherwise be allowed to join according to its join
+ * rules.
+ *
+ * The caller must have the required power level in order to perform this
+ * operation.
+ */
+class UnbanJob : public BaseJob
+{
+public:
+ /*! Unban a user from the room.
+ * \param roomId
+ * The room identifier (not alias) from which the user should be unbanned.
+ * \param userId
+ * The fully qualified user ID of the user being unbanned.
+ */
+ explicit UnbanJob(const QString& roomId, const QString& userId);
+};
- /// Unban a user from the room.
- ///
- /// Unban a user from the room. This allows them to be invited to the room,
- /// and join if they would otherwise be allowed to join according to its
- /// join rules.
- ///
- /// The caller must have the required power level in order to perform this
- /// operation.
- class UnbanJob : public BaseJob
- {
- public:
- /*! Unban a user from the room.
- * \param roomId
- * The room identifier (not alias) from which the user should be
- * unbanned. \param userId The fully qualified user ID of the user being
- * unbanned.
- */
- explicit UnbanJob(const QString& roomId, const QString& userId);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/capabilities.cpp b/lib/csapi/capabilities.cpp
index 0fb9fbae..9a054fe9 100644
--- a/lib/csapi/capabilities.cpp
+++ b/lib/csapi/capabilities.cpp
@@ -12,43 +12,48 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <>
- struct JsonObjectConverter<GetCapabilitiesJob::ChangePasswordCapability> {
- static void
- fillFrom(const QJsonObject& jo,
- GetCapabilitiesJob::ChangePasswordCapability& result)
- {
- fromJson(jo.value("enabled"_ls), result.enabled);
- }
- };
-
- template <>
- struct JsonObjectConverter<GetCapabilitiesJob::RoomVersionsCapability> {
- static void fillFrom(const QJsonObject& jo,
- GetCapabilitiesJob::RoomVersionsCapability& result)
- {
- fromJson(jo.value("default"_ls), result.defaultVersion);
- fromJson(jo.value("available"_ls), result.available);
- }
- };
-
- template <> struct JsonObjectConverter<GetCapabilitiesJob::Capabilities> {
- static void fillFrom(QJsonObject jo,
- GetCapabilitiesJob::Capabilities& result)
- {
- fromJson(jo.take("m.change_password"_ls), result.changePassword);
- fromJson(jo.take("m.room_versions"_ls), result.roomVersions);
- fromJson(jo, result.additionalProperties);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetCapabilitiesJob::ChangePasswordCapability>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetCapabilitiesJob::ChangePasswordCapability& result)
+ {
+ fromJson(jo.value("enabled"_ls), result.enabled);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetCapabilitiesJob::RoomVersionsCapability>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetCapabilitiesJob::RoomVersionsCapability& result)
+ {
+ fromJson(jo.value("default"_ls), result.defaultVersion);
+ fromJson(jo.value("available"_ls), result.available);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetCapabilitiesJob::Capabilities>
+{
+ static void fillFrom(QJsonObject jo,
+ GetCapabilitiesJob::Capabilities& result)
+ {
+ fromJson(jo.take("m.change_password"_ls), result.changePassword);
+ fromJson(jo.take("m.room_versions"_ls), result.roomVersions);
+ fromJson(jo, result.additionalProperties);
+ }
+};
+
} // namespace QMatrixClient
class GetCapabilitiesJob::Private
{
- public:
+public:
Capabilities capabilities;
};
@@ -61,11 +66,9 @@ QUrl GetCapabilitiesJob::makeRequestUrl(QUrl baseUrl)
static const auto GetCapabilitiesJobName = QStringLiteral("GetCapabilitiesJob");
GetCapabilitiesJob::GetCapabilitiesJob()
- : BaseJob(HttpVerb::Get, GetCapabilitiesJobName,
- basePath % "/capabilities"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetCapabilitiesJobName, basePath % "/capabilities")
+ , d(new Private)
+{}
GetCapabilitiesJob::~GetCapabilitiesJob() = default;
@@ -78,8 +81,9 @@ BaseJob::Status GetCapabilitiesJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("capabilities"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'capabilities' not found in the response" };
fromJson(json.value("capabilities"_ls), d->capabilities);
+
return Success;
}
diff --git a/lib/csapi/capabilities.h b/lib/csapi/capabilities.h
index 6282c2fd..f6e7ad06 100644
--- a/lib/csapi/capabilities.h
+++ b/lib/csapi/capabilities.h
@@ -4,75 +4,84 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QHash>
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets information about the server's capabilities.
+/*!
+ * Gets information about the server's supported feature set
+ * and other relevant capabilities.
+ */
+class GetCapabilitiesJob : public BaseJob
+{
+public:
+ // Inner data structures
- /// Gets information about the server's capabilities.
- ///
- /// Gets information about the server's supported feature set
- /// and other relevant capabilities.
- class GetCapabilitiesJob : public BaseJob
+ /// Capability to indicate if the user can change their password.
+ struct ChangePasswordCapability
{
- public:
- // Inner data structures
+ /// True if the user can change their password, false otherwise.
+ bool enabled;
+ };
- /// Capability to indicate if the user can change their password.
- struct ChangePasswordCapability {
- /// True if the user can change their password, false otherwise.
- bool enabled;
- };
+ /// The room versions the server supports.
+ struct RoomVersionsCapability
+ {
+ /// The default room version the server is using for new rooms.
+ QString defaultVersion;
+ /// A detailed description of the room versions the server supports.
+ QHash<QString, QString> available;
+ };
+ /// The custom capabilities the server supports, using theJava package
+ /// naming convention.
+ struct Capabilities
+ {
+ /// Capability to indicate if the user can change their password.
+ Omittable<ChangePasswordCapability> changePassword;
/// The room versions the server supports.
- struct RoomVersionsCapability {
- /// The default room version the server is using for new rooms.
- QString defaultVersion;
- /// A detailed description of the room versions the server supports.
- QHash<QString, QString> available;
- };
-
- /// Gets information about the server's supported feature set
- /// and other relevant capabilities.
- struct Capabilities {
- /// Capability to indicate if the user can change their password.
- Omittable<ChangePasswordCapability> changePassword;
- /// The room versions the server supports.
- Omittable<RoomVersionsCapability> roomVersions;
- /// The custom capabilities the server supports, using the
- /// Java package naming convention.
- QHash<QString, QJsonObject> additionalProperties;
- };
-
- // Construction/destruction
-
- explicit GetCapabilitiesJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetCapabilitiesJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetCapabilitiesJob() override;
-
- // Result properties
-
- /// Gets information about the server's supported feature set
- /// and other relevant capabilities.
- const Capabilities& capabilities() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ Omittable<RoomVersionsCapability> roomVersions;
+
+ /// The custom capabilities the server supports, using theJava package
+ /// naming convention.
+ QHash<QString, QJsonObject> additionalProperties;
};
+
+ // Construction/destruction
+
+ explicit GetCapabilitiesJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetCapabilitiesJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetCapabilitiesJob() override;
+
+ // Result properties
+
+ /// The custom capabilities the server supports, using the
+ /// Java package naming convention.
+ const Capabilities& capabilities() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/content-repo.cpp b/lib/csapi/content-repo.cpp
index d59449b9..c2720d63 100644
--- a/lib/csapi/content-repo.cpp
+++ b/lib/csapi/content-repo.cpp
@@ -15,7 +15,7 @@ static const auto basePath = QStringLiteral("/_matrix/media/r0");
class UploadContentJob::Private
{
- public:
+public:
QString contentUri;
};
@@ -31,11 +31,10 @@ static const auto UploadContentJobName = QStringLiteral("UploadContentJob");
UploadContentJob::UploadContentJob(QIODevice* content, const QString& filename,
const QString& contentType)
: BaseJob(HttpVerb::Post, UploadContentJobName, basePath % "/upload",
- queryToUploadContent(filename)),
- d(new Private)
+ queryToUploadContent(filename))
+ , d(new Private)
{
setRequestHeader("Content-Type", contentType.toLatin1());
-
setRequestData(Data(content));
}
@@ -47,15 +46,16 @@ BaseJob::Status UploadContentJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("content_uri"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'content_uri' not found in the response" };
fromJson(json.value("content_uri"_ls), d->contentUri);
+
return Success;
}
class GetContentJob::Private
{
- public:
+public:
QString contentType;
QString contentDisposition;
QIODevice* data;
@@ -73,7 +73,7 @@ QUrl GetContentJob::makeRequestUrl(QUrl baseUrl, const QString& serverName,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/download/" % serverName % "/"
- % mediaId,
+ % mediaId,
queryToGetContent(allowRemote));
}
@@ -83,8 +83,8 @@ GetContentJob::GetContentJob(const QString& serverName, const QString& mediaId,
bool allowRemote)
: BaseJob(HttpVerb::Get, GetContentJobName,
basePath % "/download/" % serverName % "/" % mediaId,
- queryToGetContent(allowRemote), {}, false),
- d(new Private)
+ queryToGetContent(allowRemote), {}, false)
+ , d(new Private)
{
setExpectedContentTypes({ "*/*" });
}
@@ -110,7 +110,7 @@ BaseJob::Status GetContentJob::parseReply(QNetworkReply* reply)
class GetContentOverrideNameJob::Private
{
- public:
+public:
QString contentType;
QString contentDisposition;
QIODevice* data;
@@ -131,12 +131,12 @@ QUrl GetContentOverrideNameJob::makeRequestUrl(QUrl baseUrl,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/download/" % serverName % "/"
- % mediaId % "/" % fileName,
+ % mediaId % "/" % fileName,
queryToGetContentOverrideName(allowRemote));
}
static const auto GetContentOverrideNameJobName =
- QStringLiteral("GetContentOverrideNameJob");
+ QStringLiteral("GetContentOverrideNameJob");
GetContentOverrideNameJob::GetContentOverrideNameJob(const QString& serverName,
const QString& mediaId,
@@ -144,9 +144,9 @@ GetContentOverrideNameJob::GetContentOverrideNameJob(const QString& serverName,
bool allowRemote)
: BaseJob(HttpVerb::Get, GetContentOverrideNameJobName,
basePath % "/download/" % serverName % "/" % mediaId % "/"
- % fileName,
- queryToGetContentOverrideName(allowRemote), {}, false),
- d(new Private)
+ % fileName,
+ queryToGetContentOverrideName(allowRemote), {}, false)
+ , d(new Private)
{
setExpectedContentTypes({ "*/*" });
}
@@ -175,7 +175,7 @@ BaseJob::Status GetContentOverrideNameJob::parseReply(QNetworkReply* reply)
class GetContentThumbnailJob::Private
{
- public:
+public:
QString contentType;
QIODevice* data;
};
@@ -199,24 +199,23 @@ QUrl GetContentThumbnailJob::makeRequestUrl(QUrl baseUrl,
bool allowRemote)
{
return BaseJob::makeRequestUrl(
- std::move(baseUrl),
- basePath % "/thumbnail/" % serverName % "/" % mediaId,
- queryToGetContentThumbnail(width, height, method, allowRemote));
+ std::move(baseUrl),
+ basePath % "/thumbnail/" % serverName % "/" % mediaId,
+ queryToGetContentThumbnail(width, height, method, allowRemote));
}
static const auto GetContentThumbnailJobName =
- QStringLiteral("GetContentThumbnailJob");
+ QStringLiteral("GetContentThumbnailJob");
GetContentThumbnailJob::GetContentThumbnailJob(const QString& serverName,
- const QString& mediaId,
- int width, int height,
- const QString& method,
+ const QString& mediaId, int width,
+ int height, const QString& method,
bool allowRemote)
: BaseJob(HttpVerb::Get, GetContentThumbnailJobName,
basePath % "/thumbnail/" % serverName % "/" % mediaId,
queryToGetContentThumbnail(width, height, method, allowRemote),
- {}, false),
- d(new Private)
+ {}, false)
+ , d(new Private)
{
setExpectedContentTypes({ "image/jpeg", "image/png" });
}
@@ -239,7 +238,7 @@ BaseJob::Status GetContentThumbnailJob::parseReply(QNetworkReply* reply)
class GetUrlPreviewJob::Private
{
- public:
+public:
Omittable<qint64> matrixImageSize;
QString ogImage;
};
@@ -255,8 +254,7 @@ BaseJob::Query queryToGetUrlPreview(const QString& url, Omittable<qint64> ts)
QUrl GetUrlPreviewJob::makeRequestUrl(QUrl baseUrl, const QString& url,
Omittable<qint64> ts)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/preview_url",
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/preview_url",
queryToGetUrlPreview(url, ts));
}
@@ -264,10 +262,9 @@ static const auto GetUrlPreviewJobName = QStringLiteral("GetUrlPreviewJob");
GetUrlPreviewJob::GetUrlPreviewJob(const QString& url, Omittable<qint64> ts)
: BaseJob(HttpVerb::Get, GetUrlPreviewJobName, basePath % "/preview_url",
- queryToGetUrlPreview(url, ts)),
- d(new Private)
-{
-}
+ queryToGetUrlPreview(url, ts))
+ , d(new Private)
+{}
GetUrlPreviewJob::~GetUrlPreviewJob() = default;
@@ -283,12 +280,13 @@ BaseJob::Status GetUrlPreviewJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("matrix:image:size"_ls), d->matrixImageSize);
fromJson(json.value("og:image"_ls), d->ogImage);
+
return Success;
}
class GetConfigJob::Private
{
- public:
+public:
Omittable<qint64> uploadSize;
};
@@ -300,10 +298,9 @@ QUrl GetConfigJob::makeRequestUrl(QUrl baseUrl)
static const auto GetConfigJobName = QStringLiteral("GetConfigJob");
GetConfigJob::GetConfigJob()
- : BaseJob(HttpVerb::Get, GetConfigJobName, basePath % "/config"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetConfigJobName, basePath % "/config")
+ , d(new Private)
+{}
GetConfigJob::~GetConfigJob() = default;
@@ -313,5 +310,6 @@ BaseJob::Status GetConfigJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("m.upload.size"_ls), d->uploadSize);
+
return Success;
}
diff --git a/lib/csapi/content-repo.h b/lib/csapi/content-repo.h
index 1bef6380..9f267f6c 100644
--- a/lib/csapi/content-repo.h
+++ b/lib/csapi/content-repo.h
@@ -4,276 +4,282 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QIODevice>
-namespace QMatrixClient {
- // Operations
-
- /// Upload some content to the content repository.
- class UploadContentJob : public BaseJob
- {
- public:
- /*! Upload some content to the content repository.
- * \param content
- * \param filename
- * The name of the file being uploaded
- * \param contentType
- * The content type of the file being uploaded
- */
- explicit UploadContentJob(QIODevice* content,
- const QString& filename = {},
- const QString& contentType = {});
- ~UploadContentJob() override;
-
- // Result properties
-
- /// The MXC URI to the uploaded content.
- const QString& contentUri() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Download content from the content repository.
- class GetContentJob : public BaseJob
- {
- public:
- /*! Download content from the content repository.
- * \param serverName
- * The server name from the ``mxc://`` URI (the authoritory component)
- * \param mediaId
- * The media ID from the ``mxc://`` URI (the path component)
- * \param allowRemote
- * Indicates to the server that it should not attempt to fetch the
- * media if it is deemed remote. This is to prevent routing loops where
- * the server contacts itself. Defaults to true if not provided.
- */
- explicit GetContentJob(const QString& serverName,
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Upload some content to the content repository.
+
+class UploadContentJob : public BaseJob
+{
+public:
+ /*! Upload some content to the content repository.
+ * \param content
+ * \param filename
+ * The name of the file being uploaded
+ * \param contentType
+ * The content type of the file being uploaded
+ */
+ explicit UploadContentJob(QIODevice* content, const QString& filename = {},
+ const QString& contentType = {});
+
+ ~UploadContentJob() override;
+
+ // Result properties
+
+ /// The MXC URI to the uploaded content.
+ const QString& contentUri() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Download content from the content repository.
+
+class GetContentJob : public BaseJob
+{
+public:
+ /*! Download content from the content repository.
+ * \param serverName
+ * The server name from the ``mxc://`` URI (the authoritory component)
+ * \param mediaId
+ * The media ID from the ``mxc://`` URI (the path component)
+ * \param allowRemote
+ * Indicates to the server that it should not attempt to fetch the media
+ * if it is deemed remote. This is to prevent routing loops where the server
+ * contacts itself. Defaults to true if not provided.
+ */
+ explicit GetContentJob(const QString& serverName, const QString& mediaId,
+ bool allowRemote = true);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetContentJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
const QString& mediaId, bool allowRemote = true);
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetContentJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
- const QString& mediaId,
- bool allowRemote = true);
-
- ~GetContentJob() override;
-
- // Result properties
-
- /// The content type of the file that was previously uploaded.
- const QString& contentType() const;
- /// The name of the file that was previously uploaded, if set.
- const QString& contentDisposition() const;
- /// The content that was previously uploaded.
- QIODevice* data() const;
-
- protected:
- Status parseReply(QNetworkReply* reply) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Download content from the content repository as a given filename.
- class GetContentOverrideNameJob : public BaseJob
- {
- public:
- /*! Download content from the content repository as a given filename.
- * \param serverName
- * The server name from the ``mxc://`` URI (the authoritory component)
- * \param mediaId
- * The media ID from the ``mxc://`` URI (the path component)
- * \param fileName
- * The filename to give in the Content-Disposition
- * \param allowRemote
- * Indicates to the server that it should not attempt to fetch the
- * media if it is deemed remote. This is to prevent routing loops where
- * the server contacts itself. Defaults to true if not provided.
- */
- explicit GetContentOverrideNameJob(const QString& serverName,
- const QString& mediaId,
- const QString& fileName,
- bool allowRemote = true);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetContentOverrideNameJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
- const QString& mediaId,
- const QString& fileName,
- bool allowRemote = true);
-
- ~GetContentOverrideNameJob() override;
-
- // Result properties
-
- /// The content type of the file that was previously uploaded.
- const QString& contentType() const;
- /// The name of file given in the request
- const QString& contentDisposition() const;
- /// The content that was previously uploaded.
- QIODevice* data() const;
-
- protected:
- Status parseReply(QNetworkReply* reply) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Download a thumbnail of the content from the content repository.
- class GetContentThumbnailJob : public BaseJob
- {
- public:
- /*! Download a thumbnail of the content from the content repository.
- * \param serverName
- * The server name from the ``mxc://`` URI (the authoritory component)
- * \param mediaId
- * The media ID from the ``mxc://`` URI (the path component)
- * \param width
- * The *desired* width of the thumbnail. The actual thumbnail may not
- * match the size specified.
- * \param height
- * The *desired* height of the thumbnail. The actual thumbnail may not
- * match the size specified.
- * \param method
- * The desired resizing method.
- * \param allowRemote
- * Indicates to the server that it should not attempt to fetch the
- * media if it is deemed remote. This is to prevent routing loops where
- * the server contacts itself. Defaults to true if not provided.
- */
- explicit GetContentThumbnailJob(const QString& serverName,
- const QString& mediaId, int width,
- int height, const QString& method = {},
- bool allowRemote = true);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetContentThumbnailJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
- const QString& mediaId, int width,
- int height, const QString& method = {},
- bool allowRemote = true);
-
- ~GetContentThumbnailJob() override;
-
- // Result properties
-
- /// The content type of the thumbnail.
- const QString& contentType() const;
- /// A thumbnail of the requested content.
- QIODevice* data() const;
-
- protected:
- Status parseReply(QNetworkReply* reply) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Get information about a URL for a client
- class GetUrlPreviewJob : public BaseJob
- {
- public:
- /*! Get information about a URL for a client
- * \param url
- * The URL to get a preview of
- * \param ts
- * The preferred point in time to return a preview for. The server may
- * return a newer version if it does not have the requested version
- * available.
- */
- explicit GetUrlPreviewJob(const QString& url,
- Omittable<qint64> ts = none);
-
- /*! 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,
- Omittable<qint64> ts = none);
-
- ~GetUrlPreviewJob() override;
-
- // Result properties
-
- /// The byte-size of the image. Omitted if there is no image attached.
- Omittable<qint64> matrixImageSize() const;
- /// An MXC URI to the image. Omitted if there is no image.
- const QString& ogImage() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Get the configuration for the content repository.
- ///
- /// This endpoint allows clients to retrieve the configuration of the
- /// content repository, such as upload limitations. Clients SHOULD use this
- /// as a guide when using content repository endpoints. All values are
- /// intentionally left optional. Clients SHOULD follow the advice given in
- /// the field description when the field is not available.
- ///
- /// **NOTE:** Both clients and server administrators should be aware that
- /// proxies between the client and the server may affect the apparent
- /// behaviour of content repository APIs, for example, proxies may enforce a
- /// lower upload size limit than is advertised by the server on this
- /// endpoint.
- class GetConfigJob : public BaseJob
- {
- public:
- explicit GetConfigJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetConfigJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetConfigJob() override;
-
- // Result properties
-
- /// The maximum size an upload can be in bytes.
- /// Clients SHOULD use this as a guide when uploading content.
- /// If not listed or null, the size limit should be treated as unknown.
- Omittable<qint64> uploadSize() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ ~GetContentJob() override;
+
+ // Result properties
+
+ /// The content type of the file that was previously uploaded.
+ const QString& contentType() const;
+ /// The name of the file that was previously uploaded, if set.
+ const QString& contentDisposition() const;
+ /// The content that was previously uploaded.
+ QIODevice* data() const;
+
+protected:
+ Status parseReply(QNetworkReply* reply) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Download content from the content repository as a given filename.
+
+class GetContentOverrideNameJob : public BaseJob
+{
+public:
+ /*! Download content from the content repository as a given filename.
+ * \param serverName
+ * The server name from the ``mxc://`` URI (the authoritory component)
+ * \param mediaId
+ * The media ID from the ``mxc://`` URI (the path component)
+ * \param fileName
+ * The filename to give in the Content-Disposition
+ * \param allowRemote
+ * Indicates to the server that it should not attempt to fetch the media
+ * if it is deemed remote. This is to prevent routing loops where the server
+ * contacts itself. Defaults to true if not provided.
+ */
+ explicit GetContentOverrideNameJob(const QString& serverName,
+ const QString& mediaId,
+ const QString& fileName,
+ bool allowRemote = true);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetContentOverrideNameJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
+ const QString& mediaId, const QString& fileName,
+ bool allowRemote = true);
+
+ ~GetContentOverrideNameJob() override;
+
+ // Result properties
+
+ /// The content type of the file that was previously uploaded.
+ const QString& contentType() const;
+ /// The name of file given in the request
+ const QString& contentDisposition() const;
+ /// The content that was previously uploaded.
+ QIODevice* data() const;
+
+protected:
+ Status parseReply(QNetworkReply* reply) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Download a thumbnail of the content from the content repository.
+
+class GetContentThumbnailJob : public BaseJob
+{
+public:
+ /*! Download a thumbnail of the content from the content repository.
+ * \param serverName
+ * The server name from the ``mxc://`` URI (the authoritory component)
+ * \param mediaId
+ * The media ID from the ``mxc://`` URI (the path component)
+ * \param width
+ * The *desired* width of the thumbnail. The actual thumbnail may not
+ * match the size specified.
+ * \param height
+ * The *desired* height of the thumbnail. The actual thumbnail may not
+ * match the size specified.
+ * \param method
+ * The desired resizing method.
+ * \param allowRemote
+ * Indicates to the server that it should not attempt to fetch the media
+ * if it is deemed remote. This is to prevent routing loops where the server
+ * contacts itself. Defaults to true if not provided.
+ */
+ explicit GetContentThumbnailJob(const QString& serverName,
+ const QString& mediaId, int width,
+ int height, const QString& method = {},
+ bool allowRemote = true);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetContentThumbnailJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
+ const QString& mediaId, int width, int height,
+ const QString& method = {},
+ bool allowRemote = true);
+
+ ~GetContentThumbnailJob() override;
+
+ // Result properties
+
+ /// The content type of the thumbnail.
+ const QString& contentType() const;
+ /// A thumbnail of the requested content.
+ QIODevice* data() const;
+
+protected:
+ Status parseReply(QNetworkReply* reply) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Get information about a URL for a client
+
+class GetUrlPreviewJob : public BaseJob
+{
+public:
+ /*! Get information about a URL for a client
+ * \param url
+ * The URL to get a preview of
+ * \param ts
+ * The preferred point in time to return a preview for. The server may
+ * return a newer version if it does not have the requested version
+ * available.
+ */
+ explicit GetUrlPreviewJob(const QString& url, Omittable<qint64> ts = none);
+
+ /*! 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,
+ Omittable<qint64> ts = none);
+
+ ~GetUrlPreviewJob() override;
+
+ // Result properties
+
+ /// The byte-size of the image. Omitted if there is no image attached.
+ Omittable<qint64> matrixImageSize() const;
+ /// An MXC URI to the image. Omitted if there is no image.
+ const QString& ogImage() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Get the configuration for the content repository.
+/*!
+ * This endpoint allows clients to retrieve the configuration of the content
+ * repository, such as upload limitations.
+ * Clients SHOULD use this as a guide when using content repository endpoints.
+ * All values are intentionally left optional. Clients SHOULD follow
+ * the advice given in the field description when the field is not available.
+ *
+ * **NOTE:** Both clients and server administrators should be aware that proxies
+ * between the client and the server may affect the apparent behaviour of
+ * content repository APIs, for example, proxies may enforce a lower upload size
+ * limit than is advertised by the server on this endpoint.
+ */
+class GetConfigJob : public BaseJob
+{
+public:
+ explicit GetConfigJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetConfigJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetConfigJob() override;
+
+ // Result properties
+
+ /// The maximum size an upload can be in bytes.
+ /// Clients SHOULD use this as a guide when uploading content.
+ /// If not listed or null, the size limit should be treated as unknown.
+ Omittable<qint64> uploadSize() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp
index 47a13d8e..e94cb008 100644
--- a/lib/csapi/create_room.cpp
+++ b/lib/csapi/create_room.cpp
@@ -12,33 +12,37 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<CreateRoomJob::Invite3pid> {
- static void dumpTo(QJsonObject& jo,
- const CreateRoomJob::Invite3pid& pod)
- {
- addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
- addParam<>(jo, QStringLiteral("medium"), pod.medium);
- addParam<>(jo, QStringLiteral("address"), pod.address);
- }
- };
-
- template <> struct JsonObjectConverter<CreateRoomJob::StateEvent> {
- static void dumpTo(QJsonObject& jo,
- const CreateRoomJob::StateEvent& pod)
- {
- addParam<>(jo, QStringLiteral("type"), pod.type);
- addParam<IfNotEmpty>(jo, QStringLiteral("state_key"), pod.stateKey);
- addParam<>(jo, QStringLiteral("content"), pod.content);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<CreateRoomJob::Invite3pid>
+{
+ static void dumpTo(QJsonObject& jo, const CreateRoomJob::Invite3pid& pod)
+ {
+ addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<>(jo, QStringLiteral("medium"), pod.medium);
+ addParam<>(jo, QStringLiteral("address"), pod.address);
+ }
+};
+
+template <>
+struct JsonObjectConverter<CreateRoomJob::StateEvent>
+{
+ static void dumpTo(QJsonObject& jo, const CreateRoomJob::StateEvent& pod)
+ {
+ addParam<>(jo, QStringLiteral("type"), pod.type);
+ addParam<IfNotEmpty>(jo, QStringLiteral("state_key"), pod.stateKey);
+ addParam<>(jo, QStringLiteral("content"), pod.content);
+ }
+};
+
} // namespace QMatrixClient
class CreateRoomJob::Private
{
- public:
+public:
QString roomId;
};
@@ -53,8 +57,8 @@ CreateRoomJob::CreateRoomJob(const QString& visibility,
const QVector<StateEvent>& initialState,
const QString& preset, Omittable<bool> isDirect,
const QJsonObject& powerLevelContentOverride)
- : BaseJob(HttpVerb::Post, CreateRoomJobName, basePath % "/createRoom"),
- d(new Private)
+ : BaseJob(HttpVerb::Post, CreateRoomJobName, basePath % "/createRoom")
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility);
@@ -83,8 +87,9 @@ BaseJob::Status CreateRoomJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("room_id"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'room_id' not found in the response" };
fromJson(json.value("room_id"_ls), d->roomId);
+
return Success;
}
diff --git a/lib/csapi/create_room.h b/lib/csapi/create_room.h
index 4348bd63..a066a3f3 100644
--- a/lib/csapi/create_room.h
+++ b/lib/csapi/create_room.h
@@ -4,269 +4,235 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QJsonObject>
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Create a new room
+/*!
+ * Create a new room with various configuration options.
+ *
+ * The server MUST apply the normal state resolution rules when creating
+ * the new room, including checking power levels for each event. It MUST
+ * apply the events implied by the request in the following order:
+ *
+ * 0. A default ``m.room.power_levels`` event, giving the room creator
+ * (and not other members) permission to send state events. Overridden
+ * by the ``power_level_content_override`` parameter.
+ *
+ * 1. Events set by the ``preset``. Currently these are the
+ * ``m.room.join_rules``,
+ * ``m.room.history_visibility``, and ``m.room.guest_access`` state events.
+ *
+ * 2. Events listed in ``initial_state``, in the order that they are
+ * listed.
+ *
+ * 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
+ * ``m.room.topic`` state events).
+ *
+ * 4. Invite events implied by ``invite`` and ``invite_3pid`` (``m.room.member``
+ * with
+ * ``membership: invite`` and ``m.room.third_party_invite``).
+ *
+ * The available presets do the following with respect to room state:
+ *
+ * ======================== ============== ======================
+ * ================ ========= Preset ``join_rules``
+ * ``history_visibility`` ``guest_access`` Other
+ * ======================== ============== ======================
+ * ================ =========
+ * ``private_chat`` ``invite`` ``shared`` ``can_join``
+ * ``trusted_private_chat`` ``invite`` ``shared`` ``can_join`` All
+ * invitees are given the same power level as the room creator.
+ * ``public_chat`` ``public`` ``shared`` ``forbidden``
+ * ======================== ============== ======================
+ * ================ =========
+ *
+ * The server will create a ``m.room.create`` event in the room with the
+ * requesting user as the creator, alongside other keys provided in the
+ * ``creation_content``.
+ */
+class CreateRoomJob : public BaseJob
+{
+public:
+ // Inner data structures
- /// Create a new room
- ///
- /// Create a new room with various configuration options.
- ///
- /// The server MUST apply the normal state resolution rules when creating
- /// the new room, including checking power levels for each event. It MUST
- /// apply the events implied by the request in the following order:
- ///
- /// 0. A default ``m.room.power_levels`` event, giving the room creator
- /// (and not other members) permission to send state events. Overridden
- /// by the ``power_level_content_override`` parameter.
- ///
- /// 1. Events set by the ``preset``. Currently these are the
- /// ``m.room.join_rules``,
- /// ``m.room.history_visibility``, and ``m.room.guest_access`` state
- /// events.
- ///
- /// 2. Events listed in ``initial_state``, in the order that they are
- /// listed.
- ///
- /// 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
- /// ``m.room.topic``
- /// state events).
- ///
- /// 4. Invite events implied by ``invite`` and ``invite_3pid``
- /// (``m.room.member`` with
- /// ``membership: invite`` and ``m.room.third_party_invite``).
- ///
- /// The available presets do the following with respect to room state:
- ///
- /// ======================== ============== ======================
- /// ================ =========
- /// Preset ``join_rules`` ``history_visibility``
- /// ``guest_access`` Other
- /// ======================== ============== ======================
- /// ================ =========
- /// ``private_chat`` ``invite`` ``shared`` ``can_join``
- /// ``trusted_private_chat`` ``invite`` ``shared`` ``can_join`` All
- /// invitees are given the same power level as the room creator.
- /// ``public_chat`` ``public`` ``shared`` ``forbidden``
- /// ======================== ============== ======================
- /// ================ =========
- ///
- /// The server will create a ``m.room.create`` event in the room with the
- /// requesting user as the creator, alongside other keys provided in the
- /// ``creation_content``.
- class CreateRoomJob : public BaseJob
+ /// Create a new room with various configuration options.The server MUST
+ /// apply the normal state resolution rules when creatingthe new room,
+ /// including checking power levels for each event. It MUSTapply the events
+ /// implied by the request in the following order:0. A default
+ /// ``m.room.power_levels`` event, giving the room creator (and not other
+ /// members) permission to send state events. Overridden by the
+ /// ``power_level_content_override`` parameter.1. Events set by the
+ /// ``preset``. Currently these are the ``m.room.join_rules``,
+ /// ``m.room.history_visibility``, and ``m.room.guest_access`` state
+ /// events.2. Events listed in ``initial_state``, in the order that they are
+ /// listed.3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
+ /// ``m.room.topic`` state events).4. Invite events implied by ``invite``
+ /// and ``invite_3pid`` (``m.room.member`` with ``membership: invite`` and
+ /// ``m.room.third_party_invite``).The available presets do the following
+ /// with respect to room state:======================== ==============
+ /// ====================== ================ ========= Preset
+ /// ``join_rules`` ``history_visibility`` ``guest_access``
+ /// Other======================== ============== ======================
+ /// ================ =========``private_chat`` ``invite``
+ /// ``shared`` ``can_join````trusted_private_chat`` ``invite``
+ /// ``shared`` ``can_join`` All invitees are given the
+ /// same power level as the room creator.``public_chat`` ``public``
+ /// ``shared`` ``forbidden``========================
+ /// ============== ====================== ================ =========The
+ /// server will create a ``m.room.create`` event in the room with
+ /// therequesting user as the creator, alongside other keys provided in
+ /// the``creation_content``.
+ struct Invite3pid
{
- public:
- // Inner data structures
+ /// The hostname+port of the identity server which should be used for
+ /// third party identifier lookups.
+ QString idServer;
+ /// The kind of address being passed in the address field, for example
+ /// ``email``.
+ QString medium;
+ /// The invitee's third party identifier.
+ QString address;
+ };
- /// Create a new room with various configuration options.
- ///
- /// The server MUST apply the normal state resolution rules when
- /// creating the new room, including checking power levels for each
- /// event. It MUST apply the events implied by the request in the
- /// following order:
- ///
- /// 0. A default ``m.room.power_levels`` event, giving the room creator
- /// (and not other members) permission to send state events.
- /// Overridden by the ``power_level_content_override`` parameter.
- ///
- /// 1. Events set by the ``preset``. Currently these are the
- /// ``m.room.join_rules``,
- /// ``m.room.history_visibility``, and ``m.room.guest_access`` state
- /// events.
- ///
- /// 2. Events listed in ``initial_state``, in the order that they are
- /// listed.
- ///
- /// 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
- /// ``m.room.topic``
- /// state events).
- ///
- /// 4. Invite events implied by ``invite`` and ``invite_3pid``
- /// (``m.room.member`` with
- /// ``membership: invite`` and ``m.room.third_party_invite``).
- ///
- /// The available presets do the following with respect to room state:
- ///
- /// ======================== ============== ======================
- /// ================ =========
- /// Preset ``join_rules`` ``history_visibility``
- /// ``guest_access`` Other
- /// ======================== ============== ======================
- /// ================ =========
- /// ``private_chat`` ``invite`` ``shared`` ``can_join``
- /// ``trusted_private_chat`` ``invite`` ``shared`` ``can_join``
- /// All invitees are given the same power level as the room creator.
- /// ``public_chat`` ``public`` ``shared`` ``forbidden``
- /// ======================== ============== ======================
- /// ================ =========
- ///
- /// The server will create a ``m.room.create`` event in the room with
- /// the requesting user as the creator, alongside other keys provided in
- /// the
- /// ``creation_content``.
- struct Invite3pid {
- /// The hostname+port of the identity server which should be used
- /// for third party identifier lookups.
- QString idServer;
- /// The kind of address being passed in the address field, for
- /// example ``email``.
- QString medium;
- /// The invitee's third party identifier.
- QString address;
- };
+ /// Create a new room with various configuration options.The server MUST
+ /// apply the normal state resolution rules when creatingthe new room,
+ /// including checking power levels for each event. It MUSTapply the events
+ /// implied by the request in the following order:0. A default
+ /// ``m.room.power_levels`` event, giving the room creator (and not other
+ /// members) permission to send state events. Overridden by the
+ /// ``power_level_content_override`` parameter.1. Events set by the
+ /// ``preset``. Currently these are the ``m.room.join_rules``,
+ /// ``m.room.history_visibility``, and ``m.room.guest_access`` state
+ /// events.2. Events listed in ``initial_state``, in the order that they are
+ /// listed.3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
+ /// ``m.room.topic`` state events).4. Invite events implied by ``invite``
+ /// and ``invite_3pid`` (``m.room.member`` with ``membership: invite`` and
+ /// ``m.room.third_party_invite``).The available presets do the following
+ /// with respect to room state:======================== ==============
+ /// ====================== ================ ========= Preset
+ /// ``join_rules`` ``history_visibility`` ``guest_access``
+ /// Other======================== ============== ======================
+ /// ================ =========``private_chat`` ``invite``
+ /// ``shared`` ``can_join````trusted_private_chat`` ``invite``
+ /// ``shared`` ``can_join`` All invitees are given the
+ /// same power level as the room creator.``public_chat`` ``public``
+ /// ``shared`` ``forbidden``========================
+ /// ============== ====================== ================ =========The
+ /// server will create a ``m.room.create`` event in the room with
+ /// therequesting user as the creator, alongside other keys provided in
+ /// the``creation_content``.
+ struct StateEvent
+ {
+ /// The type of event to send.
+ QString type;
+ /// The state_key of the state event. Defaults to an empty string.
+ QString stateKey;
+ /// The content of the event.
+ QJsonObject content;
+ };
- /// Create a new room with various configuration options.
- ///
- /// The server MUST apply the normal state resolution rules when
- /// creating the new room, including checking power levels for each
- /// event. It MUST apply the events implied by the request in the
- /// following order:
- ///
- /// 0. A default ``m.room.power_levels`` event, giving the room creator
- /// (and not other members) permission to send state events.
- /// Overridden by the ``power_level_content_override`` parameter.
- ///
- /// 1. Events set by the ``preset``. Currently these are the
- /// ``m.room.join_rules``,
- /// ``m.room.history_visibility``, and ``m.room.guest_access`` state
- /// events.
- ///
- /// 2. Events listed in ``initial_state``, in the order that they are
- /// listed.
- ///
- /// 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
- /// ``m.room.topic``
- /// state events).
- ///
- /// 4. Invite events implied by ``invite`` and ``invite_3pid``
- /// (``m.room.member`` with
- /// ``membership: invite`` and ``m.room.third_party_invite``).
- ///
- /// The available presets do the following with respect to room state:
- ///
- /// ======================== ============== ======================
- /// ================ =========
- /// Preset ``join_rules`` ``history_visibility``
- /// ``guest_access`` Other
- /// ======================== ============== ======================
- /// ================ =========
- /// ``private_chat`` ``invite`` ``shared`` ``can_join``
- /// ``trusted_private_chat`` ``invite`` ``shared`` ``can_join``
- /// All invitees are given the same power level as the room creator.
- /// ``public_chat`` ``public`` ``shared`` ``forbidden``
- /// ======================== ============== ======================
- /// ================ =========
- ///
- /// The server will create a ``m.room.create`` event in the room with
- /// the requesting user as the creator, alongside other keys provided in
- /// the
- /// ``creation_content``.
- struct StateEvent {
- /// The type of event to send.
- QString type;
- /// The state_key of the state event. Defaults to an empty string.
- QString stateKey;
- /// The content of the event.
- QJsonObject content;
- };
+ // Construction/destruction
- // Construction/destruction
+ /*! Create a new room
+ * \param visibility
+ * A ``public`` visibility indicates that the room will be shown
+ * in the published room list. A ``private`` visibility will hide
+ * the room from the published room list. Rooms default to
+ * ``private`` visibility if this key is not included. NB: This
+ * should not be confused with ``join_rules`` which also uses the
+ * word ``public``.
+ * \param roomAliasName
+ * The desired room alias **local part**. If this is included, a
+ * room alias will be created and mapped to the newly created
+ * room. The alias will belong on the *same* homeserver which
+ * created the room. For example, if this was set to "foo" and
+ * sent to the homeserver "example.com" the complete room alias
+ * would be ``#foo:example.com``.
+ *
+ * The complete room alias will become the canonical alias for
+ * the room.
+ * \param name
+ * If this is included, an ``m.room.name`` event will be sent
+ * into the room to indicate the name of the room. See Room
+ * Events for more information on ``m.room.name``.
+ * \param topic
+ * If this is included, an ``m.room.topic`` event will be sent
+ * into the room to indicate the topic for the room. See Room
+ * Events for more information on ``m.room.topic``.
+ * \param invite
+ * A list of user IDs to invite to the room. This will tell the
+ * server to invite everyone in the list to the newly created room.
+ * \param invite3pid
+ * A list of objects representing third party IDs to invite into
+ * the room.
+ * \param roomVersion
+ * The room version to set for the room. If not provided, the homeserver
+ * is to use its configured default. If provided, the homeserver will return
+ * a 400 error with the errcode ``M_UNSUPPORTED_ROOM_VERSION`` if it does
+ * not support the room version. \param creationContent Extra keys, such as
+ * ``m.federate``, to be added to the content of the `m.room.create`_ event.
+ * The server will clobber the following keys: ``creator``,
+ * ``room_version``. Future versions of the specification may allow the
+ * server to clobber other keys. \param initialState A list of state events
+ * to set in the new room. This allows the user to override the default
+ * state events set in the new room. The expected format of the state events
+ * are an object with type, state_key and content keys set.
+ *
+ * Takes precedence over events set by ``preset``, but gets
+ * overriden by ``name`` and ``topic`` keys.
+ * \param preset
+ * Convenience parameter for setting various default state events
+ * based on a preset.
+ *
+ * If unspecified, the server should use the ``visibility`` to determine
+ * which preset to use. A visbility of ``public`` equates to a preset of
+ * ``public_chat`` and ``private`` visibility equates to a preset of
+ * ``private_chat``.
+ * \param isDirect
+ * This flag makes the server set the ``is_direct`` flag on the
+ * ``m.room.member`` events sent to the users in ``invite`` and
+ * ``invite_3pid``. See `Direct Messaging`_ for more information.
+ * \param powerLevelContentOverride
+ * The power level content to override in the default power level
+ * event. This object is applied on top of the generated
+ * `m.room.power_levels`_ event content prior to it being sent to the room.
+ * Defaults to overriding nothing.
+ */
+ explicit CreateRoomJob(const QString& visibility = {},
+ const QString& roomAliasName = {},
+ const QString& name = {}, const QString& topic = {},
+ const QStringList& invite = {},
+ const QVector<Invite3pid>& invite3pid = {},
+ const QString& roomVersion = {},
+ const QJsonObject& creationContent = {},
+ const QVector<StateEvent>& initialState = {},
+ const QString& preset = {},
+ Omittable<bool> isDirect = none,
+ const QJsonObject& powerLevelContentOverride = {});
- /*! Create a new room
- * \param visibility
- * A ``public`` visibility indicates that the room will be shown
- * in the published room list. A ``private`` visibility will hide
- * the room from the published room list. Rooms default to
- * ``private`` visibility if this key is not included. NB: This
- * should not be confused with ``join_rules`` which also uses the
- * word ``public``.
- * \param roomAliasName
- * The desired room alias **local part**. If this is included, a
- * room alias will be created and mapped to the newly created
- * room. The alias will belong on the *same* homeserver which
- * created the room. For example, if this was set to "foo" and
- * sent to the homeserver "example.com" the complete room alias
- * would be ``#foo:example.com``.
- *
- * The complete room alias will become the canonical alias for
- * the room.
- * \param name
- * If this is included, an ``m.room.name`` event will be sent
- * into the room to indicate the name of the room. See Room
- * Events for more information on ``m.room.name``.
- * \param topic
- * If this is included, an ``m.room.topic`` event will be sent
- * into the room to indicate the topic for the room. See Room
- * Events for more information on ``m.room.topic``.
- * \param invite
- * A list of user IDs to invite to the room. This will tell the
- * server to invite everyone in the list to the newly created room.
- * \param invite3pid
- * A list of objects representing third party IDs to invite into
- * the room.
- * \param roomVersion
- * The room version to set for the room. If not provided, the
- * homeserver is to use its configured default. If provided, the
- * homeserver will return a 400 error with the errcode
- * ``M_UNSUPPORTED_ROOM_VERSION`` if it does not support the room
- * version. \param creationContent Extra keys, such as ``m.federate``,
- * to be added to the content of the `m.room.create`_ event. The server
- * will clobber the following keys: ``creator``, ``room_version``.
- * Future versions of the specification may allow the server to clobber
- * other keys. \param initialState A list of state events to set in the
- * new room. This allows the user to override the default state events
- * set in the new room. The expected format of the state events are an
- * object with type, state_key and content keys set.
- *
- * Takes precedence over events set by ``preset``, but gets
- * overriden by ``name`` and ``topic`` keys.
- * \param preset
- * Convenience parameter for setting various default state events
- * based on a preset.
- *
- * If unspecified, the server should use the ``visibility`` to
- * determine which preset to use. A visbility of ``public`` equates to a
- * preset of
- * ``public_chat`` and ``private`` visibility equates to a preset of
- * ``private_chat``.
- * \param isDirect
- * This flag makes the server set the ``is_direct`` flag on the
- * ``m.room.member`` events sent to the users in ``invite`` and
- * ``invite_3pid``. See `Direct Messaging`_ for more information.
- * \param powerLevelContentOverride
- * The power level content to override in the default power level
- * event. This object is applied on top of the generated
- * `m.room.power_levels`_ event content prior to it being sent to the
- * room. Defaults to overriding nothing.
- */
- explicit CreateRoomJob(
- const QString& visibility = {},
- const QString& roomAliasName = {}, const QString& name = {},
- const QString& topic = {}, const QStringList& invite = {},
- const QVector<Invite3pid>& invite3pid = {},
- const QString& roomVersion = {},
- const QJsonObject& creationContent = {},
- const QVector<StateEvent>& initialState = {},
- const QString& preset = {}, Omittable<bool> isDirect = none,
- const QJsonObject& powerLevelContentOverride = {});
- ~CreateRoomJob() override;
+ ~CreateRoomJob() override;
- // Result properties
+ // Result properties
- /// The created room's ID.
- const QString& roomId() const;
+ /// The created room's ID.
+ const QString& roomId() const;
- protected:
- Status parseJson(const QJsonDocument& data) override;
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/auth_data.cpp b/lib/csapi/definitions/auth_data.cpp
index f40a3a90..b0303a19 100644
--- a/lib/csapi/definitions/auth_data.cpp
+++ b/lib/csapi/definitions/auth_data.cpp
@@ -4,21 +4,25 @@
#include "auth_data.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<AuthenticationData>::dumpTo(
- QJsonObject& jo, const AuthenticationData& pod)
+
+void JsonObjectConverter<AuthenticationData>::dumpTo(QJsonObject& jo, const AuthenticationData& pod)
{
fillJson(jo, pod.authInfo);
addParam<>(jo, QStringLiteral("type"), pod.type);
addParam<IfNotEmpty>(jo, QStringLiteral("session"), pod.session);
-}
-void JsonObjectConverter<AuthenticationData>::fillFrom(
- QJsonObject jo, AuthenticationData& result)
+}
+
+void JsonObjectConverter<AuthenticationData>::fillFrom(QJsonObject jo, AuthenticationData& result)
{
fromJson(jo.take("type"_ls), result.type);
fromJson(jo.take("session"_ls), result.session);
-
fromJson(jo, result.authInfo);
+
}
+
+
+
diff --git a/lib/csapi/definitions/auth_data.h b/lib/csapi/definitions/auth_data.h
index e25dff7a..689caf49 100644
--- a/lib/csapi/definitions/auth_data.h
+++ b/lib/csapi/definitions/auth_data.h
@@ -4,27 +4,37 @@
#pragma once
+
+
#include "converters.h"
-#include <QtCore/QHash>
#include <QtCore/QJsonObject>
+#include <QtCore/QHash>
+
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Used by clients to submit authentication information to the interactive-authentication API
+struct AuthenticationData
+{
+ /// The login type that the client is attempting to complete.
+ QString type;
+ /// The value of the session key given by the homeserver.
+ QString session;
+
+
+ /// Keys dependent on the login type
+ QHash<QString, QJsonObject> authInfo;
+
+};
+
+template <> struct JsonObjectConverter<AuthenticationData>
+{
+ static void dumpTo(QJsonObject& jo, const AuthenticationData& pod);
+ static void fillFrom(QJsonObject jo, AuthenticationData& pod);};
+
-namespace QMatrixClient {
- // Data structures
-
- /// Used by clients to submit authentication information to the
- /// interactive-authentication API
- struct AuthenticationData {
- /// The login type that the client is attempting to complete.
- QString type;
- /// The value of the session key given by the homeserver.
- QString session;
- /// Keys dependent on the login type
- QHash<QString, QJsonObject> authInfo;
- };
- template <> struct JsonObjectConverter<AuthenticationData> {
- static void dumpTo(QJsonObject& jo, const AuthenticationData& pod);
- static void fillFrom(QJsonObject jo, AuthenticationData& pod);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/client_device.cpp b/lib/csapi/definitions/client_device.cpp
index 2ca58e2f..5710537d 100644
--- a/lib/csapi/definitions/client_device.cpp
+++ b/lib/csapi/definitions/client_device.cpp
@@ -4,21 +4,27 @@
#include "client_device.h"
+
using namespace QMatrixClient;
+
void JsonObjectConverter<Device>::dumpTo(QJsonObject& jo, const Device& pod)
{
addParam<>(jo, QStringLiteral("device_id"), pod.deviceId);
addParam<IfNotEmpty>(jo, QStringLiteral("display_name"), pod.displayName);
addParam<IfNotEmpty>(jo, QStringLiteral("last_seen_ip"), pod.lastSeenIp);
addParam<IfNotEmpty>(jo, QStringLiteral("last_seen_ts"), pod.lastSeenTs);
-}
-void JsonObjectConverter<Device>::fillFrom(const QJsonObject& jo,
- Device& result)
+}
+
+void JsonObjectConverter<Device>::fillFrom(const QJsonObject& jo, Device& result)
{
fromJson(jo.value("device_id"_ls), result.deviceId);
fromJson(jo.value("display_name"_ls), result.displayName);
fromJson(jo.value("last_seen_ip"_ls), result.lastSeenIp);
fromJson(jo.value("last_seen_ts"_ls), result.lastSeenTs);
+
}
+
+
+
diff --git a/lib/csapi/definitions/client_device.h b/lib/csapi/definitions/client_device.h
index b473a037..7c63a9b6 100644
--- a/lib/csapi/definitions/client_device.h
+++ b/lib/csapi/definitions/client_device.h
@@ -4,31 +4,37 @@
#pragma once
+
+
#include "converters.h"
#include "converters.h"
-namespace QMatrixClient {
- // Data structures
-
- /// A client device
- struct Device {
- /// Identifier of this device.
- QString deviceId;
- /// Display name set by the user for this device. Absent if no name has
- /// been set.
- QString displayName;
- /// The IP address where this device was last seen. (May be a few
- /// minutes out of date, for efficiency reasons).
- QString lastSeenIp;
- /// The timestamp (in milliseconds since the unix epoch) when this
- /// devices was last seen. (May be a few minutes out of date, for
- /// efficiency reasons).
- Omittable<qint64> lastSeenTs;
- };
- template <> struct JsonObjectConverter<Device> {
- static void dumpTo(QJsonObject& jo, const Device& pod);
- static void fillFrom(const QJsonObject& jo, Device& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// A client device
+struct Device
+{
+ /// Identifier of this device.
+ QString deviceId;
+ /// Display name set by the user for this device. Absent if no name has beenset.
+ QString displayName;
+ /// The IP address where this device was last seen. (May be a few minutes outof date, for efficiency reasons).
+ QString lastSeenIp;
+ /// The timestamp (in milliseconds since the unix epoch) when this deviceswas last seen. (May be a few minutes out of date, for efficiencyreasons).
+ Omittable<qint64> lastSeenTs;
+
+
+};
+
+template <> struct JsonObjectConverter<Device>
+{
+ static void dumpTo(QJsonObject& jo, const Device& pod);
+ static void fillFrom(const QJsonObject& jo, Device& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/device_keys.cpp b/lib/csapi/definitions/device_keys.cpp
index cc5262b7..ffe0cfbe 100644
--- a/lib/csapi/definitions/device_keys.cpp
+++ b/lib/csapi/definitions/device_keys.cpp
@@ -4,24 +4,29 @@
#include "device_keys.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<DeviceKeys>::dumpTo(QJsonObject& jo,
- const DeviceKeys& pod)
+
+void JsonObjectConverter<DeviceKeys>::dumpTo(QJsonObject& jo, const DeviceKeys& pod)
{
addParam<>(jo, QStringLiteral("user_id"), pod.userId);
addParam<>(jo, QStringLiteral("device_id"), pod.deviceId);
addParam<>(jo, QStringLiteral("algorithms"), pod.algorithms);
addParam<>(jo, QStringLiteral("keys"), pod.keys);
addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
-}
-void JsonObjectConverter<DeviceKeys>::fillFrom(const QJsonObject& jo,
- DeviceKeys& result)
+}
+
+void JsonObjectConverter<DeviceKeys>::fillFrom(const QJsonObject& jo, DeviceKeys& result)
{
fromJson(jo.value("user_id"_ls), result.userId);
fromJson(jo.value("device_id"_ls), result.deviceId);
fromJson(jo.value("algorithms"_ls), result.algorithms);
fromJson(jo.value("keys"_ls), result.keys);
fromJson(jo.value("signatures"_ls), result.signatures);
+
}
+
+
+
diff --git a/lib/csapi/definitions/device_keys.h b/lib/csapi/definitions/device_keys.h
index 6c417ce7..c86db46a 100644
--- a/lib/csapi/definitions/device_keys.h
+++ b/lib/csapi/definitions/device_keys.h
@@ -4,38 +4,39 @@
#pragma once
+
+
#include "converters.h"
#include <QtCore/QHash>
-namespace QMatrixClient {
- // Data structures
-
- /// Device identity keys
- struct DeviceKeys {
- /// The ID of the user the device belongs to. Must match the user ID
- /// used when logging in.
- QString userId;
- /// The ID of the device these keys belong to. Must match the device ID
- /// used when logging in.
- QString deviceId;
- /// The encryption algorithms supported by this device.
- QStringList algorithms;
- /// Public identity keys. The names of the properties should be in the
- /// format ``<algorithm>:<device_id>``. The keys themselves should be
- /// encoded as specified by the key algorithm.
- QHash<QString, QString> keys;
- /// Signatures for the device key object. A map from user ID, to a map
- /// from
- /// ``<algorithm>:<device_id>`` to the signature.
- ///
- /// The signature is calculated using the process described at `Signing
- /// JSON`_.
- QHash<QString, QHash<QString, QString>> signatures;
- };
- template <> struct JsonObjectConverter<DeviceKeys> {
- static void dumpTo(QJsonObject& jo, const DeviceKeys& pod);
- static void fillFrom(const QJsonObject& jo, DeviceKeys& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Device identity keys
+struct DeviceKeys
+{
+ /// The ID of the user the device belongs to. Must match the user ID usedwhen logging in.
+ QString userId;
+ /// The ID of the device these keys belong to. Must match the device ID usedwhen logging in.
+ QString deviceId;
+ /// The encryption algorithms supported by this device.
+ QStringList algorithms;
+ /// Public identity keys. The names of the properties should be in theformat ``<algorithm>:<device_id>``. The keys themselves should beencoded as specified by the key algorithm.
+ QHash<QString, QString> keys;
+ /// Signatures for the device key object. A map from user ID, to a map from``<algorithm>:<device_id>`` to the signature.The signature is calculated using the process described at `SigningJSON`_.
+ QHash<QString, QHash<QString, QString>> signatures;
+
+
+};
+
+template <> struct JsonObjectConverter<DeviceKeys>
+{
+ static void dumpTo(QJsonObject& jo, const DeviceKeys& pod);
+ static void fillFrom(const QJsonObject& jo, DeviceKeys& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/event_filter.cpp b/lib/csapi/definitions/event_filter.cpp
index 9b2c7a33..8be98c94 100644
--- a/lib/csapi/definitions/event_filter.cpp
+++ b/lib/csapi/definitions/event_filter.cpp
@@ -4,24 +4,29 @@
#include "event_filter.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<EventFilter>::dumpTo(QJsonObject& jo,
- const EventFilter& pod)
+
+void JsonObjectConverter<EventFilter>::dumpTo(QJsonObject& jo, const EventFilter& pod)
{
addParam<IfNotEmpty>(jo, QStringLiteral("limit"), pod.limit);
addParam<IfNotEmpty>(jo, QStringLiteral("not_senders"), pod.notSenders);
addParam<IfNotEmpty>(jo, QStringLiteral("not_types"), pod.notTypes);
addParam<IfNotEmpty>(jo, QStringLiteral("senders"), pod.senders);
addParam<IfNotEmpty>(jo, QStringLiteral("types"), pod.types);
-}
-void JsonObjectConverter<EventFilter>::fillFrom(const QJsonObject& jo,
- EventFilter& result)
+}
+
+void JsonObjectConverter<EventFilter>::fillFrom(const QJsonObject& jo, EventFilter& result)
{
fromJson(jo.value("limit"_ls), result.limit);
fromJson(jo.value("not_senders"_ls), result.notSenders);
fromJson(jo.value("not_types"_ls), result.notTypes);
fromJson(jo.value("senders"_ls), result.senders);
fromJson(jo.value("types"_ls), result.types);
+
}
+
+
+
diff --git a/lib/csapi/definitions/event_filter.h b/lib/csapi/definitions/event_filter.h
index 5a1a831b..b8b2a983 100644
--- a/lib/csapi/definitions/event_filter.h
+++ b/lib/csapi/definitions/event_filter.h
@@ -4,36 +4,39 @@
#pragma once
+
+
#include "converters.h"
#include "converters.h"
-namespace QMatrixClient {
- // Data structures
-
- struct EventFilter {
- /// The maximum number of events to return.
- Omittable<int> limit;
- /// A list of sender IDs to exclude. If this list is absent then no
- /// senders are excluded. A matching sender will be excluded even if it
- /// is listed in the ``'senders'`` filter.
- QStringList notSenders;
- /// A list of event types to exclude. If this list is absent then no
- /// event types are excluded. A matching type will be excluded even if
- /// it is listed in the ``'types'`` filter. A '*' can be used as a
- /// wildcard to match any sequence of characters.
- QStringList notTypes;
- /// A list of senders IDs to include. If this list is absent then all
- /// senders are included.
- QStringList senders;
- /// A list of event types to include. If this list is absent then all
- /// event types are included. A ``'*'`` can be used as a wildcard to
- /// match any sequence of characters.
- QStringList types;
- };
- template <> struct JsonObjectConverter<EventFilter> {
- static void dumpTo(QJsonObject& jo, const EventFilter& pod);
- static void fillFrom(const QJsonObject& jo, EventFilter& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+
+struct EventFilter
+{
+ /// The maximum number of events to return.
+ Omittable<int> limit;
+ /// A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the ``'senders'`` filter.
+ QStringList notSenders;
+ /// A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the ``'types'`` filter. A '*' can be used as a wildcard to match any sequence of characters.
+ QStringList notTypes;
+ /// A list of senders IDs to include. If this list is absent then all senders are included.
+ QStringList senders;
+ /// A list of event types to include. If this list is absent then all event types are included. A ``'*'`` can be used as a wildcard to match any sequence of characters.
+ QStringList types;
+
+
+};
+
+template <> struct JsonObjectConverter<EventFilter>
+{
+ static void dumpTo(QJsonObject& jo, const EventFilter& pod);
+ static void fillFrom(const QJsonObject& jo, EventFilter& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/public_rooms_response.cpp b/lib/csapi/definitions/public_rooms_response.cpp
index 199a7a93..2c03b7d3 100644
--- a/lib/csapi/definitions/public_rooms_response.cpp
+++ b/lib/csapi/definitions/public_rooms_response.cpp
@@ -4,14 +4,14 @@
#include "public_rooms_response.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<PublicRoomsChunk>::dumpTo(QJsonObject& jo,
- const PublicRoomsChunk& pod)
+
+void JsonObjectConverter<PublicRoomsChunk>::dumpTo(QJsonObject& jo, const PublicRoomsChunk& pod)
{
addParam<IfNotEmpty>(jo, QStringLiteral("aliases"), pod.aliases);
- addParam<IfNotEmpty>(jo, QStringLiteral("canonical_alias"),
- pod.canonicalAlias);
+ addParam<IfNotEmpty>(jo, QStringLiteral("canonical_alias"), pod.canonicalAlias);
addParam<IfNotEmpty>(jo, QStringLiteral("name"), pod.name);
addParam<>(jo, QStringLiteral("num_joined_members"), pod.numJoinedMembers);
addParam<>(jo, QStringLiteral("room_id"), pod.roomId);
@@ -19,10 +19,10 @@ void JsonObjectConverter<PublicRoomsChunk>::dumpTo(QJsonObject& jo,
addParam<>(jo, QStringLiteral("world_readable"), pod.worldReadable);
addParam<>(jo, QStringLiteral("guest_can_join"), pod.guestCanJoin);
addParam<IfNotEmpty>(jo, QStringLiteral("avatar_url"), pod.avatarUrl);
-}
-void JsonObjectConverter<PublicRoomsChunk>::fillFrom(const QJsonObject& jo,
- PublicRoomsChunk& result)
+}
+
+void JsonObjectConverter<PublicRoomsChunk>::fillFrom(const QJsonObject& jo, PublicRoomsChunk& result)
{
fromJson(jo.value("aliases"_ls), result.aliases);
fromJson(jo.value("canonical_alias"_ls), result.canonicalAlias);
@@ -33,24 +33,28 @@ void JsonObjectConverter<PublicRoomsChunk>::fillFrom(const QJsonObject& jo,
fromJson(jo.value("world_readable"_ls), result.worldReadable);
fromJson(jo.value("guest_can_join"_ls), result.guestCanJoin);
fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
+
}
+
-void JsonObjectConverter<PublicRoomsResponse>::dumpTo(
- QJsonObject& jo, const PublicRoomsResponse& pod)
+
+void JsonObjectConverter<PublicRoomsResponse>::dumpTo(QJsonObject& jo, const PublicRoomsResponse& pod)
{
addParam<>(jo, QStringLiteral("chunk"), pod.chunk);
addParam<IfNotEmpty>(jo, QStringLiteral("next_batch"), pod.nextBatch);
addParam<IfNotEmpty>(jo, QStringLiteral("prev_batch"), pod.prevBatch);
- addParam<IfNotEmpty>(jo, QStringLiteral("total_room_count_estimate"),
- pod.totalRoomCountEstimate);
-}
+ addParam<IfNotEmpty>(jo, QStringLiteral("total_room_count_estimate"), pod.totalRoomCountEstimate);
-void JsonObjectConverter<PublicRoomsResponse>::fillFrom(
- const QJsonObject& jo, PublicRoomsResponse& result)
+}
+
+void JsonObjectConverter<PublicRoomsResponse>::fillFrom(const QJsonObject& jo, PublicRoomsResponse& result)
{
fromJson(jo.value("chunk"_ls), result.chunk);
fromJson(jo.value("next_batch"_ls), result.nextBatch);
fromJson(jo.value("prev_batch"_ls), result.prevBatch);
- fromJson(jo.value("total_room_count_estimate"_ls),
- result.totalRoomCountEstimate);
+ fromJson(jo.value("total_room_count_estimate"_ls), result.totalRoomCountEstimate);
+
}
+
+
+
diff --git a/lib/csapi/definitions/public_rooms_response.h b/lib/csapi/definitions/public_rooms_response.h
index 6d8caf98..d282a592 100644
--- a/lib/csapi/definitions/public_rooms_response.h
+++ b/lib/csapi/definitions/public_rooms_response.h
@@ -4,60 +4,68 @@
#pragma once
+
+
#include "converters.h"
#include "converters.h"
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Data structures
-
- struct PublicRoomsChunk {
- /// Aliases of the room. May be empty.
- QStringList aliases;
- /// The canonical alias of the room, if any.
- QString canonicalAlias;
- /// The name of the room, if any.
- QString name;
- /// The number of members joined to the room.
- int numJoinedMembers;
- /// The ID of the room.
- QString roomId;
- /// The topic of the room, if any.
- QString topic;
- /// Whether the room may be viewed by guest users without joining.
- bool worldReadable;
- /// Whether guest users may join the room and participate in it.
- /// If they can, they will be subject to ordinary power level
- /// rules like any other user.
- bool guestCanJoin;
- /// The URL for the room's avatar, if one is set.
- QString avatarUrl;
- };
- template <> struct JsonObjectConverter<PublicRoomsChunk> {
- static void dumpTo(QJsonObject& jo, const PublicRoomsChunk& pod);
- static void fillFrom(const QJsonObject& jo, PublicRoomsChunk& pod);
- };
-
- /// A list of the rooms on the server.
- struct PublicRoomsResponse {
- /// A paginated chunk of public rooms.
- QVector<PublicRoomsChunk> chunk;
- /// 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;
- /// 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;
- /// An estimate on the total number of public rooms, if the
- /// server has an estimate.
- Omittable<int> totalRoomCountEstimate;
- };
- template <> struct JsonObjectConverter<PublicRoomsResponse> {
- static void dumpTo(QJsonObject& jo, const PublicRoomsResponse& pod);
- static void fillFrom(const QJsonObject& jo, PublicRoomsResponse& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+
+struct PublicRoomsChunk
+{
+ /// Aliases of the room. May be empty.
+ QStringList aliases;
+ /// The canonical alias of the room, if any.
+ QString canonicalAlias;
+ /// The name of the room, if any.
+ QString name;
+ /// The number of members joined to the room.
+ int numJoinedMembers;
+ /// The ID of the room.
+ QString roomId;
+ /// The topic of the room, if any.
+ QString topic;
+ /// Whether the room may be viewed by guest users without joining.
+ bool worldReadable;
+ /// Whether guest users may join the room and participate in it.If they can, they will be subject to ordinary power levelrules like any other user.
+ bool guestCanJoin;
+ /// The URL for the room's avatar, if one is set.
+ QString avatarUrl;
+
+
+};
+
+template <> struct JsonObjectConverter<PublicRoomsChunk>
+{
+ static void dumpTo(QJsonObject& jo, const PublicRoomsChunk& pod);
+ static void fillFrom(const QJsonObject& jo, PublicRoomsChunk& pod);};
+
+/// A list of the rooms on the server.
+struct PublicRoomsResponse
+{
+ /// A paginated chunk of public rooms.
+ QVector<PublicRoomsChunk> chunk;
+ /// A pagination token for the response. The absence of this tokenmeans there are no more results to fetch and the client shouldstop paginating.
+ QString nextBatch;
+ /// A pagination token that allows fetching previous results. Theabsence of this token means there are no results before thisbatch, i.e. this is the first batch.
+ QString prevBatch;
+ /// An estimate on the total number of public rooms, if theserver has an estimate.
+ Omittable<int> totalRoomCountEstimate;
+
+
+};
+
+template <> struct JsonObjectConverter<PublicRoomsResponse>
+{
+ static void dumpTo(QJsonObject& jo, const PublicRoomsResponse& pod);
+ static void fillFrom(const QJsonObject& jo, PublicRoomsResponse& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/push_condition.cpp b/lib/csapi/definitions/push_condition.cpp
index 5bcb845e..86b3107e 100644
--- a/lib/csapi/definitions/push_condition.cpp
+++ b/lib/csapi/definitions/push_condition.cpp
@@ -4,22 +4,27 @@
#include "push_condition.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<PushCondition>::dumpTo(QJsonObject& jo,
- const PushCondition& pod)
+
+void JsonObjectConverter<PushCondition>::dumpTo(QJsonObject& jo, const PushCondition& pod)
{
addParam<>(jo, QStringLiteral("kind"), pod.kind);
addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key);
addParam<IfNotEmpty>(jo, QStringLiteral("pattern"), pod.pattern);
addParam<IfNotEmpty>(jo, QStringLiteral("is"), pod.is);
-}
-void JsonObjectConverter<PushCondition>::fillFrom(const QJsonObject& jo,
- PushCondition& result)
+}
+
+void JsonObjectConverter<PushCondition>::fillFrom(const QJsonObject& jo, PushCondition& result)
{
fromJson(jo.value("kind"_ls), result.kind);
fromJson(jo.value("key"_ls), result.key);
fromJson(jo.value("pattern"_ls), result.pattern);
fromJson(jo.value("is"_ls), result.is);
+
}
+
+
+
diff --git a/lib/csapi/definitions/push_condition.h b/lib/csapi/definitions/push_condition.h
index a4e44e93..e61fb24e 100644
--- a/lib/csapi/definitions/push_condition.h
+++ b/lib/csapi/definitions/push_condition.h
@@ -4,31 +4,36 @@
#pragma once
+
+
#include "converters.h"
-namespace QMatrixClient {
- // Data structures
-
- struct PushCondition {
- QString kind;
- /// Required for ``event_match`` conditions. The dot-separated field of
- /// the event to match.
- QString key;
- /// Required for ``event_match`` conditions. The glob-style pattern to
- /// match against. Patterns with no special glob characters should be
- /// treated as having asterisks prepended and appended when testing the
- /// condition.
- QString pattern;
- /// Required for ``room_member_count`` conditions. A decimal integer
- /// optionally prefixed by one of, ==, <, >, >= or <=. A prefix of <
- /// matches rooms where the member count is strictly less than the given
- /// number and so forth. If no prefix is present, this parameter
- /// defaults to ==.
- QString is;
- };
- template <> struct JsonObjectConverter<PushCondition> {
- static void dumpTo(QJsonObject& jo, const PushCondition& pod);
- static void fillFrom(const QJsonObject& jo, PushCondition& pod);
- };
+
+namespace QMatrixClient
+{
+
+// Data structures
+
+
+struct PushCondition
+{
+
+ QString kind;
+ /// Required for ``event_match`` conditions. The dot-separated field of theevent to match.
+ QString key;
+ /// Required for ``event_match`` conditions. The glob-style pattern tomatch against. Patterns with no special glob characters should betreated as having asterisks prepended and appended when testing thecondition.
+ QString pattern;
+ /// Required for ``room_member_count`` conditions. A decimal integeroptionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matchesrooms where the member count is strictly less than the given number andso forth. If no prefix is present, this parameter defaults to ==.
+ QString is;
+
+
+};
+
+template <> struct JsonObjectConverter<PushCondition>
+{
+ static void dumpTo(QJsonObject& jo, const PushCondition& pod);
+ static void fillFrom(const QJsonObject& jo, PushCondition& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/push_rule.cpp b/lib/csapi/definitions/push_rule.cpp
index fc2be2c7..bfa8a7ef 100644
--- a/lib/csapi/definitions/push_rule.cpp
+++ b/lib/csapi/definitions/push_rule.cpp
@@ -4,8 +4,10 @@
#include "push_rule.h"
+
using namespace QMatrixClient;
+
void JsonObjectConverter<PushRule>::dumpTo(QJsonObject& jo, const PushRule& pod)
{
addParam<>(jo, QStringLiteral("actions"), pod.actions);
@@ -14,10 +16,10 @@ void JsonObjectConverter<PushRule>::dumpTo(QJsonObject& jo, const PushRule& pod)
addParam<>(jo, QStringLiteral("rule_id"), pod.ruleId);
addParam<IfNotEmpty>(jo, QStringLiteral("conditions"), pod.conditions);
addParam<IfNotEmpty>(jo, QStringLiteral("pattern"), pod.pattern);
-}
-void JsonObjectConverter<PushRule>::fillFrom(const QJsonObject& jo,
- PushRule& result)
+}
+
+void JsonObjectConverter<PushRule>::fillFrom(const QJsonObject& jo, PushRule& result)
{
fromJson(jo.value("actions"_ls), result.actions);
fromJson(jo.value("default"_ls), result.isDefault);
@@ -25,4 +27,8 @@ void JsonObjectConverter<PushRule>::fillFrom(const QJsonObject& jo,
fromJson(jo.value("rule_id"_ls), result.ruleId);
fromJson(jo.value("conditions"_ls), result.conditions);
fromJson(jo.value("pattern"_ls), result.pattern);
+
}
+
+
+
diff --git a/lib/csapi/definitions/push_rule.h b/lib/csapi/definitions/push_rule.h
index d8d2cc0f..98bd904d 100644
--- a/lib/csapi/definitions/push_rule.h
+++ b/lib/csapi/definitions/push_rule.h
@@ -4,37 +4,45 @@
#pragma once
+
+
#include "converters.h"
#include "converters.h"
+#include <QtCore/QVariant>
#include "csapi/definitions/push_condition.h"
#include <QtCore/QJsonObject>
-#include <QtCore/QVariant>
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Data structures
-
- struct PushRule {
- /// The actions to perform when this rule is matched.
- QVector<QVariant> actions;
- /// Whether this is a default rule, or has been set explicitly.
- bool isDefault;
- /// Whether the push rule is enabled or not.
- bool enabled;
- /// The ID of this rule.
- QString ruleId;
- /// The conditions that must hold true for an event in order for a rule
- /// to be applied to an event. A rule with no conditions always matches.
- /// Only applicable to ``underride`` and ``override`` rules.
- QVector<PushCondition> conditions;
- /// The glob-style pattern to match against. Only applicable to
- /// ``content`` rules.
- QString pattern;
- };
- template <> struct JsonObjectConverter<PushRule> {
- static void dumpTo(QJsonObject& jo, const PushRule& pod);
- static void fillFrom(const QJsonObject& jo, PushRule& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+
+struct PushRule
+{
+ /// The actions to perform when this rule is matched.
+ QVector<QVariant> actions;
+ /// Whether this is a default rule, or has been set explicitly.
+ bool isDefault;
+ /// Whether the push rule is enabled or not.
+ bool enabled;
+ /// The ID of this rule.
+ QString ruleId;
+ /// The conditions that must hold true for an event in order for a rule to beapplied to an event. A rule with no conditions always matches. Onlyapplicable to ``underride`` and ``override`` rules.
+ QVector<PushCondition> conditions;
+ /// The glob-style pattern to match against. Only applicable to ``content``rules.
+ QString pattern;
+
+
+};
+
+template <> struct JsonObjectConverter<PushRule>
+{
+ static void dumpTo(QJsonObject& jo, const PushRule& pod);
+ static void fillFrom(const QJsonObject& jo, PushRule& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/push_ruleset.cpp b/lib/csapi/definitions/push_ruleset.cpp
index 6f48d27b..4754e07b 100644
--- a/lib/csapi/definitions/push_ruleset.cpp
+++ b/lib/csapi/definitions/push_ruleset.cpp
@@ -4,24 +4,29 @@
#include "push_ruleset.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<PushRuleset>::dumpTo(QJsonObject& jo,
- const PushRuleset& pod)
+
+void JsonObjectConverter<PushRuleset>::dumpTo(QJsonObject& jo, const PushRuleset& pod)
{
addParam<IfNotEmpty>(jo, QStringLiteral("content"), pod.content);
addParam<IfNotEmpty>(jo, QStringLiteral("override"), pod.override);
addParam<IfNotEmpty>(jo, QStringLiteral("room"), pod.room);
addParam<IfNotEmpty>(jo, QStringLiteral("sender"), pod.sender);
addParam<IfNotEmpty>(jo, QStringLiteral("underride"), pod.underride);
-}
-void JsonObjectConverter<PushRuleset>::fillFrom(const QJsonObject& jo,
- PushRuleset& result)
+}
+
+void JsonObjectConverter<PushRuleset>::fillFrom(const QJsonObject& jo, PushRuleset& result)
{
fromJson(jo.value("content"_ls), result.content);
fromJson(jo.value("override"_ls), result.override);
fromJson(jo.value("room"_ls), result.room);
fromJson(jo.value("sender"_ls), result.sender);
fromJson(jo.value("underride"_ls), result.underride);
+
}
+
+
+
diff --git a/lib/csapi/definitions/push_ruleset.h b/lib/csapi/definitions/push_ruleset.h
index b2f791c4..e1a2c142 100644
--- a/lib/csapi/definitions/push_ruleset.h
+++ b/lib/csapi/definitions/push_ruleset.h
@@ -4,25 +4,41 @@
#pragma once
-#include "converters.h"
+
#include "converters.h"
+
#include "csapi/definitions/push_rule.h"
+#include "converters.h"
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Data structures
-
- struct PushRuleset {
- QVector<PushRule> content;
- QVector<PushRule> override;
- QVector<PushRule> room;
- QVector<PushRule> sender;
- QVector<PushRule> underride;
- };
- template <> struct JsonObjectConverter<PushRuleset> {
- static void dumpTo(QJsonObject& jo, const PushRuleset& pod);
- static void fillFrom(const QJsonObject& jo, PushRuleset& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+
+struct PushRuleset
+{
+
+ QVector<PushRule> content;
+
+ QVector<PushRule> override;
+
+ QVector<PushRule> room;
+
+ QVector<PushRule> sender;
+
+ QVector<PushRule> underride;
+
+
+};
+
+template <> struct JsonObjectConverter<PushRuleset>
+{
+ static void dumpTo(QJsonObject& jo, const PushRuleset& pod);
+ static void fillFrom(const QJsonObject& jo, PushRuleset& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/room_event_filter.cpp b/lib/csapi/definitions/room_event_filter.cpp
index bd38ebc7..fc859395 100644
--- a/lib/csapi/definitions/room_event_filter.cpp
+++ b/lib/csapi/definitions/room_event_filter.cpp
@@ -4,22 +4,27 @@
#include "room_event_filter.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<RoomEventFilter>::dumpTo(QJsonObject& jo,
- const RoomEventFilter& pod)
+
+void JsonObjectConverter<RoomEventFilter>::dumpTo(QJsonObject& jo, const RoomEventFilter& pod)
{
fillJson<EventFilter>(jo, pod);
addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
addParam<IfNotEmpty>(jo, QStringLiteral("contains_url"), pod.containsUrl);
-}
-void JsonObjectConverter<RoomEventFilter>::fillFrom(const QJsonObject& jo,
- RoomEventFilter& result)
+}
+
+void JsonObjectConverter<RoomEventFilter>::fillFrom(const QJsonObject& jo, RoomEventFilter& result)
{
fillFromJson<EventFilter>(jo, result);
fromJson(jo.value("not_rooms"_ls), result.notRooms);
fromJson(jo.value("rooms"_ls), result.rooms);
fromJson(jo.value("contains_url"_ls), result.containsUrl);
+
}
+
+
+
diff --git a/lib/csapi/definitions/room_event_filter.h b/lib/csapi/definitions/room_event_filter.h
index 13c82341..92e210fe 100644
--- a/lib/csapi/definitions/room_event_filter.h
+++ b/lib/csapi/definitions/room_event_filter.h
@@ -4,30 +4,36 @@
#pragma once
-#include "converters.h"
+
#include "converters.h"
+
#include "csapi/definitions/event_filter.h"
+#include "converters.h"
+
+namespace QMatrixClient
+{
+
+// Data structures
+
+
+struct RoomEventFilter : EventFilter
+{
+ /// A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the ``'rooms'`` filter.
+ QStringList notRooms;
+ /// A list of room IDs to include. If this list is absent then all rooms are included.
+ QStringList rooms;
+ /// If ``true``, includes only events with a ``url`` key in their content. If ``false``, excludes those events. If omitted, ``url`` key is not considered for filtering.
+ Omittable<bool> containsUrl;
+
+
+};
+
+template <> struct JsonObjectConverter<RoomEventFilter>
+{
+ static void dumpTo(QJsonObject& jo, const RoomEventFilter& pod);
+ static void fillFrom(const QJsonObject& jo, RoomEventFilter& pod);};
+
-namespace QMatrixClient {
- // Data structures
-
- struct RoomEventFilter : EventFilter {
- /// A list of room IDs to exclude. If this list is absent then no rooms
- /// are excluded. A matching room will be excluded even if it is listed
- /// in the ``'rooms'`` filter.
- QStringList notRooms;
- /// A list of room IDs to include. If this list is absent then all rooms
- /// are included.
- QStringList rooms;
- /// If ``true``, includes only events with a ``url`` key in their
- /// content. If ``false``, excludes those events. If omitted, ``url``
- /// key is not considered for filtering.
- Omittable<bool> containsUrl;
- };
- template <> struct JsonObjectConverter<RoomEventFilter> {
- static void dumpTo(QJsonObject& jo, const RoomEventFilter& pod);
- static void fillFrom(const QJsonObject& jo, RoomEventFilter& pod);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/sync_filter.cpp b/lib/csapi/definitions/sync_filter.cpp
index c06c16ca..a1ef53c5 100644
--- a/lib/csapi/definitions/sync_filter.cpp
+++ b/lib/csapi/definitions/sync_filter.cpp
@@ -4,29 +4,29 @@
#include "sync_filter.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<StateFilter>::dumpTo(QJsonObject& jo,
- const StateFilter& pod)
+
+void JsonObjectConverter<StateFilter>::dumpTo(QJsonObject& jo, const StateFilter& pod)
{
fillJson<RoomEventFilter>(jo, pod);
- addParam<IfNotEmpty>(jo, QStringLiteral("lazy_load_members"),
- pod.lazyLoadMembers);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_redundant_members"),
- pod.includeRedundantMembers);
-}
+ addParam<IfNotEmpty>(jo, QStringLiteral("lazy_load_members"), pod.lazyLoadMembers);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_redundant_members"), pod.includeRedundantMembers);
-void JsonObjectConverter<StateFilter>::fillFrom(const QJsonObject& jo,
- StateFilter& result)
+}
+
+void JsonObjectConverter<StateFilter>::fillFrom(const QJsonObject& jo, StateFilter& result)
{
fillFromJson<RoomEventFilter>(jo, result);
fromJson(jo.value("lazy_load_members"_ls), result.lazyLoadMembers);
- fromJson(jo.value("include_redundant_members"_ls),
- result.includeRedundantMembers);
+ fromJson(jo.value("include_redundant_members"_ls), result.includeRedundantMembers);
+
}
+
-void JsonObjectConverter<RoomFilter>::dumpTo(QJsonObject& jo,
- const RoomFilter& pod)
+
+void JsonObjectConverter<RoomFilter>::dumpTo(QJsonObject& jo, const RoomFilter& pod)
{
addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
@@ -35,10 +35,10 @@ void JsonObjectConverter<RoomFilter>::dumpTo(QJsonObject& jo,
addParam<IfNotEmpty>(jo, QStringLiteral("state"), pod.state);
addParam<IfNotEmpty>(jo, QStringLiteral("timeline"), pod.timeline);
addParam<IfNotEmpty>(jo, QStringLiteral("account_data"), pod.accountData);
-}
-void JsonObjectConverter<RoomFilter>::fillFrom(const QJsonObject& jo,
- RoomFilter& result)
+}
+
+void JsonObjectConverter<RoomFilter>::fillFrom(const QJsonObject& jo, RoomFilter& result)
{
fromJson(jo.value("not_rooms"_ls), result.notRooms);
fromJson(jo.value("rooms"_ls), result.rooms);
@@ -47,8 +47,11 @@ void JsonObjectConverter<RoomFilter>::fillFrom(const QJsonObject& jo,
fromJson(jo.value("state"_ls), result.state);
fromJson(jo.value("timeline"_ls), result.timeline);
fromJson(jo.value("account_data"_ls), result.accountData);
+
}
+
+
void JsonObjectConverter<Filter>::dumpTo(QJsonObject& jo, const Filter& pod)
{
addParam<IfNotEmpty>(jo, QStringLiteral("event_fields"), pod.eventFields);
@@ -56,14 +59,18 @@ void JsonObjectConverter<Filter>::dumpTo(QJsonObject& jo, const Filter& pod)
addParam<IfNotEmpty>(jo, QStringLiteral("presence"), pod.presence);
addParam<IfNotEmpty>(jo, QStringLiteral("account_data"), pod.accountData);
addParam<IfNotEmpty>(jo, QStringLiteral("room"), pod.room);
-}
-void JsonObjectConverter<Filter>::fillFrom(const QJsonObject& jo,
- Filter& result)
+}
+
+void JsonObjectConverter<Filter>::fillFrom(const QJsonObject& jo, Filter& result)
{
fromJson(jo.value("event_fields"_ls), result.eventFields);
fromJson(jo.value("event_format"_ls), result.eventFormat);
fromJson(jo.value("presence"_ls), result.presence);
fromJson(jo.value("account_data"_ls), result.accountData);
fromJson(jo.value("room"_ls), result.room);
+
}
+
+
+
diff --git a/lib/csapi/definitions/sync_filter.h b/lib/csapi/definitions/sync_filter.h
index d523c388..551ba2fd 100644
--- a/lib/csapi/definitions/sync_filter.h
+++ b/lib/csapi/definitions/sync_filter.h
@@ -4,94 +4,83 @@
#pragma once
-#include "converters.h"
+
#include "converters.h"
+
#include "csapi/definitions/event_filter.h"
+#include "converters.h"
#include "csapi/definitions/room_event_filter.h"
-namespace QMatrixClient {
- // Data structures
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// The state events to include for rooms.
+struct StateFilter : RoomEventFilter
+{
+ /// If ``true``, the only ``m.room.member`` events returned inthe ``state`` section of the ``/sync`` response are thosewhich are definitely necessary for a client to displaythe ``sender`` of the timeline events in that response.If ``false``, ``m.room.member`` events are not filtered.By default, servers should suppress duplicate redundantlazy-loaded ``m.room.member`` events from being sent to a givenclient across multiple calls to ``/sync``, given that most clientscache membership events (see ``include_redundant_members``to change this behaviour).
+ Omittable<bool> lazyLoadMembers;
+ /// If ``true``, the ``state`` section of the ``/sync`` response willalways contain the ``m.room.member`` events required to displaythe ``sender`` of the timeline events in that response, assuming``lazy_load_members`` is enabled. This means that redundantduplicate member events may be returned across multiple calls to``/sync``. This is useful for naive clients who never trackmembership data. If ``false``, duplicate ``m.room.member`` eventsmay be suppressed by the server across multiple calls to ``/sync``.If ``lazy_load_members`` is ``false`` this field is ignored.
+ Omittable<bool> includeRedundantMembers;
+
+
+};
+
+template <> struct JsonObjectConverter<StateFilter>
+{
+ static void dumpTo(QJsonObject& jo, const StateFilter& pod);
+ static void fillFrom(const QJsonObject& jo, StateFilter& pod);};
+/// Filters to be applied to room data.
+struct RoomFilter
+{
+ /// A list of room IDs to exclude. If this list is absent then no rooms are excluded. A matching room will be excluded even if it is listed in the ``'rooms'`` filter. This filter is applied before the filters in ``ephemeral``, ``state``, ``timeline`` or ``account_data``
+ QStringList notRooms;
+ /// A list of room IDs to include. If this list is absent then all rooms are included. This filter is applied before the filters in ``ephemeral``, ``state``, ``timeline`` or ``account_data``
+ QStringList rooms;
+ /// The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms.
+ Omittable<RoomEventFilter> ephemeral;
+ /// Include rooms that the user has left in the sync, default false
+ Omittable<bool> includeLeave;
/// The state events to include for rooms.
- struct StateFilter : RoomEventFilter {
- /// If ``true``, the only ``m.room.member`` events returned in
- /// the ``state`` section of the ``/sync`` response are those
- /// which are definitely necessary for a client to display
- /// the ``sender`` of the timeline events in that response.
- /// If ``false``, ``m.room.member`` events are not filtered.
- /// By default, servers should suppress duplicate redundant
- /// lazy-loaded ``m.room.member`` events from being sent to a given
- /// client across multiple calls to ``/sync``, given that most clients
- /// cache membership events (see ``include_redundant_members``
- /// to change this behaviour).
- Omittable<bool> lazyLoadMembers;
- /// If ``true``, the ``state`` section of the ``/sync`` response will
- /// always contain the ``m.room.member`` events required to display
- /// the ``sender`` of the timeline events in that response, assuming
- /// ``lazy_load_members`` is enabled. This means that redundant
- /// duplicate member events may be returned across multiple calls to
- /// ``/sync``. This is useful for naive clients who never track
- /// membership data. If ``false``, duplicate ``m.room.member`` events
- /// may be suppressed by the server across multiple calls to ``/sync``.
- /// If ``lazy_load_members`` is ``false`` this field is ignored.
- Omittable<bool> includeRedundantMembers;
- };
- template <> struct JsonObjectConverter<StateFilter> {
- static void dumpTo(QJsonObject& jo, const StateFilter& pod);
- static void fillFrom(const QJsonObject& jo, StateFilter& pod);
- };
+ Omittable<StateFilter> state;
+ /// The message and state update events to include for rooms.
+ Omittable<RoomEventFilter> timeline;
+ /// The per user account data to include for rooms.
+ Omittable<RoomEventFilter> accountData;
+
+};
+
+template <> struct JsonObjectConverter<RoomFilter>
+{
+ static void dumpTo(QJsonObject& jo, const RoomFilter& pod);
+ static void fillFrom(const QJsonObject& jo, RoomFilter& pod);};
+
+
+struct Filter
+{
+ /// List of event fields to include. If this list is absent then all fields are included. The entries may include '.' charaters to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' object. A literal '.' character in a field name may be escaped using a '\\'. A server may include more fields than were requested.
+ QStringList eventFields;
+ /// The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as receieved over federation. The default is 'client'.
+ QString eventFormat;
+ /// The presence updates to include.
+ Omittable<EventFilter> presence;
+ /// The user account data that isn't associated with rooms to include.
+ Omittable<EventFilter> accountData;
/// Filters to be applied to room data.
- struct RoomFilter {
- /// A list of room IDs to exclude. If this list is absent then no rooms
- /// are excluded. A matching room will be excluded even if it is listed
- /// in the ``'rooms'`` filter. This filter is applied before the filters
- /// in ``ephemeral``, ``state``, ``timeline`` or ``account_data``
- QStringList notRooms;
- /// A list of room IDs to include. If this list is absent then all rooms
- /// are included. This filter is applied before the filters in
- /// ``ephemeral``, ``state``, ``timeline`` or ``account_data``
- QStringList rooms;
- /// The events that aren't recorded in the room history, e.g. typing and
- /// receipts, to include for rooms.
- Omittable<RoomEventFilter> ephemeral;
- /// Include rooms that the user has left in the sync, default false
- Omittable<bool> includeLeave;
- /// The state events to include for rooms.
- Omittable<StateFilter> state;
- /// The message and state update events to include for rooms.
- Omittable<RoomEventFilter> timeline;
- /// The per user account data to include for rooms.
- Omittable<RoomEventFilter> accountData;
- };
- template <> struct JsonObjectConverter<RoomFilter> {
- static void dumpTo(QJsonObject& jo, const RoomFilter& pod);
- static void fillFrom(const QJsonObject& jo, RoomFilter& pod);
- };
-
- struct Filter {
- /// List of event fields to include. If this list is absent then all
- /// fields are included. The entries may include '.' charaters to
- /// indicate sub-fields. So ['content.body'] will include the 'body'
- /// field of the 'content' object. A literal '.' character in a field
- /// name may be escaped using a '\\'. A server may include more fields
- /// than were requested.
- QStringList eventFields;
- /// The format to use for events. 'client' will return the events in a
- /// format suitable for clients. 'federation' will return the raw event
- /// as receieved over federation. The default is 'client'.
- QString eventFormat;
- /// The presence updates to include.
- Omittable<EventFilter> presence;
- /// The user account data that isn't associated with rooms to include.
- Omittable<EventFilter> accountData;
- /// Filters to be applied to room data.
- Omittable<RoomFilter> room;
- };
- template <> struct JsonObjectConverter<Filter> {
- static void dumpTo(QJsonObject& jo, const Filter& pod);
- static void fillFrom(const QJsonObject& jo, Filter& pod);
- };
+ Omittable<RoomFilter> room;
+
+
+};
+
+template <> struct JsonObjectConverter<Filter>
+{
+ static void dumpTo(QJsonObject& jo, const Filter& pod);
+ static void fillFrom(const QJsonObject& jo, Filter& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/user_identifier.cpp b/lib/csapi/definitions/user_identifier.cpp
index 998f1b85..02201179 100644
--- a/lib/csapi/definitions/user_identifier.cpp
+++ b/lib/csapi/definitions/user_identifier.cpp
@@ -4,19 +4,23 @@
#include "user_identifier.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<UserIdentifier>::dumpTo(QJsonObject& jo,
- const UserIdentifier& pod)
+
+void JsonObjectConverter<UserIdentifier>::dumpTo(QJsonObject& jo, const UserIdentifier& pod)
{
fillJson(jo, pod.additionalProperties);
addParam<>(jo, QStringLiteral("type"), pod.type);
-}
-void JsonObjectConverter<UserIdentifier>::fillFrom(QJsonObject jo,
- UserIdentifier& result)
+}
+
+void JsonObjectConverter<UserIdentifier>::fillFrom(QJsonObject jo, UserIdentifier& result)
{
fromJson(jo.take("type"_ls), result.type);
-
fromJson(jo, result.additionalProperties);
+
}
+
+
+
diff --git a/lib/csapi/definitions/user_identifier.h b/lib/csapi/definitions/user_identifier.h
index 4a9ce684..831ba191 100644
--- a/lib/csapi/definitions/user_identifier.h
+++ b/lib/csapi/definitions/user_identifier.h
@@ -4,24 +4,34 @@
#pragma once
+
+
#include "converters.h"
#include <QtCore/QVariant>
-namespace QMatrixClient {
- // Data structures
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Identification information for a user
+struct UserIdentifier
+{
+ /// The type of identification. See `Identifier types`_ for supported values and additional property descriptions.
+ QString type;
+
/// Identification information for a user
- struct UserIdentifier {
- /// The type of identification. See `Identifier types`_ for supported
- /// values and additional property descriptions.
- QString type;
- /// Identification information for a user
- QVariantHash additionalProperties;
- };
- template <> struct JsonObjectConverter<UserIdentifier> {
- static void dumpTo(QJsonObject& jo, const UserIdentifier& pod);
- static void fillFrom(QJsonObject jo, UserIdentifier& pod);
- };
+ QVariantHash additionalProperties;
+
+};
+
+template <> struct JsonObjectConverter<UserIdentifier>
+{
+ static void dumpTo(QJsonObject& jo, const UserIdentifier& pod);
+ static void fillFrom(QJsonObject jo, UserIdentifier& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/wellknown/full.cpp b/lib/csapi/definitions/wellknown/full.cpp
index 35c0df5b..a2d71db0 100644
--- a/lib/csapi/definitions/wellknown/full.cpp
+++ b/lib/csapi/definitions/wellknown/full.cpp
@@ -4,22 +4,25 @@
#include "full.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<DiscoveryInformation>::dumpTo(
- QJsonObject& jo, const DiscoveryInformation& pod)
+
+void JsonObjectConverter<DiscoveryInformation>::dumpTo(QJsonObject& jo, const DiscoveryInformation& pod)
{
fillJson(jo, pod.additionalProperties);
addParam<>(jo, QStringLiteral("m.homeserver"), pod.homeserver);
- addParam<IfNotEmpty>(jo, QStringLiteral("m.identity_server"),
- pod.identityServer);
-}
+ addParam<IfNotEmpty>(jo, QStringLiteral("m.identity_server"), pod.identityServer);
-void JsonObjectConverter<DiscoveryInformation>::fillFrom(
- QJsonObject jo, DiscoveryInformation& result)
+}
+
+void JsonObjectConverter<DiscoveryInformation>::fillFrom(QJsonObject jo, DiscoveryInformation& result)
{
fromJson(jo.take("m.homeserver"_ls), result.homeserver);
fromJson(jo.take("m.identity_server"_ls), result.identityServer);
-
fromJson(jo, result.additionalProperties);
+
}
+
+
+
diff --git a/lib/csapi/definitions/wellknown/full.h b/lib/csapi/definitions/wellknown/full.h
index 9b920eda..ef975969 100644
--- a/lib/csapi/definitions/wellknown/full.h
+++ b/lib/csapi/definitions/wellknown/full.h
@@ -4,32 +4,40 @@
#pragma once
+
+
#include "converters.h"
+#include <QtCore/QJsonObject>
#include "converters.h"
#include "csapi/definitions/wellknown/homeserver.h"
#include "csapi/definitions/wellknown/identity_server.h"
#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Data structures
-
- /// Used by clients to determine the homeserver, identity server, and other
- /// optional components they should be interacting with.
- struct DiscoveryInformation {
- /// Used by clients to determine the homeserver, identity server, and
- /// other optional components they should be interacting with.
- HomeserverInformation homeserver;
- /// Used by clients to determine the homeserver, identity server, and
- /// other optional components they should be interacting with.
- Omittable<IdentityServerInformation> identityServer;
- /// Application-dependent keys using Java package naming convention.
- QHash<QString, QJsonObject> additionalProperties;
- };
- template <> struct JsonObjectConverter<DiscoveryInformation> {
- static void dumpTo(QJsonObject& jo, const DiscoveryInformation& pod);
- static void fillFrom(QJsonObject jo, DiscoveryInformation& pod);
- };
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Used by clients to determine the homeserver, identity server, and other/// optional components they should be interacting with.
+struct DiscoveryInformation
+{
+ /// Used by clients to determine the homeserver, identity server, and otheroptional components they should be interacting with.
+ HomeserverInformation homeserver;
+ /// Used by clients to determine the homeserver, identity server, and otheroptional components they should be interacting with.
+ Omittable<IdentityServerInformation> identityServer;
+
+
+ /// Application-dependent keys using Java package naming convention.
+ QHash<QString, QJsonObject> additionalProperties;
+
+};
+
+template <> struct JsonObjectConverter<DiscoveryInformation>
+{
+ static void dumpTo(QJsonObject& jo, const DiscoveryInformation& pod);
+ static void fillFrom(QJsonObject jo, DiscoveryInformation& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/wellknown/homeserver.cpp b/lib/csapi/definitions/wellknown/homeserver.cpp
index a7337520..a8a5077b 100644
--- a/lib/csapi/definitions/wellknown/homeserver.cpp
+++ b/lib/csapi/definitions/wellknown/homeserver.cpp
@@ -4,16 +4,21 @@
#include "homeserver.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<HomeserverInformation>::dumpTo(
- QJsonObject& jo, const HomeserverInformation& pod)
+
+void JsonObjectConverter<HomeserverInformation>::dumpTo(QJsonObject& jo, const HomeserverInformation& pod)
{
addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
-}
-void JsonObjectConverter<HomeserverInformation>::fillFrom(
- const QJsonObject& jo, HomeserverInformation& result)
+}
+
+void JsonObjectConverter<HomeserverInformation>::fillFrom(const QJsonObject& jo, HomeserverInformation& result)
{
fromJson(jo.value("base_url"_ls), result.baseUrl);
+
}
+
+
+
diff --git a/lib/csapi/definitions/wellknown/homeserver.h b/lib/csapi/definitions/wellknown/homeserver.h
index 8bd3c150..fe6af172 100644
--- a/lib/csapi/definitions/wellknown/homeserver.h
+++ b/lib/csapi/definitions/wellknown/homeserver.h
@@ -4,19 +4,30 @@
#pragma once
+
+
#include "converters.h"
-namespace QMatrixClient {
- // Data structures
-
- /// Used by clients to discover homeserver information.
- struct HomeserverInformation {
- /// The base URL for the homeserver for client-server connections.
- QString baseUrl;
- };
- template <> struct JsonObjectConverter<HomeserverInformation> {
- static void dumpTo(QJsonObject& jo, const HomeserverInformation& pod);
- static void fillFrom(const QJsonObject& jo, HomeserverInformation& pod);
- };
+
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Used by clients to discover homeserver information.
+struct HomeserverInformation
+{
+ /// The base URL for the homeserver for client-server connections.
+ QString baseUrl;
+
+
+};
+
+template <> struct JsonObjectConverter<HomeserverInformation>
+{
+ static void dumpTo(QJsonObject& jo, const HomeserverInformation& pod);
+ static void fillFrom(const QJsonObject& jo, HomeserverInformation& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/wellknown/identity_server.cpp b/lib/csapi/definitions/wellknown/identity_server.cpp
index 46a614d8..a9fae614 100644
--- a/lib/csapi/definitions/wellknown/identity_server.cpp
+++ b/lib/csapi/definitions/wellknown/identity_server.cpp
@@ -4,16 +4,21 @@
#include "identity_server.h"
+
using namespace QMatrixClient;
-void JsonObjectConverter<IdentityServerInformation>::dumpTo(
- QJsonObject& jo, const IdentityServerInformation& pod)
+
+void JsonObjectConverter<IdentityServerInformation>::dumpTo(QJsonObject& jo, const IdentityServerInformation& pod)
{
addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
-}
-void JsonObjectConverter<IdentityServerInformation>::fillFrom(
- const QJsonObject& jo, IdentityServerInformation& result)
+}
+
+void JsonObjectConverter<IdentityServerInformation>::fillFrom(const QJsonObject& jo, IdentityServerInformation& result)
{
fromJson(jo.value("base_url"_ls), result.baseUrl);
+
}
+
+
+
diff --git a/lib/csapi/definitions/wellknown/identity_server.h b/lib/csapi/definitions/wellknown/identity_server.h
index fd53dfc1..4462f86e 100644
--- a/lib/csapi/definitions/wellknown/identity_server.h
+++ b/lib/csapi/definitions/wellknown/identity_server.h
@@ -4,21 +4,30 @@
#pragma once
+
+
#include "converters.h"
-namespace QMatrixClient {
- // Data structures
-
- /// Used by clients to discover identity server information.
- struct IdentityServerInformation {
- /// The base URL for the identity server for client-server connections.
- QString baseUrl;
- };
- template <> struct JsonObjectConverter<IdentityServerInformation> {
- static void dumpTo(QJsonObject& jo,
- const IdentityServerInformation& pod);
- static void fillFrom(const QJsonObject& jo,
- IdentityServerInformation& pod);
- };
+
+namespace QMatrixClient
+{
+
+// Data structures
+
+/// Used by clients to discover identity server information.
+struct IdentityServerInformation
+{
+ /// The base URL for the identity server for client-server connections.
+ QString baseUrl;
+
+
+};
+
+template <> struct JsonObjectConverter<IdentityServerInformation>
+{
+ static void dumpTo(QJsonObject& jo, const IdentityServerInformation& pod);
+ static void fillFrom(const QJsonObject& jo, IdentityServerInformation& pod);};
+
+
} // namespace QMatrixClient
diff --git a/lib/csapi/device_management.cpp b/lib/csapi/device_management.cpp
index 7d15bb2b..9135c22d 100644
--- a/lib/csapi/device_management.cpp
+++ b/lib/csapi/device_management.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetDevicesJob::Private
{
- public:
+public:
QVector<Device> devices;
};
@@ -26,10 +26,9 @@ QUrl GetDevicesJob::makeRequestUrl(QUrl baseUrl)
static const auto GetDevicesJobName = QStringLiteral("GetDevicesJob");
GetDevicesJob::GetDevicesJob()
- : BaseJob(HttpVerb::Get, GetDevicesJobName, basePath % "/devices"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetDevicesJobName, basePath % "/devices")
+ , d(new Private)
+{}
GetDevicesJob::~GetDevicesJob() = default;
@@ -39,12 +38,13 @@ BaseJob::Status GetDevicesJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("devices"_ls), d->devices);
+
return Success;
}
class GetDeviceJob::Private
{
- public:
+public:
Device data;
};
@@ -57,11 +57,9 @@ QUrl GetDeviceJob::makeRequestUrl(QUrl baseUrl, const QString& deviceId)
static const auto GetDeviceJobName = QStringLiteral("GetDeviceJob");
GetDeviceJob::GetDeviceJob(const QString& deviceId)
- : BaseJob(HttpVerb::Get, GetDeviceJobName,
- basePath % "/devices/" % deviceId),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetDeviceJobName, basePath % "/devices/" % deviceId)
+ , d(new Private)
+{}
GetDeviceJob::~GetDeviceJob() = default;
@@ -101,8 +99,7 @@ static const auto DeleteDevicesJobName = QStringLiteral("DeleteDevicesJob");
DeleteDevicesJob::DeleteDevicesJob(const QStringList& devices,
const Omittable<AuthenticationData>& auth)
- : BaseJob(HttpVerb::Post, DeleteDevicesJobName,
- basePath % "/delete_devices")
+ : BaseJob(HttpVerb::Post, DeleteDevicesJobName, basePath % "/delete_devices")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("devices"), devices);
diff --git a/lib/csapi/device_management.h b/lib/csapi/device_management.h
index 628f26d2..01838c6f 100644
--- a/lib/csapi/device_management.h
+++ b/lib/csapi/device_management.h
@@ -4,138 +4,145 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/auth_data.h"
#include "csapi/definitions/client_device.h"
+
+#include "jobs/basejob.h"
+
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
-
- /// List registered devices for the current user
- ///
- /// Gets information about all devices for the current user.
- class GetDevicesJob : public BaseJob
- {
- public:
- explicit GetDevicesJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetDevicesJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetDevicesJob() override;
-
- // Result properties
-
- /// A list of all registered devices for this user.
- const QVector<Device>& devices() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Get a single device
- ///
- /// Gets information on a single device, by device id.
- class GetDeviceJob : public BaseJob
- {
- public:
- /*! Get a single device
- * \param deviceId
- * The device to retrieve.
- */
- explicit GetDeviceJob(const QString& deviceId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetDeviceJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& deviceId);
-
- ~GetDeviceJob() override;
-
- // Result properties
-
- /// Device information
- const Device& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Update a device
- ///
- /// Updates the metadata on the given device.
- class UpdateDeviceJob : public BaseJob
- {
- public:
- /*! Update a device
- * \param deviceId
- * The device to update.
- * \param displayName
- * The new display name for this device. If not given, the
- * display name is unchanged.
- */
- explicit UpdateDeviceJob(const QString& deviceId,
- const QString& displayName = {});
- };
-
- /// Delete a device
- ///
- /// This API endpoint uses the `User-Interactive Authentication API`_.
- ///
- /// Deletes the given device, and invalidates any access token associated
- /// with it.
- class DeleteDeviceJob : public BaseJob
- {
- public:
- /*! Delete a device
- * \param deviceId
- * The device to delete.
- * \param auth
- * Additional authentication information for the
- * user-interactive authentication API.
- */
- explicit DeleteDeviceJob(
- const QString& deviceId,
- const Omittable<AuthenticationData>& auth = none);
- };
-
- /// Bulk deletion of devices
- ///
- /// This API endpoint uses the `User-Interactive Authentication API`_.
- ///
- /// Deletes the given devices, and invalidates any access token associated
- /// with them.
- class DeleteDevicesJob : public BaseJob
- {
- public:
- /*! Bulk deletion of devices
- * \param devices
- * The list of device IDs to delete.
- * \param auth
- * Additional authentication information for the
- * user-interactive authentication API.
- */
- explicit DeleteDevicesJob(
- const QStringList& devices,
- const Omittable<AuthenticationData>& auth = none);
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// List registered devices for the current user
+/*!
+ * Gets information about all devices for the current user.
+ */
+class GetDevicesJob : public BaseJob
+{
+public:
+ explicit GetDevicesJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetDevicesJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetDevicesJob() override;
+
+ // Result properties
+
+ /// A list of all registered devices for this user.
+ const QVector<Device>& devices() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Get a single device
+/*!
+ * Gets information on a single device, by device id.
+ */
+class GetDeviceJob : public BaseJob
+{
+public:
+ /*! Get a single device
+ * \param deviceId
+ * The device to retrieve.
+ */
+ explicit GetDeviceJob(const QString& deviceId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetDeviceJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& deviceId);
+
+ ~GetDeviceJob() override;
+
+ // Result properties
+
+ /// Device information
+ const Device& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Update a device
+/*!
+ * Updates the metadata on the given device.
+ */
+class UpdateDeviceJob : public BaseJob
+{
+public:
+ /*! Update a device
+ * \param deviceId
+ * The device to update.
+ * \param displayName
+ * The new display name for this device. If not given, the
+ * display name is unchanged.
+ */
+ explicit UpdateDeviceJob(const QString& deviceId,
+ const QString& displayName = {});
+};
+
+/// Delete a device
+/*!
+ * This API endpoint uses the `User-Interactive Authentication API`_.
+ *
+ * Deletes the given device, and invalidates any access token associated with it.
+ */
+class DeleteDeviceJob : public BaseJob
+{
+public:
+ /*! Delete a device
+ * \param deviceId
+ * The device to delete.
+ * \param auth
+ * Additional authentication information for the
+ * user-interactive authentication API.
+ */
+ explicit DeleteDeviceJob(const QString& deviceId,
+ const Omittable<AuthenticationData>& auth = none);
+};
+
+/// Bulk deletion of devices
+/*!
+ * This API endpoint uses the `User-Interactive Authentication API`_.
+ *
+ * Deletes the given devices, and invalidates any access token associated with
+ * them.
+ */
+class DeleteDevicesJob : public BaseJob
+{
+public:
+ /*! Bulk deletion of devices
+ * \param devices
+ * The list of device IDs to delete.
+ * \param auth
+ * Additional authentication information for the
+ * user-interactive authentication API.
+ */
+ explicit DeleteDevicesJob(const QStringList& devices,
+ const Omittable<AuthenticationData>& auth = none);
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/directory.cpp b/lib/csapi/directory.cpp
index b4282ffb..992d1da5 100644
--- a/lib/csapi/directory.cpp
+++ b/lib/csapi/directory.cpp
@@ -14,8 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0/directory");
static const auto SetRoomAliasJobName = QStringLiteral("SetRoomAliasJob");
-SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias,
- const QString& roomId)
+SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias, const QString& roomId)
: BaseJob(HttpVerb::Put, SetRoomAliasJobName,
basePath % "/room/" % roomAlias)
{
@@ -26,7 +25,7 @@ SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias,
class GetRoomIdByAliasJob::Private
{
- public:
+public:
QString roomId;
QStringList servers;
};
@@ -38,14 +37,13 @@ QUrl GetRoomIdByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias)
}
static const auto GetRoomIdByAliasJobName =
- QStringLiteral("GetRoomIdByAliasJob");
+ QStringLiteral("GetRoomIdByAliasJob");
GetRoomIdByAliasJob::GetRoomIdByAliasJob(const QString& roomAlias)
: BaseJob(HttpVerb::Get, GetRoomIdByAliasJobName,
- basePath % "/room/" % roomAlias, false),
- d(new Private)
-{
-}
+ basePath % "/room/" % roomAlias, false)
+ , d(new Private)
+{}
GetRoomIdByAliasJob::~GetRoomIdByAliasJob() = default;
@@ -58,6 +56,7 @@ BaseJob::Status GetRoomIdByAliasJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("room_id"_ls), d->roomId);
fromJson(json.value("servers"_ls), d->servers);
+
return Success;
}
@@ -72,5 +71,4 @@ static const auto DeleteRoomAliasJobName = QStringLiteral("DeleteRoomAliasJob");
DeleteRoomAliasJob::DeleteRoomAliasJob(const QString& roomAlias)
: BaseJob(HttpVerb::Delete, DeleteRoomAliasJobName,
basePath % "/room/" % roomAlias)
-{
-}
+{}
diff --git a/lib/csapi/directory.h b/lib/csapi/directory.h
index 6bf5ad14..f5331db8 100644
--- a/lib/csapi/directory.h
+++ b/lib/csapi/directory.h
@@ -6,86 +6,91 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Create a new mapping from room alias to room ID.
- class SetRoomAliasJob : public BaseJob
- {
- public:
- /*! Create a new mapping from room alias to room ID.
- * \param roomAlias
- * The room alias to set.
- * \param roomId
- * The room ID to set.
- */
- explicit SetRoomAliasJob(const QString& roomAlias,
- const QString& roomId);
- };
-
- /// Get the room ID corresponding to this room alias.
- ///
- /// Requests that the server resolve a room alias to a room ID.
- ///
- /// The server will use the federation API to resolve the alias if the
- /// domain part of the alias does not correspond to the server's own
- /// domain.
- class GetRoomIdByAliasJob : public BaseJob
- {
- public:
- /*! Get the room ID corresponding to this room alias.
- * \param roomAlias
- * The room alias.
- */
- explicit GetRoomIdByAliasJob(const QString& roomAlias);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomIdByAliasJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomAlias);
-
- ~GetRoomIdByAliasJob() override;
-
- // Result properties
-
- /// The room ID for this room alias.
- const QString& roomId() const;
- /// A list of servers that are aware of this room alias.
- const QStringList& servers() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Remove a mapping of room alias to room ID.
- ///
- /// Remove a mapping of room alias to room ID.
- ///
- /// Servers may choose to implement additional access control checks here,
- /// for instance that room aliases can only be deleted by their creator or a
- /// server administrator.
- class DeleteRoomAliasJob : public BaseJob
- {
- public:
- /*! Remove a mapping of room alias to room ID.
- * \param roomAlias
- * The room alias to remove.
- */
- explicit DeleteRoomAliasJob(const QString& roomAlias);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * DeleteRoomAliasJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomAlias);
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Create a new mapping from room alias to room ID.
+
+class SetRoomAliasJob : public BaseJob
+{
+public:
+ /*! Create a new mapping from room alias to room ID.
+ * \param roomAlias
+ * The room alias to set.
+ * \param roomId
+ * The room ID to set.
+ */
+ explicit SetRoomAliasJob(const QString& roomAlias, const QString& roomId);
+};
+
+/// Get the room ID corresponding to this room alias.
+/*!
+ * Requests that the server resolve a room alias to a room ID.
+ *
+ * The server will use the federation API to resolve the alias if the
+ * domain part of the alias does not correspond to the server's own
+ * domain.
+ */
+class GetRoomIdByAliasJob : public BaseJob
+{
+public:
+ /*! Get the room ID corresponding to this room alias.
+ * \param roomAlias
+ * The room alias.
+ */
+ explicit GetRoomIdByAliasJob(const QString& roomAlias);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomIdByAliasJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomAlias);
+
+ ~GetRoomIdByAliasJob() override;
+
+ // Result properties
+
+ /// The room ID for this room alias.
+ const QString& roomId() const;
+ /// A list of servers that are aware of this room alias.
+ const QStringList& servers() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Remove a mapping of room alias to room ID.
+/*!
+ * Remove a mapping of room alias to room ID.
+ *
+ * Servers may choose to implement additional access control checks here, for
+ * instance that room aliases can only be deleted by their creator or a server
+ * administrator.
+ */
+class DeleteRoomAliasJob : public BaseJob
+{
+public:
+ /*! Remove a mapping of room alias to room ID.
+ * \param roomAlias
+ * The room alias to remove.
+ */
+ explicit DeleteRoomAliasJob(const QString& roomAlias);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * DeleteRoomAliasJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomAlias);
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/event_context.cpp b/lib/csapi/event_context.cpp
index 9ead6ac6..936b2430 100644
--- a/lib/csapi/event_context.cpp
+++ b/lib/csapi/event_context.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetEventContextJob::Private
{
- public:
+public:
QString begin;
QString end;
RoomEvents eventsBefore;
@@ -36,7 +36,7 @@ QUrl GetEventContextJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/rooms/" % roomId % "/context/"
- % eventId,
+ % eventId,
queryToGetEventContext(limit));
}
@@ -47,10 +47,9 @@ GetEventContextJob::GetEventContextJob(const QString& roomId,
Omittable<int> limit)
: BaseJob(HttpVerb::Get, GetEventContextJobName,
basePath % "/rooms/" % roomId % "/context/" % eventId,
- queryToGetEventContext(limit)),
- d(new Private)
-{
-}
+ queryToGetEventContext(limit))
+ , d(new Private)
+{}
GetEventContextJob::~GetEventContextJob() = default;
@@ -81,5 +80,6 @@ BaseJob::Status GetEventContextJob::parseJson(const QJsonDocument& data)
fromJson(json.value("event"_ls), d->event);
fromJson(json.value("events_after"_ls), d->eventsAfter);
fromJson(json.value("state"_ls), d->state);
+
return Success;
}
diff --git a/lib/csapi/event_context.h b/lib/csapi/event_context.h
index cfefc550..ca06f4b9 100644
--- a/lib/csapi/event_context.h
+++ b/lib/csapi/event_context.h
@@ -4,68 +4,71 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "events/eventloader.h"
+#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Get events and state around the specified event.
+/*!
+ * This API returns a number of events that happened just before and
+ * after the specified event. This allows clients to get the context
+ * surrounding an event.
+ */
+class GetEventContextJob : public BaseJob
+{
+public:
+ /*! Get events and state around the specified event.
+ * \param roomId
+ * The room to get events from.
+ * \param eventId
+ * The event to get context around.
+ * \param limit
+ * The maximum number of events to return. Default: 10.
+ */
+ explicit GetEventContextJob(const QString& roomId, const QString& eventId,
+ Omittable<int> limit = none);
- /// Get events and state around the specified event.
- ///
- /// This API returns a number of events that happened just before and
- /// after the specified event. This allows clients to get the context
- /// surrounding an event.
- class GetEventContextJob : public BaseJob
- {
- public:
- /*! Get events and state around the specified event.
- * \param roomId
- * The room to get events from.
- * \param eventId
- * The event to get context around.
- * \param limit
- * The maximum number of events to return. Default: 10.
- */
- explicit GetEventContextJob(const QString& roomId,
- const QString& eventId,
- Omittable<int> limit = none);
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetEventContextJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+ const QString& eventId,
+ Omittable<int> limit = none);
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetEventContextJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& eventId,
- Omittable<int> limit = none);
+ ~GetEventContextJob() override;
- ~GetEventContextJob() override;
+ // Result properties
- // Result properties
+ /// A token that can be used to paginate backwards with.
+ const QString& begin() const;
+ /// A token that can be used to paginate forwards with.
+ const QString& end() const;
+ /// A list of room events that happened just before the
+ /// requested event, in reverse-chronological order.
+ RoomEvents&& eventsBefore();
+ /// Details of the requested event.
+ RoomEventPtr&& event();
+ /// A list of room events that happened just after the
+ /// requested event, in chronological order.
+ RoomEvents&& eventsAfter();
+ /// The state of the room at the last event returned.
+ StateEvents&& state();
- /// A token that can be used to paginate backwards with.
- const QString& begin() const;
- /// A token that can be used to paginate forwards with.
- const QString& end() const;
- /// A list of room events that happened just before the
- /// requested event, in reverse-chronological order.
- RoomEvents&& eventsBefore();
- /// Details of the requested event.
- RoomEventPtr&& event();
- /// A list of room events that happened just after the
- /// requested event, in chronological order.
- RoomEvents&& eventsAfter();
- /// The state of the room at the last event returned.
- StateEvents&& state();
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- protected:
- Status parseJson(const QJsonDocument& data) override;
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/filter.cpp b/lib/csapi/filter.cpp
index 40743de4..79dd5ea5 100644
--- a/lib/csapi/filter.cpp
+++ b/lib/csapi/filter.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class DefineFilterJob::Private
{
- public:
+public:
QString filterId;
};
@@ -22,8 +22,8 @@ static const auto DefineFilterJobName = QStringLiteral("DefineFilterJob");
DefineFilterJob::DefineFilterJob(const QString& userId, const Filter& filter)
: BaseJob(HttpVerb::Post, DefineFilterJobName,
- basePath % "/user/" % userId % "/filter"),
- d(new Private)
+ basePath % "/user/" % userId % "/filter")
+ , d(new Private)
{
setRequestData(Data(toJson(filter)));
}
@@ -36,34 +36,34 @@ BaseJob::Status DefineFilterJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("filter_id"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'filter_id' not found in the response" };
fromJson(json.value("filter_id"_ls), d->filterId);
+
return Success;
}
class GetFilterJob::Private
{
- public:
+public:
Filter data;
};
QUrl GetFilterJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& filterId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/user/" % userId % "/filter/"
- % filterId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/user/"
+ % userId % "/filter/"
+ % filterId);
}
static const auto GetFilterJobName = QStringLiteral("GetFilterJob");
GetFilterJob::GetFilterJob(const QString& userId, const QString& filterId)
: BaseJob(HttpVerb::Get, GetFilterJobName,
- basePath % "/user/" % userId % "/filter/" % filterId),
- d(new Private)
-{
-}
+ basePath % "/user/" % userId % "/filter/" % filterId)
+ , d(new Private)
+{}
GetFilterJob::~GetFilterJob() = default;
diff --git a/lib/csapi/filter.h b/lib/csapi/filter.h
index 85e05667..0a5a98ae 100644
--- a/lib/csapi/filter.h
+++ b/lib/csapi/filter.h
@@ -4,82 +4,88 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/sync_filter.h"
-namespace QMatrixClient {
- // Operations
-
- /// Upload a new filter.
- ///
- /// Uploads a new filter definition to the homeserver.
- /// Returns a filter ID that may be used in future requests to
- /// restrict which events are returned to the client.
- class DefineFilterJob : public BaseJob
- {
- public:
- /*! Upload a new filter.
- * \param userId
- * The id of the user uploading the filter. The access token must be
- * authorized to make requests for this user id. \param filter Uploads a
- * new filter definition to the homeserver. Returns a filter ID that may
- * be used in future requests to restrict which events are returned to
- * the client.
- */
- explicit DefineFilterJob(const QString& userId, const Filter& filter);
- ~DefineFilterJob() override;
-
- // Result properties
-
- /// The ID of the filter that was created. Cannot start
- /// 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.
- const QString& filterId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Download a filter
- class GetFilterJob : public BaseJob
- {
- public:
- /*! Download a filter
- * \param userId
- * The user ID to download a filter for.
- * \param filterId
- * The filter ID to download.
- */
- explicit GetFilterJob(const QString& userId, const QString& filterId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetFilterJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
- const QString& filterId);
-
- ~GetFilterJob() override;
-
- // Result properties
-
- /// "The filter defintion"
- const Filter& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+#include "jobs/basejob.h"
+
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Upload a new filter.
+/*!
+ * Uploads a new filter definition to the homeserver.
+ * Returns a filter ID that may be used in future requests to
+ * restrict which events are returned to the client.
+ */
+class DefineFilterJob : public BaseJob
+{
+public:
+ /*! Upload a new filter.
+ * \param userId
+ * The id of the user uploading the filter. The access token must be
+ * authorized to make requests for this user id. \param filter Uploads a new
+ * filter definition to the homeserver. Returns a filter ID that may be used
+ * in future requests to restrict which events are returned to the client.
+ */
+ explicit DefineFilterJob(const QString& userId, const Filter& filter);
+
+ ~DefineFilterJob() override;
+
+ // Result properties
+
+ /// The ID of the filter that was created. Cannot start
+ /// 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.
+ const QString& filterId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Download a filter
+
+class GetFilterJob : public BaseJob
+{
+public:
+ /*! Download a filter
+ * \param userId
+ * The user ID to download a filter for.
+ * \param filterId
+ * The filter ID to download.
+ */
+ explicit GetFilterJob(const QString& userId, const QString& filterId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetFilterJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
+ const QString& filterId);
+
+ ~GetFilterJob() override;
+
+ // Result properties
+
+ /// "The filter defintion"
+ const Filter& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/inviting.h b/lib/csapi/inviting.h
index 12cf1b58..b0911ea8 100644
--- a/lib/csapi/inviting.h
+++ b/lib/csapi/inviting.h
@@ -6,38 +6,42 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Invite a user to participate in a particular room.
+/*!
+ * .. _invite-by-user-id-endpoint:
+ *
+ * *Note that there are two forms of this API, which are documented separately.
+ * This version of the API requires that the inviter knows the Matrix
+ * identifier of the invitee. The other is documented in the*
+ * `third party invites section`_.
+ *
+ * This API invites a user to participate in a particular room.
+ * They do not start participating in the room until they actually join the
+ * room.
+ *
+ * Only users currently in a particular room can invite other users to
+ * join that room.
+ *
+ * If the user was invited to the room, the homeserver will append a
+ * ``m.room.member`` event to the room.
+ *
+ * .. _third party invites section: `invite-by-third-party-id-endpoint`_
+ */
+class InviteUserJob : public BaseJob
+{
+public:
+ /*! Invite a user to participate in a particular room.
+ * \param roomId
+ * The room identifier (not alias) to which to invite the user.
+ * \param userId
+ * The fully qualified user ID of the invitee.
+ */
+ explicit InviteUserJob(const QString& roomId, const QString& userId);
+};
- /// Invite a user to participate in a particular room.
- ///
- /// .. _invite-by-user-id-endpoint:
- ///
- /// *Note that there are two forms of this API, which are documented
- /// separately. This version of the API requires that the inviter knows the
- /// Matrix identifier of the invitee. The other is documented in the* `third
- /// party invites section`_.
- ///
- /// This API invites a user to participate in a particular room.
- /// They do not start participating in the room until they actually join the
- /// room.
- ///
- /// Only users currently in a particular room can invite other users to
- /// join that room.
- ///
- /// If the user was invited to the room, the homeserver will append a
- /// ``m.room.member`` event to the room.
- ///
- /// .. _third party invites section: `invite-by-third-party-id-endpoint`_
- class InviteUserJob : public BaseJob
- {
- public:
- /*! Invite a user to participate in a particular room.
- * \param roomId
- * The room identifier (not alias) to which to invite the user.
- * \param userId
- * The fully qualified user ID of the invitee.
- */
- explicit InviteUserJob(const QString& roomId, const QString& userId);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp
index fe4c83e3..cb40cb96 100644
--- a/lib/csapi/joining.cpp
+++ b/lib/csapi/joining.cpp
@@ -12,35 +12,38 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<JoinRoomByIdJob::ThirdPartySigned> {
- static void dumpTo(QJsonObject& jo,
- const JoinRoomByIdJob::ThirdPartySigned& pod)
- {
- addParam<>(jo, QStringLiteral("sender"), pod.sender);
- addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
- addParam<>(jo, QStringLiteral("token"), pod.token);
- addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<JoinRoomByIdJob::ThirdPartySigned>
+{
+ static void dumpTo(QJsonObject& jo,
+ const JoinRoomByIdJob::ThirdPartySigned& pod)
+ {
+ addParam<>(jo, QStringLiteral("sender"), pod.sender);
+ addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
+ addParam<>(jo, QStringLiteral("token"), pod.token);
+ addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
+ }
+};
+
} // namespace QMatrixClient
class JoinRoomByIdJob::Private
{
- public:
+public:
QString roomId;
};
static const auto JoinRoomByIdJobName = QStringLiteral("JoinRoomByIdJob");
JoinRoomByIdJob::JoinRoomByIdJob(
- const QString& roomId,
- const Omittable<ThirdPartySigned>& thirdPartySigned)
+ const QString& roomId, const Omittable<ThirdPartySigned>& thirdPartySigned)
: BaseJob(HttpVerb::Post, JoinRoomByIdJobName,
- basePath % "/rooms/" % roomId % "/join"),
- d(new Private)
+ basePath % "/rooms/" % roomId % "/join")
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"),
@@ -56,37 +59,43 @@ BaseJob::Status JoinRoomByIdJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("room_id"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'room_id' not found in the response" };
fromJson(json.value("room_id"_ls), d->roomId);
+
return Success;
}
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<JoinRoomJob::Signed> {
- static void dumpTo(QJsonObject& jo, const JoinRoomJob::Signed& pod)
- {
- addParam<>(jo, QStringLiteral("sender"), pod.sender);
- addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
- addParam<>(jo, QStringLiteral("token"), pod.token);
- addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
- }
- };
-
- template <> struct JsonObjectConverter<JoinRoomJob::ThirdPartySigned> {
- static void dumpTo(QJsonObject& jo,
- const JoinRoomJob::ThirdPartySigned& pod)
- {
- addParam<>(jo, QStringLiteral("signed"), pod.signedData);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<JoinRoomJob::Signed>
+{
+ static void dumpTo(QJsonObject& jo, const JoinRoomJob::Signed& pod)
+ {
+ addParam<>(jo, QStringLiteral("sender"), pod.sender);
+ addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
+ addParam<>(jo, QStringLiteral("token"), pod.token);
+ addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
+ }
+};
+
+template <>
+struct JsonObjectConverter<JoinRoomJob::ThirdPartySigned>
+{
+ static void dumpTo(QJsonObject& jo, const JoinRoomJob::ThirdPartySigned& pod)
+ {
+ addParam<>(jo, QStringLiteral("signed"), pod.signedData);
+ }
+};
+
} // namespace QMatrixClient
class JoinRoomJob::Private
{
- public:
+public:
QString roomId;
};
@@ -103,8 +112,8 @@ JoinRoomJob::JoinRoomJob(const QString& roomIdOrAlias,
const QStringList& serverName,
const Omittable<ThirdPartySigned>& thirdPartySigned)
: BaseJob(HttpVerb::Post, JoinRoomJobName,
- basePath % "/join/" % roomIdOrAlias, queryToJoinRoom(serverName)),
- d(new Private)
+ basePath % "/join/" % roomIdOrAlias, queryToJoinRoom(serverName))
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"),
@@ -120,8 +129,9 @@ BaseJob::Status JoinRoomJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("room_id"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'room_id' not found in the response" };
fromJson(json.value("room_id"_ls), d->roomId);
+
return Success;
}
diff --git a/lib/csapi/joining.h b/lib/csapi/joining.h
index 5d118dab..a96f323d 100644
--- a/lib/csapi/joining.h
+++ b/lib/csapi/joining.h
@@ -4,161 +4,165 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
-
- /// Start the requesting user participating in a particular room.
- ///
- /// *Note that this API requires a room ID, not alias.*
- /// ``/join/{roomIdOrAlias}`` *exists if you have a room alias.*
- ///
- /// This API starts a user participating in a particular room, if that user
- /// is allowed to participate in that room. After this call, the client is
- /// allowed to see all current state events in the room, and all subsequent
- /// events associated with the room until the user leaves the room.
- ///
- /// After a user has joined a room, the room will appear as an entry in the
- /// response of the |/initialSync|_ and |/sync|_ APIs.
- ///
- /// If a ``third_party_signed`` was supplied, the homeserver must verify
- /// that it matches a pending ``m.room.third_party_invite`` event in the
- /// room, and perform key validity checking if required by the event.
- class JoinRoomByIdJob : public BaseJob
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Start the requesting user participating in a particular room.
+/*!
+ * *Note that this API requires a room ID, not alias.* ``/join/{roomIdOrAlias}``
+ * *exists if you have a room alias.*
+ *
+ * This API starts a user participating in a particular room, if that user
+ * is allowed to participate in that room. After this call, the client is
+ * allowed to see all current state events in the room, and all subsequent
+ * events associated with the room until the user leaves the room.
+ *
+ * After a user has joined a room, the room will appear as an entry in the
+ * response of the |/initialSync|_ and |/sync|_ APIs.
+ *
+ * If a ``third_party_signed`` was supplied, the homeserver must verify
+ * that it matches a pending ``m.room.third_party_invite`` event in the
+ * room, and perform key validity checking if required by the event.
+ */
+class JoinRoomByIdJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// A signature of an ``m.third_party_invite`` token to prove that this user
+ /// owns a third party identity which has been invited to the room.
+ struct ThirdPartySigned
{
- public:
- // Inner data structures
-
- /// A signature of an ``m.third_party_invite`` token to prove that this
- /// user owns a third party identity which has been invited to the room.
- struct ThirdPartySigned {
- /// The Matrix ID of the user who issued the invite.
- QString sender;
- /// The Matrix ID of the invitee.
- QString mxid;
- /// The state key of the m.third_party_invite event.
- QString token;
- /// A signatures object containing a signature of the entire signed
- /// object.
- QJsonObject signatures;
- };
-
- // Construction/destruction
-
- /*! Start the requesting user participating in a particular room.
- * \param roomId
- * The room identifier (not alias) to join.
- * \param thirdPartySigned
- * A signature of an ``m.third_party_invite`` token to prove that this
- * user owns a third party identity which has been invited to the room.
- */
- explicit JoinRoomByIdJob(
- const QString& roomId,
- const Omittable<ThirdPartySigned>& thirdPartySigned = none);
- ~JoinRoomByIdJob() override;
-
- // Result properties
-
- /// The joined room ID.
- const QString& roomId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// The Matrix ID of the user who issued the invite.
+ QString sender;
+ /// The Matrix ID of the invitee.
+ QString mxid;
+ /// The state key of the m.third_party_invite event.
+ QString token;
+ /// A signatures object containing a signature of the entire signed
+ /// object.
+ QJsonObject signatures;
};
- /// Start the requesting user participating in a particular room.
- ///
+ // Construction/destruction
+
+ /*! Start the requesting user participating in a particular room.
+ * \param roomId
+ * The room identifier (not alias) to join.
+ * \param thirdPartySigned
+ * A signature of an ``m.third_party_invite`` token to prove that this
+ * user owns a third party identity which has been invited to the room.
+ */
+ explicit JoinRoomByIdJob(
+ const QString& roomId,
+ const Omittable<ThirdPartySigned>& thirdPartySigned = none);
+
+ ~JoinRoomByIdJob() override;
+
+ // Result properties
+
+ /// The joined room ID.
+ const QString& roomId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Start the requesting user participating in a particular room.
+/*!
+ * *Note that this API takes either a room ID or alias, unlike*
+ * ``/room/{roomId}/join``.
+ *
+ * This API starts a user participating in a particular room, if that user
+ * is allowed to participate in that room. After this call, the client is
+ * allowed to see all current state events in the room, and all subsequent
+ * events associated with the room until the user leaves the room.
+ *
+ * After a user has joined a room, the room will appear as an entry in the
+ * response of the |/initialSync|_ and |/sync|_ APIs.
+ *
+ * If a ``third_party_signed`` was supplied, the homeserver must verify
+ * that it matches a pending ``m.room.third_party_invite`` event in the
+ * room, and perform key validity checking if required by the event.
+ */
+class JoinRoomJob : public BaseJob
+{
+public:
+ // Inner data structures
+
/// *Note that this API takes either a room ID or alias, unlike*
- /// ``/room/{roomId}/join``.
- ///
- /// This API starts a user participating in a particular room, if that user
- /// is allowed to participate in that room. After this call, the client is
- /// allowed to see all current state events in the room, and all subsequent
- /// events associated with the room until the user leaves the room.
- ///
- /// After a user has joined a room, the room will appear as an entry in the
- /// response of the |/initialSync|_ and |/sync|_ APIs.
- ///
- /// If a ``third_party_signed`` was supplied, the homeserver must verify
- /// that it matches a pending ``m.room.third_party_invite`` event in the
- /// room, and perform key validity checking if required by the event.
- class JoinRoomJob : public BaseJob
+ /// ``/room/{roomId}/join``.This API starts a user participating in a
+ /// particular room, if that useris allowed to participate in that room.
+ /// After this call, the client isallowed to see all current state events in
+ /// the room, and all subsequentevents associated with the room until the
+ /// user leaves the room.After a user has joined a room, the room will
+ /// appear as an entry in theresponse of the |/initialSync|_ and |/sync|_
+ /// APIs.If a ``third_party_signed`` was supplied, the homeserver must
+ /// verifythat it matches a pending ``m.room.third_party_invite`` event in
+ /// theroom, and perform key validity checking if required by the event.
+ struct Signed
{
- public:
- // Inner data structures
-
- /// *Note that this API takes either a room ID or alias, unlike*
- /// ``/room/{roomId}/join``.
- ///
- /// This API starts a user participating in a particular room, if that
- /// user is allowed to participate in that room. After this call, the
- /// client is allowed to see all current state events in the room, and
- /// all subsequent events associated with the room until the user leaves
- /// the room.
- ///
- /// After a user has joined a room, the room will appear as an entry in
- /// the response of the |/initialSync|_ and |/sync|_ APIs.
- ///
- /// If a ``third_party_signed`` was supplied, the homeserver must verify
- /// that it matches a pending ``m.room.third_party_invite`` event in the
- /// room, and perform key validity checking if required by the event.
- struct Signed {
- /// The Matrix ID of the user who issued the invite.
- QString sender;
- /// The Matrix ID of the invitee.
- QString mxid;
- /// The state key of the m.third_party_invite event.
- QString token;
- /// A signatures object containing a signature of the entire signed
- /// object.
- QJsonObject signatures;
- };
+ /// The Matrix ID of the user who issued the invite.
+ QString sender;
+ /// The Matrix ID of the invitee.
+ QString mxid;
+ /// The state key of the m.third_party_invite event.
+ QString token;
+ /// A signatures object containing a signature of the entire signed
+ /// object.
+ QJsonObject signatures;
+ };
+ /// A signature of an ``m.third_party_invite`` token to prove that this user
+ /// owns a third party identity which has been invited to the room.
+ struct ThirdPartySigned
+ {
/// A signature of an ``m.third_party_invite`` token to prove that this
/// user owns a third party identity which has been invited to the room.
- struct ThirdPartySigned {
- /// A signature of an ``m.third_party_invite`` token to prove that
- /// this user owns a third party identity which has been invited to
- /// the room.
- Signed signedData;
- };
-
- // Construction/destruction
-
- /*! Start the requesting user participating in a particular room.
- * \param roomIdOrAlias
- * The room identifier or alias to join.
- * \param serverName
- * The servers to attempt to join the room through. One of the servers
- * must be participating in the room.
- * \param thirdPartySigned
- * A signature of an ``m.third_party_invite`` token to prove that this
- * user owns a third party identity which has been invited to the room.
- */
- explicit JoinRoomJob(
- const QString& roomIdOrAlias,
- const QStringList& serverName = {},
- const Omittable<ThirdPartySigned>& thirdPartySigned = none);
- ~JoinRoomJob() override;
-
- // Result properties
-
- /// The joined room ID.
- const QString& roomId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ Signed signedData;
};
+
+ // Construction/destruction
+
+ /*! Start the requesting user participating in a particular room.
+ * \param roomIdOrAlias
+ * The room identifier or alias to join.
+ * \param serverName
+ * The servers to attempt to join the room through. One of the servers
+ * must be participating in the room.
+ * \param thirdPartySigned
+ * A signature of an ``m.third_party_invite`` token to prove that this
+ * user owns a third party identity which has been invited to the room.
+ */
+ explicit JoinRoomJob(
+ const QString& roomIdOrAlias, const QStringList& serverName = {},
+ const Omittable<ThirdPartySigned>& thirdPartySigned = none);
+
+ ~JoinRoomJob() override;
+
+ // Result properties
+
+ /// The joined room ID.
+ const QString& roomId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/keys.cpp b/lib/csapi/keys.cpp
index 862366a3..1752b865 100644
--- a/lib/csapi/keys.cpp
+++ b/lib/csapi/keys.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class UploadKeysJob::Private
{
- public:
+public:
QHash<QString, int> oneTimeKeyCounts;
};
@@ -22,8 +22,8 @@ static const auto UploadKeysJobName = QStringLiteral("UploadKeysJob");
UploadKeysJob::UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys,
const QHash<QString, QVariant>& oneTimeKeys)
- : BaseJob(HttpVerb::Post, UploadKeysJobName, basePath % "/keys/upload"),
- d(new Private)
+ : BaseJob(HttpVerb::Post, UploadKeysJobName, basePath % "/keys/upload")
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("device_keys"), deviceKeys);
@@ -42,37 +42,43 @@ BaseJob::Status UploadKeysJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("one_time_key_counts"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'one_time_key_counts' not found in the response" };
fromJson(json.value("one_time_key_counts"_ls), d->oneTimeKeyCounts);
+
return Success;
}
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo> {
- static void fillFrom(const QJsonObject& jo,
- QueryKeysJob::UnsignedDeviceInfo& result)
- {
- fromJson(jo.value("device_display_name"_ls),
- result.deviceDisplayName);
- }
- };
-
- template <> struct JsonObjectConverter<QueryKeysJob::DeviceInformation> {
- static void fillFrom(const QJsonObject& jo,
- QueryKeysJob::DeviceInformation& result)
- {
- fillFromJson<DeviceKeys>(jo, result);
- fromJson(jo.value("unsigned"_ls), result.unsignedData);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo>
+{
+ static void fillFrom(const QJsonObject& jo,
+ QueryKeysJob::UnsignedDeviceInfo& result)
+ {
+ fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName);
+ }
+};
+
+template <>
+struct JsonObjectConverter<QueryKeysJob::DeviceInformation>
+{
+ static void fillFrom(const QJsonObject& jo,
+ QueryKeysJob::DeviceInformation& result)
+ {
+ fillFromJson<DeviceKeys>(jo, result);
+ fromJson(jo.value("unsigned"_ls), result.unsignedData);
+ }
+};
+
} // namespace QMatrixClient
class QueryKeysJob::Private
{
- public:
+public:
QHash<QString, QJsonObject> failures;
QHash<QString, QHash<QString, DeviceInformation>> deviceKeys;
};
@@ -81,8 +87,8 @@ static const auto QueryKeysJobName = QStringLiteral("QueryKeysJob");
QueryKeysJob::QueryKeysJob(const QHash<QString, QStringList>& deviceKeys,
Omittable<int> timeout, const QString& token)
- : BaseJob(HttpVerb::Post, QueryKeysJobName, basePath % "/keys/query"),
- d(new Private)
+ : BaseJob(HttpVerb::Post, QueryKeysJobName, basePath % "/keys/query")
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
@@ -109,12 +115,13 @@ BaseJob::Status QueryKeysJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("failures"_ls), d->failures);
fromJson(json.value("device_keys"_ls), d->deviceKeys);
+
return Success;
}
class ClaimKeysJob::Private
{
- public:
+public:
QHash<QString, QJsonObject> failures;
QHash<QString, QHash<QString, QVariant>> oneTimeKeys;
};
@@ -122,10 +129,10 @@ class ClaimKeysJob::Private
static const auto ClaimKeysJobName = QStringLiteral("ClaimKeysJob");
ClaimKeysJob::ClaimKeysJob(
- const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
- Omittable<int> timeout)
- : BaseJob(HttpVerb::Post, ClaimKeysJobName, basePath % "/keys/claim"),
- d(new Private)
+ const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
+ Omittable<int> timeout)
+ : BaseJob(HttpVerb::Post, ClaimKeysJobName, basePath % "/keys/claim")
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
@@ -140,8 +147,7 @@ const QHash<QString, QJsonObject>& ClaimKeysJob::failures() const
return d->failures;
}
-const QHash<QString, QHash<QString, QVariant>>&
-ClaimKeysJob::oneTimeKeys() const
+const QHash<QString, QHash<QString, QVariant>>& ClaimKeysJob::oneTimeKeys() const
{
return d->oneTimeKeys;
}
@@ -151,12 +157,13 @@ BaseJob::Status ClaimKeysJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("failures"_ls), d->failures);
fromJson(json.value("one_time_keys"_ls), d->oneTimeKeys);
+
return Success;
}
class GetKeysChangesJob::Private
{
- public:
+public:
QStringList changed;
QStringList left;
};
@@ -181,10 +188,9 @@ static const auto GetKeysChangesJobName = QStringLiteral("GetKeysChangesJob");
GetKeysChangesJob::GetKeysChangesJob(const QString& from, const QString& to)
: BaseJob(HttpVerb::Get, GetKeysChangesJobName, basePath % "/keys/changes",
- queryToGetKeysChanges(from, to)),
- d(new Private)
-{
-}
+ queryToGetKeysChanges(from, to))
+ , d(new Private)
+{}
GetKeysChangesJob::~GetKeysChangesJob() = default;
@@ -197,5 +203,6 @@ BaseJob::Status GetKeysChangesJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("changed"_ls), d->changed);
fromJson(json.value("left"_ls), d->left);
+
return Success;
}
diff --git a/lib/csapi/keys.h b/lib/csapi/keys.h
index a01cd33b..f69028fd 100644
--- a/lib/csapi/keys.h
+++ b/lib/csapi/keys.h
@@ -4,223 +4,231 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/device_keys.h"
+
+#include "jobs/basejob.h"
+
#include <QtCore/QHash>
#include <QtCore/QJsonObject>
#include <QtCore/QVariant>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
- /// Upload end-to-end encryption keys.
- ///
- /// Publishes end-to-end encryption keys for the device.
- class UploadKeysJob : public BaseJob
- {
- public:
- /*! Upload end-to-end encryption keys.
- * \param deviceKeys
- * Identity keys for the device. May be absent if no new
- * identity keys are required.
- * \param oneTimeKeys
- * One-time public keys for "pre-key" messages. The names of
- * the properties should be in the format
- * ``<algorithm>:<key_id>``. The format of the key is determined
- * by the key algorithm.
- *
- * May be absent if no new one-time keys are required.
- */
- explicit UploadKeysJob(
- const Omittable<DeviceKeys>& deviceKeys = none,
- const QHash<QString, QVariant>& oneTimeKeys = {});
- ~UploadKeysJob() override;
-
- // Result properties
-
- /// For each key algorithm, the number of unclaimed one-time keys
- /// of that type currently held on the server for this device.
- const QHash<QString, int>& oneTimeKeyCounts() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+// Operations
- /// Download device identity keys.
- ///
- /// Returns the current devices and identity keys for the given users.
- class QueryKeysJob : public BaseJob
+/// Upload end-to-end encryption keys.
+/*!
+ * Publishes end-to-end encryption keys for the device.
+ */
+class UploadKeysJob : public BaseJob
+{
+public:
+ /*! Upload end-to-end encryption keys.
+ * \param deviceKeys
+ * Identity keys for the device. May be absent if no new
+ * identity keys are required.
+ * \param oneTimeKeys
+ * One-time public keys for "pre-key" messages. The names of
+ * the properties should be in the format
+ * ``<algorithm>:<key_id>``. The format of the key is determined
+ * by the key algorithm.
+ *
+ * May be absent if no new one-time keys are required.
+ */
+ explicit UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys = none,
+ const QHash<QString, QVariant>& oneTimeKeys = {});
+
+ ~UploadKeysJob() override;
+
+ // Result properties
+
+ /// For each key algorithm, the number of unclaimed one-time keys
+ /// of that type currently held on the server for this device.
+ const QHash<QString, int>& oneTimeKeyCounts() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Download device identity keys.
+/*!
+ * Returns the current devices and identity keys for the given users.
+ */
+class QueryKeysJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// Additional data added to the device key informationby intermediate
+ /// servers, and not covered by thesignatures.
+ struct UnsignedDeviceInfo
{
- public:
- // Inner data structures
-
- /// Additional data added to the device key information
- /// by intermediate servers, and not covered by the
- /// signatures.
- struct UnsignedDeviceInfo {
- /// The display name which the user set on the device.
- QString deviceDisplayName;
- };
-
- /// Returns the current devices and identity keys for the given users.
- struct DeviceInformation : DeviceKeys {
- /// Additional data added to the device key information
- /// by intermediate servers, and not covered by the
- /// signatures.
- Omittable<UnsignedDeviceInfo> unsignedData;
- };
-
- // Construction/destruction
-
- /*! Download device identity keys.
- * \param deviceKeys
- * The keys to be downloaded. A map from user ID, to a list of
- * device IDs, or to an empty list to indicate all devices for the
- * corresponding user.
- * \param timeout
- * The time (in milliseconds) to wait when downloading keys from
- * remote servers. 10 seconds is the recommended default.
- * \param token
- * If the client is fetching keys as a result of a device update
- * received in a sync request, this should be the 'since' token of that
- * sync request, or any later sync token. This allows the server to
- * ensure its response contains the keys advertised by the notification
- * in that sync.
- */
- explicit QueryKeysJob(const QHash<QString, QStringList>& deviceKeys,
- Omittable<int> timeout = none,
- const QString& token = {});
- ~QueryKeysJob() override;
-
- // Result properties
-
- /// If any remote homeservers could not be reached, they are
- /// recorded here. The names of the properties are the names of
- /// the unreachable servers.
- ///
- /// If the homeserver could be reached, but the user or device
- /// was unknown, no failure is recorded. Instead, the corresponding
- /// user or device is missing from the ``device_keys`` result.
- const QHash<QString, QJsonObject>& failures() const;
- /// Information on the queried devices. A map from user ID, to a
- /// map from device ID to device information. For each device,
- /// the information returned will be the same as uploaded via
- /// ``/keys/upload``, with the addition of an ``unsigned``
- /// property.
- const QHash<QString, QHash<QString, DeviceInformation>>&
- deviceKeys() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// The display name which the user set on the device.
+ QString deviceDisplayName;
};
- /// Claim one-time encryption keys.
- ///
- /// Claims one-time keys for use in pre-key messages.
- class ClaimKeysJob : public BaseJob
+ /// Returns the current devices and identity keys for the given users.
+ struct DeviceInformation : DeviceKeys
{
- public:
- /*! Claim one-time encryption keys.
- * \param oneTimeKeys
- * The keys to be claimed. A map from user ID, to a map from
- * device ID to algorithm name.
- * \param timeout
- * The time (in milliseconds) to wait when downloading keys from
- * remote servers. 10 seconds is the recommended default.
- */
- explicit ClaimKeysJob(
- const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
- Omittable<int> timeout = none);
- ~ClaimKeysJob() override;
-
- // Result properties
-
- /// If any remote homeservers could not be reached, they are
- /// recorded here. The names of the properties are the names of
- /// the unreachable servers.
- ///
- /// If the homeserver could be reached, but the user or device
- /// was unknown, no failure is recorded. Instead, the corresponding
- /// user or device is missing from the ``one_time_keys`` result.
- const QHash<QString, QJsonObject>& failures() const;
- /// One-time keys for the queried devices. A map from user ID, to a
- /// map from devices to a map from ``<algorithm>:<key_id>`` to the key
- /// object.
- const QHash<QString, QHash<QString, QVariant>>& oneTimeKeys() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// Additional data added to the device key informationby intermediate
+ /// servers, and not covered by thesignatures.
+ Omittable<UnsignedDeviceInfo> unsignedData;
};
- /// Query users with recent device key updates.
- ///
- /// Gets a list of users who have updated their device identity keys since a
- /// previous sync token.
+ // Construction/destruction
+
+ /*! Download device identity keys.
+ * \param deviceKeys
+ * The keys to be downloaded. A map from user ID, to a list of
+ * device IDs, or to an empty list to indicate all devices for the
+ * corresponding user.
+ * \param timeout
+ * The time (in milliseconds) to wait when downloading keys from
+ * remote servers. 10 seconds is the recommended default.
+ * \param token
+ * If the client is fetching keys as a result of a device update received
+ * in a sync request, this should be the 'since' token of that sync
+ * request, or any later sync token. This allows the server to ensure its
+ * response contains the keys advertised by the notification in that sync.
+ */
+ explicit QueryKeysJob(const QHash<QString, QStringList>& deviceKeys,
+ Omittable<int> timeout = none,
+ const QString& token = {});
+
+ ~QueryKeysJob() override;
+
+ // Result properties
+
+ /// If any remote homeservers could not be reached, they are
+ /// recorded here. The names of the properties are the names of
+ /// the unreachable servers.
///
- /// The server should include in the results any users who:
+ /// If the homeserver could be reached, but the user or device
+ /// was unknown, no failure is recorded. Instead, the corresponding
+ /// user or device is missing from the ``device_keys`` result.
+ const QHash<QString, QJsonObject>& failures() const;
+ /// Information on the queried devices. A map from user ID, to a
+ /// map from device ID to device information. For each device,
+ /// the information returned will be the same as uploaded via
+ /// ``/keys/upload``, with the addition of an ``unsigned``
+ /// property.
+ const QHash<QString, QHash<QString, DeviceInformation>>& deviceKeys() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Claim one-time encryption keys.
+/*!
+ * Claims one-time keys for use in pre-key messages.
+ */
+class ClaimKeysJob : public BaseJob
+{
+public:
+ /*! Claim one-time encryption keys.
+ * \param oneTimeKeys
+ * The keys to be claimed. A map from user ID, to a map from
+ * device ID to algorithm name.
+ * \param timeout
+ * The time (in milliseconds) to wait when downloading keys from
+ * remote servers. 10 seconds is the recommended default.
+ */
+ explicit ClaimKeysJob(
+ const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
+ Omittable<int> timeout = none);
+
+ ~ClaimKeysJob() override;
+
+ // Result properties
+
+ /// If any remote homeservers could not be reached, they are
+ /// recorded here. The names of the properties are the names of
+ /// the unreachable servers.
///
- /// * currently share a room with the calling user (ie, both users have
- /// membership state ``join``); *and*
- /// * added new device identity keys or removed an existing device with
- /// identity keys, between ``from`` and ``to``.
- class GetKeysChangesJob : public BaseJob
- {
- public:
- /*! Query users with recent device key updates.
- * \param from
- * The desired start point of the list. Should be the ``next_batch``
- * field from a response to an earlier call to |/sync|. Users who have
- * not uploaded new device identity keys since this point, nor deleted
- * existing devices with identity keys since then, will be excluded
- * from the results.
- * \param to
- * The desired end point of the list. Should be the ``next_batch``
- * field from a recent call to |/sync| - typically the most recent
- * such call. This may be used by the server as a hint to check its
- * caches are up to date.
- */
- explicit GetKeysChangesJob(const QString& from, const QString& to);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetKeysChangesJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& from,
- const QString& to);
-
- ~GetKeysChangesJob() override;
-
- // Result properties
-
- /// The Matrix User IDs of all users who updated their device
- /// identity keys.
- const QStringList& changed() const;
- /// The Matrix User IDs of all users who may have left all
- /// the end-to-end encrypted rooms they previously shared
- /// with the user.
- const QStringList& left() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ /// If the homeserver could be reached, but the user or device
+ /// was unknown, no failure is recorded. Instead, the corresponding
+ /// user or device is missing from the ``one_time_keys`` result.
+ const QHash<QString, QJsonObject>& failures() const;
+ /// One-time keys for the queried devices. A map from user ID, to a
+ /// map from devices to a map from ``<algorithm>:<key_id>`` to the key object.
+ const QHash<QString, QHash<QString, QVariant>>& oneTimeKeys() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Query users with recent device key updates.
+/*!
+ * Gets a list of users who have updated their device identity keys since a
+ * previous sync token.
+ *
+ * The server should include in the results any users who:
+ *
+ * * currently share a room with the calling user (ie, both users have
+ * membership state ``join``); *and*
+ * * added new device identity keys or removed an existing device with
+ * identity keys, between ``from`` and ``to``.
+ */
+class GetKeysChangesJob : public BaseJob
+{
+public:
+ /*! Query users with recent device key updates.
+ * \param from
+ * The desired start point of the list. Should be the ``next_batch`` field
+ * from a response to an earlier call to |/sync|. Users who have not
+ * uploaded new device identity keys since this point, nor deleted
+ * existing devices with identity keys since then, will be excluded
+ * from the results.
+ * \param to
+ * The desired end point of the list. Should be the ``next_batch``
+ * field from a recent call to |/sync| - typically the most recent
+ * such call. This may be used by the server as a hint to check its
+ * caches are up to date.
+ */
+ explicit GetKeysChangesJob(const QString& from, const QString& to);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetKeysChangesJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& from,
+ const QString& to);
+
+ ~GetKeysChangesJob() override;
+
+ // Result properties
+
+ /// The Matrix User IDs of all users who updated their device
+ /// identity keys.
+ const QStringList& changed() const;
+ /// The Matrix User IDs of all users who may have left all
+ /// the end-to-end encrypted rooms they previously shared
+ /// with the user.
+ const QStringList& left() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/kicking.h b/lib/csapi/kicking.h
index d75b8df3..9566a9a4 100644
--- a/lib/csapi/kicking.h
+++ b/lib/csapi/kicking.h
@@ -6,32 +6,37 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Kick a user from the room.
+/*!
+ * Kick a user from the room.
+ *
+ * The caller must have the required power level in order to perform this
+ * operation.
+ *
+ * Kicking a user adjusts the target member's membership state to be ``leave``
+ * with an optional ``reason``. Like with other membership changes, a user can
+ * directly adjust the target member's state by making a request to
+ * ``/rooms/<room id>/state/m.room.member/<user id>``.
+ */
+class KickJob : public BaseJob
+{
+public:
+ /*! Kick a user from the room.
+ * \param roomId
+ * The room identifier (not alias) from which the user should be kicked.
+ * \param userId
+ * The fully qualified user ID of the user being kicked.
+ * \param reason
+ * The reason the user has been kicked. This will be supplied as the
+ * ``reason`` on the target's updated `m.room.member`_ event.
+ */
+ explicit KickJob(const QString& roomId, const QString& userId,
+ const QString& reason = {});
+};
- /// Kick a user from the room.
- ///
- /// Kick a user from the room.
- ///
- /// The caller must have the required power level in order to perform this
- /// operation.
- ///
- /// Kicking a user adjusts the target member's membership state to be
- /// ``leave`` with an optional ``reason``. Like with other membership
- /// changes, a user can directly adjust the target member's state by making
- /// a request to ``/rooms/<room id>/state/m.room.member/<user id>``.
- class KickJob : public BaseJob
- {
- public:
- /*! Kick a user from the room.
- * \param roomId
- * The room identifier (not alias) from which the user should be
- * kicked. \param userId The fully qualified user ID of the user being
- * kicked. \param reason The reason the user has been kicked. This will
- * be supplied as the
- * ``reason`` on the target's updated `m.room.member`_ event.
- */
- explicit KickJob(const QString& roomId, const QString& userId,
- const QString& reason = {});
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/leaving.cpp b/lib/csapi/leaving.cpp
index c46567d7..325b1e04 100644
--- a/lib/csapi/leaving.cpp
+++ b/lib/csapi/leaving.cpp
@@ -23,8 +23,7 @@ static const auto LeaveRoomJobName = QStringLiteral("LeaveRoomJob");
LeaveRoomJob::LeaveRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Post, LeaveRoomJobName,
basePath % "/rooms/" % roomId % "/leave")
-{
-}
+{}
QUrl ForgetRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
@@ -37,5 +36,4 @@ static const auto ForgetRoomJobName = QStringLiteral("ForgetRoomJob");
ForgetRoomJob::ForgetRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Post, ForgetRoomJobName,
basePath % "/rooms/" % roomId % "/forget")
-{
-}
+{}
diff --git a/lib/csapi/leaving.h b/lib/csapi/leaving.h
index 374d27d4..2ed6c8e7 100644
--- a/lib/csapi/leaving.h
+++ b/lib/csapi/leaving.h
@@ -6,66 +6,71 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
- /// Stop the requesting user participating in a particular room.
- ///
- /// This API stops a user participating in a particular room.
- ///
- /// If the user was already in the room, they will no longer be able to see
- /// new events in the room. If the room requires an invite to join, they
- /// will need to be re-invited before they can re-join.
- ///
- /// If the user was invited to the room, but had not joined, this call
- /// serves to reject the invite.
- ///
- /// The user will still be allowed to retrieve history from the room which
- /// they were previously allowed to see.
- class LeaveRoomJob : public BaseJob
- {
- public:
- /*! Stop the requesting user participating in a particular room.
- * \param roomId
- * The room identifier to leave.
- */
- explicit LeaveRoomJob(const QString& roomId);
+// Operations
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * LeaveRoomJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
- };
+/// Stop the requesting user participating in a particular room.
+/*!
+ * This API stops a user participating in a particular room.
+ *
+ * If the user was already in the room, they will no longer be able to see
+ * new events in the room. If the room requires an invite to join, they
+ * will need to be re-invited before they can re-join.
+ *
+ * If the user was invited to the room, but had not joined, this call
+ * serves to reject the invite.
+ *
+ * The user will still be allowed to retrieve history from the room which
+ * they were previously allowed to see.
+ */
+class LeaveRoomJob : public BaseJob
+{
+public:
+ /*! Stop the requesting user participating in a particular room.
+ * \param roomId
+ * The room identifier to leave.
+ */
+ explicit LeaveRoomJob(const QString& roomId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * LeaveRoomJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+};
+
+/// Stop the requesting user remembering about a particular room.
+/*!
+ * This API stops a user remembering about a particular room.
+ *
+ * In general, history is a first class citizen in Matrix. After this API
+ * is called, however, a user will no longer be able to retrieve history
+ * for this room. If all users on a homeserver forget a room, the room is
+ * eligible for deletion from that homeserver.
+ *
+ * If the user is currently joined to the room, they must leave the room
+ * before calling this API.
+ */
+class ForgetRoomJob : public BaseJob
+{
+public:
+ /*! Stop the requesting user remembering about a particular room.
+ * \param roomId
+ * The room identifier to forget.
+ */
+ explicit ForgetRoomJob(const QString& roomId);
- /// Stop the requesting user remembering about a particular room.
- ///
- /// This API stops a user remembering about a particular room.
- ///
- /// In general, history is a first class citizen in Matrix. After this API
- /// is called, however, a user will no longer be able to retrieve history
- /// for this room. If all users on a homeserver forget a room, the room is
- /// eligible for deletion from that homeserver.
- ///
- /// If the user is currently joined to the room, they must leave the room
- /// before calling this API.
- class ForgetRoomJob : public BaseJob
- {
- public:
- /*! Stop the requesting user remembering about a particular room.
- * \param roomId
- * The room identifier to forget.
- */
- explicit ForgetRoomJob(const QString& roomId);
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * ForgetRoomJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+};
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * ForgetRoomJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp
index 145e91ad..43c948f7 100644
--- a/lib/csapi/list_joined_rooms.cpp
+++ b/lib/csapi/list_joined_rooms.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetJoinedRoomsJob::Private
{
- public:
+public:
QStringList joinedRooms;
};
@@ -27,10 +27,9 @@ QUrl GetJoinedRoomsJob::makeRequestUrl(QUrl baseUrl)
static const auto GetJoinedRoomsJobName = QStringLiteral("GetJoinedRoomsJob");
GetJoinedRoomsJob::GetJoinedRoomsJob()
- : BaseJob(HttpVerb::Get, GetJoinedRoomsJobName, basePath % "/joined_rooms"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetJoinedRoomsJobName, basePath % "/joined_rooms")
+ , d(new Private)
+{}
GetJoinedRoomsJob::~GetJoinedRoomsJob() = default;
@@ -43,8 +42,9 @@ BaseJob::Status GetJoinedRoomsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("joined_rooms"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'joined_rooms' not found in the response" };
fromJson(json.value("joined_rooms"_ls), d->joinedRooms);
+
return Success;
}
diff --git a/lib/csapi/list_joined_rooms.h b/lib/csapi/list_joined_rooms.h
index 6f4169e8..1b64a004 100644
--- a/lib/csapi/list_joined_rooms.h
+++ b/lib/csapi/list_joined_rooms.h
@@ -6,37 +6,41 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Lists the user's current rooms.
- ///
- /// This API returns a list of the user's current rooms.
- class GetJoinedRoomsJob : public BaseJob
- {
- public:
- explicit GetJoinedRoomsJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetJoinedRoomsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetJoinedRoomsJob() override;
-
- // Result properties
-
- /// The ID of each room in which the user has ``joined`` membership.
- const QStringList& joinedRooms() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Lists the user's current rooms.
+/*!
+ * This API returns a list of the user's current rooms.
+ */
+class GetJoinedRoomsJob : public BaseJob
+{
+public:
+ explicit GetJoinedRoomsJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetJoinedRoomsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetJoinedRoomsJob() override;
+
+ // Result properties
+
+ /// The ID of each room in which the user has ``joined`` membership.
+ const QStringList& joinedRooms() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/list_public_rooms.cpp b/lib/csapi/list_public_rooms.cpp
index 2649b9f8..4d96dac3 100644
--- a/lib/csapi/list_public_rooms.cpp
+++ b/lib/csapi/list_public_rooms.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetRoomVisibilityOnDirectoryJob::Private
{
- public:
+public:
QString visibility;
};
@@ -26,15 +26,14 @@ QUrl GetRoomVisibilityOnDirectoryJob::makeRequestUrl(QUrl baseUrl,
}
static const auto GetRoomVisibilityOnDirectoryJobName =
- QStringLiteral("GetRoomVisibilityOnDirectoryJob");
+ QStringLiteral("GetRoomVisibilityOnDirectoryJob");
GetRoomVisibilityOnDirectoryJob::GetRoomVisibilityOnDirectoryJob(
- const QString& roomId)
+ const QString& roomId)
: BaseJob(HttpVerb::Get, GetRoomVisibilityOnDirectoryJobName,
- basePath % "/directory/list/room/" % roomId, false),
- d(new Private)
-{
-}
+ basePath % "/directory/list/room/" % roomId, false)
+ , d(new Private)
+{}
GetRoomVisibilityOnDirectoryJob::~GetRoomVisibilityOnDirectoryJob() = default;
@@ -48,14 +47,15 @@ GetRoomVisibilityOnDirectoryJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("visibility"_ls), d->visibility);
+
return Success;
}
static const auto SetRoomVisibilityOnDirectoryJobName =
- QStringLiteral("SetRoomVisibilityOnDirectoryJob");
+ QStringLiteral("SetRoomVisibilityOnDirectoryJob");
SetRoomVisibilityOnDirectoryJob::SetRoomVisibilityOnDirectoryJob(
- const QString& roomId, const QString& visibility)
+ const QString& roomId, const QString& visibility)
: BaseJob(HttpVerb::Put, SetRoomVisibilityOnDirectoryJobName,
basePath % "/directory/list/room/" % roomId)
{
@@ -66,7 +66,7 @@ SetRoomVisibilityOnDirectoryJob::SetRoomVisibilityOnDirectoryJob(
class GetPublicRoomsJob::Private
{
- public:
+public:
PublicRoomsResponse data;
};
@@ -84,8 +84,7 @@ QUrl GetPublicRoomsJob::makeRequestUrl(QUrl baseUrl, Omittable<int> limit,
const QString& since,
const QString& server)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/publicRooms",
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/publicRooms",
queryToGetPublicRooms(limit, since, server));
}
@@ -94,10 +93,9 @@ static const auto GetPublicRoomsJobName = QStringLiteral("GetPublicRoomsJob");
GetPublicRoomsJob::GetPublicRoomsJob(Omittable<int> limit, const QString& since,
const QString& server)
: BaseJob(HttpVerb::Get, GetPublicRoomsJobName, basePath % "/publicRooms",
- queryToGetPublicRooms(limit, since, server), {}, false),
- d(new Private)
-{
-}
+ queryToGetPublicRooms(limit, since, server), {}, false)
+ , d(new Private)
+{}
GetPublicRoomsJob::~GetPublicRoomsJob() = default;
@@ -109,22 +107,25 @@ BaseJob::Status GetPublicRoomsJob::parseJson(const QJsonDocument& data)
return Success;
}
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<QueryPublicRoomsJob::Filter> {
- static void dumpTo(QJsonObject& jo,
- const QueryPublicRoomsJob::Filter& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("generic_search_term"),
- pod.genericSearchTerm);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<QueryPublicRoomsJob::Filter>
+{
+ static void dumpTo(QJsonObject& jo, const QueryPublicRoomsJob::Filter& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("generic_search_term"),
+ pod.genericSearchTerm);
+ }
+};
+
} // namespace QMatrixClient
class QueryPublicRoomsJob::Private
{
- public:
+public:
PublicRoomsResponse data;
};
@@ -136,7 +137,7 @@ BaseJob::Query queryToQueryPublicRooms(const QString& server)
}
static const auto QueryPublicRoomsJobName =
- QStringLiteral("QueryPublicRoomsJob");
+ QStringLiteral("QueryPublicRoomsJob");
QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server,
Omittable<int> limit,
@@ -145,8 +146,8 @@ QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server,
Omittable<bool> includeAllNetworks,
const QString& thirdPartyInstanceId)
: BaseJob(HttpVerb::Post, QueryPublicRoomsJobName,
- basePath % "/publicRooms", queryToQueryPublicRooms(server)),
- d(new Private)
+ basePath % "/publicRooms", queryToQueryPublicRooms(server))
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("limit"), limit);
diff --git a/lib/csapi/list_public_rooms.h b/lib/csapi/list_public_rooms.h
index 1a0af880..da68416d 100644
--- a/lib/csapi/list_public_rooms.h
+++ b/lib/csapi/list_public_rooms.h
@@ -4,180 +4,189 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/public_rooms_response.h"
-namespace QMatrixClient {
- // Operations
+#include "jobs/basejob.h"
- /// Gets the visibility of a room in the directory
- ///
- /// Gets the visibility of a given room on the server's public room
- /// directory.
- class GetRoomVisibilityOnDirectoryJob : public BaseJob
- {
- public:
- /*! Gets the visibility of a room in the directory
- * \param roomId
- * The room ID.
- */
- explicit GetRoomVisibilityOnDirectoryJob(const QString& roomId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomVisibilityOnDirectoryJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
-
- ~GetRoomVisibilityOnDirectoryJob() override;
-
- // Result properties
-
- /// The visibility of the room in the directory.
- const QString& visibility() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
- /// Sets the visibility of a room in the room directory
- ///
- /// Sets the visibility of a given room in the server's public room
- /// directory.
- ///
- /// Servers may choose to implement additional access control checks
- /// here, for instance that room visibility can only be changed by
- /// the room creator or a server administrator.
- class SetRoomVisibilityOnDirectoryJob : public BaseJob
- {
- public:
- /*! Sets the visibility of a room in the room directory
- * \param roomId
- * The room ID.
- * \param visibility
- * The new visibility setting for the room.
- * Defaults to 'public'.
- */
- explicit SetRoomVisibilityOnDirectoryJob(
- const QString& roomId, const QString& visibility = {});
- };
+// Operations
- /// Lists the public rooms on the server.
- ///
- /// Lists the public rooms on the server.
- ///
- /// This API returns paginated responses. The rooms are ordered by the
- /// number of joined members, with the largest rooms first.
- class GetPublicRoomsJob : public BaseJob
- {
- public:
- /*! Lists the public rooms on the server.
- * \param limit
- * Limit the number of results returned.
- * \param since
- * A pagination token from a previous request, allowing clients to
- * get the next (or previous) batch of rooms.
- * The direction of pagination is specified solely by which token
- * is supplied, rather than via an explicit flag.
- * \param server
- * The server to fetch the public room lists from. Defaults to the
- * local server.
- */
- explicit GetPublicRoomsJob(Omittable<int> limit = none,
- const QString& since = {},
- const QString& server = {});
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetPublicRoomsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, Omittable<int> limit = none,
- const QString& since = {},
- const QString& server = {});
-
- ~GetPublicRoomsJob() override;
-
- // Result properties
-
- /// A list of the rooms on the server.
- const PublicRoomsResponse& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+/// Gets the visibility of a room in the directory
+/*!
+ * Gets the visibility of a given room on the server's public room directory.
+ */
+class GetRoomVisibilityOnDirectoryJob : public BaseJob
+{
+public:
+ /*! Gets the visibility of a room in the directory
+ * \param roomId
+ * The room ID.
+ */
+ explicit GetRoomVisibilityOnDirectoryJob(const QString& roomId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomVisibilityOnDirectoryJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+
+ ~GetRoomVisibilityOnDirectoryJob() override;
+
+ // Result properties
+
+ /// The visibility of the room in the directory.
+ const QString& visibility() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Sets the visibility of a room in the room directory
+/*!
+ * Sets the visibility of a given room in the server's public room
+ * directory.
+ *
+ * Servers may choose to implement additional access control checks
+ * here, for instance that room visibility can only be changed by
+ * the room creator or a server administrator.
+ */
+class SetRoomVisibilityOnDirectoryJob : public BaseJob
+{
+public:
+ /*! Sets the visibility of a room in the room directory
+ * \param roomId
+ * The room ID.
+ * \param visibility
+ * The new visibility setting for the room.
+ * Defaults to 'public'.
+ */
+ explicit SetRoomVisibilityOnDirectoryJob(const QString& roomId,
+ const QString& visibility = {});
+};
+
+/// Lists the public rooms on the server.
+/*!
+ * Lists the public rooms on the server.
+ *
+ * This API returns paginated responses. The rooms are ordered by the number
+ * of joined members, with the largest rooms first.
+ */
+class GetPublicRoomsJob : public BaseJob
+{
+public:
+ /*! Lists the public rooms on the server.
+ * \param limit
+ * Limit the number of results returned.
+ * \param since
+ * A pagination token from a previous request, allowing clients to
+ * get the next (or previous) batch of rooms.
+ * The direction of pagination is specified solely by which token
+ * is supplied, rather than via an explicit flag.
+ * \param server
+ * The server to fetch the public room lists from. Defaults to the
+ * local server.
+ */
+ explicit GetPublicRoomsJob(Omittable<int> limit = none,
+ const QString& since = {},
+ const QString& server = {});
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetPublicRoomsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, Omittable<int> limit = none,
+ const QString& since = {},
+ const QString& server = {});
+
+ ~GetPublicRoomsJob() override;
+
+ // Result properties
+
+ /// A list of the rooms on the server.
+ const PublicRoomsResponse& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Lists the public rooms on the server with optional filter.
+/*!
+ * Lists the public rooms on the server, with optional filter.
+ *
+ * This API returns paginated responses. The rooms are ordered by the number
+ * of joined members, with the largest rooms first.
+ */
+class QueryPublicRoomsJob : public BaseJob
+{
+public:
+ // Inner data structures
- /// Lists the public rooms on the server with optional filter.
- ///
- /// Lists the public rooms on the server, with optional filter.
- ///
- /// This API returns paginated responses. The rooms are ordered by the
- /// number of joined members, with the largest rooms first.
- class QueryPublicRoomsJob : public BaseJob
+ /// Filter to apply to the results.
+ struct Filter
{
- public:
- // Inner data structures
-
- /// Filter to apply to the results.
- struct Filter {
- /// A string to search for in the room metadata, e.g. name,
- /// topic, canonical alias etc. (Optional).
- QString genericSearchTerm;
- };
-
- // Construction/destruction
-
- /*! Lists the public rooms on the server with optional filter.
- * \param server
- * The server to fetch the public room lists from. Defaults to the
- * local server.
- * \param limit
- * Limit the number of results returned.
- * \param since
- * A pagination token from a previous request, allowing clients
- * to get the next (or previous) batch of rooms. The direction
- * of pagination is specified solely by which token is supplied,
- * rather than via an explicit flag.
- * \param filter
- * Filter to apply to the results.
- * \param includeAllNetworks
- * Whether or not to include all known networks/protocols from
- * application services on the homeserver. Defaults to false.
- * \param thirdPartyInstanceId
- * The specific third party network/protocol to request from the
- * homeserver. Can only be used if ``include_all_networks`` is false.
- */
- explicit QueryPublicRoomsJob(const QString& server = {},
- Omittable<int> limit = none,
- const QString& since = {},
- const Omittable<Filter>& filter = none,
- Omittable<bool> includeAllNetworks = none,
- const QString& thirdPartyInstanceId = {});
- ~QueryPublicRoomsJob() override;
-
- // Result properties
-
- /// A list of the rooms on the server.
- const PublicRoomsResponse& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// A string to search for in the room metadata, e.g. name,topic,
+ /// canonical alias etc. (Optional).
+ QString genericSearchTerm;
};
+
+ // Construction/destruction
+
+ /*! Lists the public rooms on the server with optional filter.
+ * \param server
+ * The server to fetch the public room lists from. Defaults to the
+ * local server.
+ * \param limit
+ * Limit the number of results returned.
+ * \param since
+ * A pagination token from a previous request, allowing clients
+ * to get the next (or previous) batch of rooms. The direction
+ * of pagination is specified solely by which token is supplied,
+ * rather than via an explicit flag.
+ * \param filter
+ * Filter to apply to the results.
+ * \param includeAllNetworks
+ * Whether or not to include all known networks/protocols from
+ * application services on the homeserver. Defaults to false.
+ * \param thirdPartyInstanceId
+ * The specific third party network/protocol to request from the
+ * homeserver. Can only be used if ``include_all_networks`` is false.
+ */
+ explicit QueryPublicRoomsJob(const QString& server = {},
+ Omittable<int> limit = none,
+ const QString& since = {},
+ const Omittable<Filter>& filter = none,
+ Omittable<bool> includeAllNetworks = none,
+ const QString& thirdPartyInstanceId = {});
+
+ ~QueryPublicRoomsJob() override;
+
+ // Result properties
+
+ /// A list of the rooms on the server.
+ const PublicRoomsResponse& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/login.cpp b/lib/csapi/login.cpp
index 77652e64..29ee4ab5 100644
--- a/lib/csapi/login.cpp
+++ b/lib/csapi/login.cpp
@@ -12,21 +12,25 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<GetLoginFlowsJob::LoginFlow> {
- static void fillFrom(const QJsonObject& jo,
- GetLoginFlowsJob::LoginFlow& result)
- {
- fromJson(jo.value("type"_ls), result.type);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetLoginFlowsJob::LoginFlow>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetLoginFlowsJob::LoginFlow& result)
+ {
+ fromJson(jo.value("type"_ls), result.type);
+ }
+};
+
} // namespace QMatrixClient
class GetLoginFlowsJob::Private
{
- public:
+public:
QVector<LoginFlow> flows;
};
@@ -38,10 +42,9 @@ QUrl GetLoginFlowsJob::makeRequestUrl(QUrl baseUrl)
static const auto GetLoginFlowsJobName = QStringLiteral("GetLoginFlowsJob");
GetLoginFlowsJob::GetLoginFlowsJob()
- : BaseJob(HttpVerb::Get, GetLoginFlowsJobName, basePath % "/login", false),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetLoginFlowsJobName, basePath % "/login", false)
+ , d(new Private)
+{}
GetLoginFlowsJob::~GetLoginFlowsJob() = default;
@@ -54,12 +57,13 @@ BaseJob::Status GetLoginFlowsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("flows"_ls), d->flows);
+
return Success;
}
class LoginJob::Private
{
- public:
+public:
QString userId;
QString accessToken;
QString homeServer;
@@ -75,8 +79,8 @@ LoginJob::LoginJob(const QString& type,
const QString& deviceId,
const QString& initialDeviceDisplayName, const QString& user,
const QString& medium, const QString& address)
- : BaseJob(HttpVerb::Post, LoginJobName, basePath % "/login", false),
- d(new Private)
+ : BaseJob(HttpVerb::Post, LoginJobName, basePath % "/login", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("type"), type);
@@ -115,5 +119,6 @@ BaseJob::Status LoginJob::parseJson(const QJsonDocument& data)
fromJson(json.value("home_server"_ls), d->homeServer);
fromJson(json.value("device_id"_ls), d->deviceId);
fromJson(json.value("well_known"_ls), d->wellKnown);
+
return Success;
}
diff --git a/lib/csapi/login.h b/lib/csapi/login.h
index 89c8ca79..3ab0648f 100644
--- a/lib/csapi/login.h
+++ b/lib/csapi/login.h
@@ -4,140 +4,143 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/user_identifier.h"
#include "csapi/definitions/wellknown/full.h"
-#include <QtCore/QVector>
-
-namespace QMatrixClient {
- // Operations
-
- /// Get the supported login types to authenticate users
- ///
- /// Gets the homeserver's supported login types to authenticate users.
- /// Clients should pick one of these and supply it as the ``type`` when
- /// logging in.
- class GetLoginFlowsJob : public BaseJob
- {
- public:
- // Inner data structures
-
- /// Gets the homeserver's supported login types to authenticate users.
- /// Clients should pick one of these and supply it as the ``type`` when
- /// logging in.
- struct LoginFlow {
- /// The login type. This is supplied as the ``type`` when
- /// logging in.
- QString type;
- };
-
- // Construction/destruction
-
- explicit GetLoginFlowsJob();
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetLoginFlowsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
+#include "jobs/basejob.h"
- ~GetLoginFlowsJob() override;
+#include <QtCore/QVector>
- // Result properties
+namespace QMatrixClient
+{
- /// The homeserver's supported login types
- const QVector<LoginFlow>& flows() const;
+// Operations
- protected:
- Status parseJson(const QJsonDocument& data) override;
+/// Get the supported login types to authenticate users
+/*!
+ * Gets the homeserver's supported login types to authenticate users. Clients
+ * should pick one of these and supply it as the ``type`` when logging in.
+ */
+class GetLoginFlowsJob : public BaseJob
+{
+public:
+ // Inner data structures
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// Gets the homeserver's supported login types to authenticate users.
+ /// Clientsshould pick one of these and supply it as the ``type`` when
+ /// logging in.
+ struct LoginFlow
+ {
+ /// The login type. This is supplied as the ``type`` whenlogging in.
+ QString type;
};
- /// Authenticates the user.
- ///
- /// Authenticates the user, and issues an access token they can
- /// use to authorize themself in subsequent requests.
- ///
- /// If the client does not supply a ``device_id``, the server must
- /// auto-generate one.
+ // Construction/destruction
+
+ explicit GetLoginFlowsJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetLoginFlowsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetLoginFlowsJob() override;
+
+ // Result properties
+
+ /// The homeserver's supported login types
+ const QVector<LoginFlow>& flows() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Authenticates the user.
+/*!
+ * Authenticates the user, and issues an access token they can
+ * use to authorize themself in subsequent requests.
+ *
+ * If the client does not supply a ``device_id``, the server must
+ * auto-generate one.
+ *
+ * The returned access token must be associated with the ``device_id``
+ * supplied by the client or generated by the server. The server may
+ * invalidate any access token previously associated with that device. See
+ * `Relationship between access tokens and devices`_.
+ */
+class LoginJob : public BaseJob
+{
+public:
+ /*! Authenticates the user.
+ * \param type
+ * The login type being used.
+ * \param identifier
+ * Identification information for the user.
+ * \param password
+ * Required when ``type`` is ``m.login.password``. The user's
+ * password.
+ * \param token
+ * Required when ``type`` is ``m.login.token``. Part of `Token-based`_
+ * login. \param deviceId ID of the client device. If this does not
+ * correspond to a known client device, a new device will be created. The
+ * server will auto-generate a device_id if this is not specified. \param
+ * initialDeviceDisplayName A display name to assign to the newly-created
+ * device. Ignored if ``device_id`` corresponds to a known device. \param
+ * user The fully qualified user ID or just local part of the user ID, to
+ * log in. Deprecated in favour of ``identifier``. \param medium When
+ * logging in using a third party identifier, the medium of the identifier.
+ * Must be 'email'. Deprecated in favour of ``identifier``. \param address
+ * Third party identifier for the user. Deprecated in favour of
+ * ``identifier``.
+ */
+ explicit LoginJob(const QString& type,
+ const Omittable<UserIdentifier>& identifier = none,
+ const QString& password = {}, const QString& token = {},
+ const QString& deviceId = {},
+ const QString& initialDeviceDisplayName = {},
+ const QString& user = {}, const QString& medium = {},
+ const QString& address = {});
+
+ ~LoginJob() override;
+
+ // Result properties
+
+ /// The fully-qualified Matrix ID that has been registered.
+ const QString& userId() const;
+ /// An access token for the account.
+ /// This access token can then be used to authorize other requests.
+ const QString& accessToken() const;
+ /// The server_name of the homeserver on which the account has
+ /// been registered.
///
- /// The returned access token must be associated with the ``device_id``
- /// supplied by the client or generated by the server. The server may
- /// invalidate any access token previously associated with that device. See
- /// `Relationship between access tokens and devices`_.
- class LoginJob : public BaseJob
- {
- public:
- /*! Authenticates the user.
- * \param type
- * The login type being used.
- * \param identifier
- * Identification information for the user.
- * \param password
- * Required when ``type`` is ``m.login.password``. The user's
- * password.
- * \param token
- * Required when ``type`` is ``m.login.token``. Part of `Token-based`_
- * login. \param deviceId ID of the client device. If this does not
- * correspond to a known client device, a new device will be created.
- * The server will auto-generate a device_id if this is not specified.
- * \param initialDeviceDisplayName
- * A display name to assign to the newly-created device. Ignored
- * if ``device_id`` corresponds to a known device.
- * \param user
- * The fully qualified user ID or just local part of the user ID, to
- * log in. Deprecated in favour of ``identifier``. \param medium When
- * logging in using a third party identifier, the medium of the
- * identifier. Must be 'email'. Deprecated in favour of ``identifier``.
- * \param address
- * Third party identifier for the user. Deprecated in favour of
- * ``identifier``.
- */
- explicit LoginJob(const QString& type,
- const Omittable<UserIdentifier>& identifier = none,
- const QString& password = {},
- const QString& token = {},
- const QString& deviceId = {},
- const QString& initialDeviceDisplayName = {},
- const QString& user = {}, const QString& medium = {},
- const QString& address = {});
- ~LoginJob() override;
-
- // Result properties
-
- /// The fully-qualified Matrix ID that has been registered.
- const QString& userId() const;
- /// An access token for the account.
- /// This access token can then be used to authorize other requests.
- const QString& accessToken() const;
- /// The server_name of the homeserver on which the account has
- /// been registered.
- ///
- /// **Deprecated**. Clients should extract the server_name from
- /// ``user_id`` (by splitting at the first colon) if they require
- /// it. Note also that ``homeserver`` is not spelt this way.
- const QString& homeServer() const;
- /// ID of the logged-in device. Will be the same as the
- /// corresponding parameter in the request, if one was specified.
- const QString& deviceId() const;
- /// Optional client configuration provided by the server. If present,
- /// clients SHOULD use the provided object to reconfigure themselves,
- /// optionally validating the URLs within. This object takes the same
- /// form as the one returned from .well-known autodiscovery.
- const Omittable<DiscoveryInformation>& wellKnown() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ /// **Deprecated**. Clients should extract the server_name from
+ /// ``user_id`` (by splitting at the first colon) if they require
+ /// it. Note also that ``homeserver`` is not spelt this way.
+ const QString& homeServer() const;
+ /// ID of the logged-in device. Will be the same as the
+ /// corresponding parameter in the request, if one was specified.
+ const QString& deviceId() const;
+ /// Optional client configuration provided by the server. If present,
+ /// clients SHOULD use the provided object to reconfigure themselves,
+ /// optionally validating the URLs within. This object takes the same
+ /// form as the one returned from .well-known autodiscovery.
+ const Omittable<DiscoveryInformation>& wellKnown() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/logout.cpp b/lib/csapi/logout.cpp
index f2d2e130..d0bef20e 100644
--- a/lib/csapi/logout.cpp
+++ b/lib/csapi/logout.cpp
@@ -21,18 +21,15 @@ static const auto LogoutJobName = QStringLiteral("LogoutJob");
LogoutJob::LogoutJob()
: BaseJob(HttpVerb::Post, LogoutJobName, basePath % "/logout")
-{
-}
+{}
QUrl LogoutAllJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/logout/all");
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/logout/all");
}
static const auto LogoutAllJobName = QStringLiteral("LogoutAllJob");
LogoutAllJob::LogoutAllJob()
: BaseJob(HttpVerb::Post, LogoutAllJobName, basePath % "/logout/all")
-{
-}
+{}
diff --git a/lib/csapi/logout.h b/lib/csapi/logout.h
index 4bbb8526..c03af180 100644
--- a/lib/csapi/logout.h
+++ b/lib/csapi/logout.h
@@ -6,50 +6,53 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Invalidates a user access token
- ///
- /// Invalidates an existing access token, so that it can no longer be used
- /// for authorization.
- class LogoutJob : public BaseJob
- {
- public:
- explicit LogoutJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * LogoutJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
- };
-
- /// Invalidates all access tokens for a user
- ///
- /// Invalidates all access tokens for a user, so that they can no longer be
- /// used for authorization. This includes the access token that made this
- /// request.
- ///
- /// This endpoint does not require UI authorization because UI authorization
- /// is designed to protect against attacks where the someone gets hold of a
- /// single access token then takes over the account. This endpoint
- /// invalidates all access tokens for the user, including the token used in
- /// the request, and therefore the attacker is unable to take over the
- /// account in this way.
- class LogoutAllJob : public BaseJob
- {
- public:
- explicit LogoutAllJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * LogoutAllJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Invalidates a user access token
+/*!
+ * Invalidates an existing access token, so that it can no longer be used for
+ * authorization.
+ */
+class LogoutJob : public BaseJob
+{
+public:
+ explicit LogoutJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * LogoutJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+};
+
+/// Invalidates all access tokens for a user
+/*!
+ * Invalidates all access tokens for a user, so that they can no longer be used
+ * for authorization. This includes the access token that made this request.
+ *
+ * This endpoint does not require UI authorization because UI authorization is
+ * designed to protect against attacks where the someone gets hold of a single
+ * access token then takes over the account. This endpoint invalidates all
+ * access tokens for the user, including the token used in the request, and
+ * therefore the attacker is unable to take over the account in this way.
+ */
+class LogoutAllJob : public BaseJob
+{
+public:
+ explicit LogoutAllJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * LogoutAllJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/message_pagination.cpp b/lib/csapi/message_pagination.cpp
index 272c1c20..3f09bd85 100644
--- a/lib/csapi/message_pagination.cpp
+++ b/lib/csapi/message_pagination.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetRoomEventsJob::Private
{
- public:
+public:
QString begin;
QString end;
RoomEvents chunk;
@@ -39,8 +39,8 @@ QUrl GetRoomEventsJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& filter)
{
return BaseJob::makeRequestUrl(
- std::move(baseUrl), basePath % "/rooms/" % roomId % "/messages",
- queryToGetRoomEvents(from, to, dir, limit, filter));
+ std::move(baseUrl), basePath % "/rooms/" % roomId % "/messages",
+ queryToGetRoomEvents(from, to, dir, limit, filter));
}
static const auto GetRoomEventsJobName = QStringLiteral("GetRoomEventsJob");
@@ -50,10 +50,9 @@ GetRoomEventsJob::GetRoomEventsJob(const QString& roomId, const QString& from,
Omittable<int> limit, const QString& filter)
: BaseJob(HttpVerb::Get, GetRoomEventsJobName,
basePath % "/rooms/" % roomId % "/messages",
- queryToGetRoomEvents(from, to, dir, limit, filter)),
- d(new Private)
-{
-}
+ queryToGetRoomEvents(from, to, dir, limit, filter))
+ , d(new Private)
+{}
GetRoomEventsJob::~GetRoomEventsJob() = default;
@@ -69,5 +68,6 @@ BaseJob::Status GetRoomEventsJob::parseJson(const QJsonDocument& data)
fromJson(json.value("start"_ls), d->begin);
fromJson(json.value("end"_ls), d->end);
fromJson(json.value("chunk"_ls), d->chunk);
+
return Success;
}
diff --git a/lib/csapi/message_pagination.h b/lib/csapi/message_pagination.h
index 8ce1962e..03b3d42a 100644
--- a/lib/csapi/message_pagination.h
+++ b/lib/csapi/message_pagination.h
@@ -4,71 +4,80 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "events/eventloader.h"
+#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Get a list of events for this room
+/*!
+ * This API returns a list of message and state events for a room. It uses
+ * pagination query parameters to paginate history in the room.
+ */
+class GetRoomEventsJob : public BaseJob
+{
+public:
+ /*! Get a list of events for this room
+ * \param roomId
+ * The room to get events from.
+ * \param from
+ * The token to start returning events from. This token can be obtained
+ * from a ``prev_batch`` token returned for each room by the sync API,
+ * or from a ``start`` or ``end`` token returned by a previous request
+ * to this endpoint.
+ * \param dir
+ * The direction to return events from.
+ * \param to
+ * The token to stop returning events at. This token can be obtained from
+ * a ``prev_batch`` token returned for each room by the sync endpoint,
+ * or from a ``start`` or ``end`` token returned by a previous request to
+ * this endpoint.
+ * \param limit
+ * The maximum number of events to return. Default: 10.
+ * \param filter
+ * A JSON RoomEventFilter to filter returned events with.
+ */
+ explicit GetRoomEventsJob(const QString& roomId, const QString& from,
+ const QString& dir, const QString& to = {},
+ Omittable<int> limit = none,
+ const QString& filter = {});
- /// Get a list of events for this room
- ///
- /// This API returns a list of message and state events for a room. It uses
- /// pagination query parameters to paginate history in the room.
- class GetRoomEventsJob : public BaseJob
- {
- public:
- /*! Get a list of events for this room
- * \param roomId
- * The room to get events from.
- * \param from
- * The token to start returning events from. This token can be
- * obtained from a ``prev_batch`` token returned for each room by the
- * sync API, or from a ``start`` or ``end`` token returned by a previous
- * request to this endpoint. \param dir The direction to return events
- * from. \param to The token to stop returning events at. This token can
- * be obtained from a ``prev_batch`` token returned for each room by the
- * sync endpoint, or from a ``start`` or ``end`` token returned by a
- * previous request to this endpoint. \param limit The maximum number of
- * events to return. Default: 10. \param filter A JSON RoomEventFilter
- * to filter returned events with.
- */
- explicit GetRoomEventsJob(const QString& roomId, const QString& from,
- const QString& dir, const QString& to = {},
- Omittable<int> limit = none,
- const QString& filter = {});
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomEventsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+ const QString& from, const QString& dir,
+ const QString& to = {},
+ Omittable<int> limit = none,
+ const QString& filter = {});
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomEventsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& from, const QString& dir,
- const QString& to = {},
- Omittable<int> limit = none,
- const QString& filter = {});
+ ~GetRoomEventsJob() override;
- ~GetRoomEventsJob() override;
+ // Result properties
- // Result properties
+ /// The token the pagination starts from. If ``dir=b`` this will be
+ /// the token supplied in ``from``.
+ const QString& begin() const;
+ /// The token the pagination ends at. If ``dir=b`` this token should
+ /// be used again to request even earlier events.
+ const QString& end() const;
+ /// A list of room events.
+ RoomEvents&& chunk();
- /// The token the pagination starts from. If ``dir=b`` this will be
- /// the token supplied in ``from``.
- const QString& begin() const;
- /// The token the pagination ends at. If ``dir=b`` this token should
- /// be used again to request even earlier events.
- const QString& end() const;
- /// A list of room events.
- RoomEvents&& chunk();
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- protected:
- Status parseJson(const QJsonDocument& data) override;
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/notifications.cpp b/lib/csapi/notifications.cpp
index b7f252ac..3a05a0b2 100644
--- a/lib/csapi/notifications.cpp
+++ b/lib/csapi/notifications.cpp
@@ -12,33 +12,36 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<GetNotificationsJob::Notification> {
- static void fillFrom(const QJsonObject& jo,
- GetNotificationsJob::Notification& result)
- {
- fromJson(jo.value("actions"_ls), result.actions);
- fromJson(jo.value("event"_ls), result.event);
- fromJson(jo.value("profile_tag"_ls), result.profileTag);
- fromJson(jo.value("read"_ls), result.read);
- fromJson(jo.value("room_id"_ls), result.roomId);
- fromJson(jo.value("ts"_ls), result.ts);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetNotificationsJob::Notification>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetNotificationsJob::Notification& result)
+ {
+ fromJson(jo.value("actions"_ls), result.actions);
+ fromJson(jo.value("event"_ls), result.event);
+ fromJson(jo.value("profile_tag"_ls), result.profileTag);
+ fromJson(jo.value("read"_ls), result.read);
+ fromJson(jo.value("room_id"_ls), result.roomId);
+ fromJson(jo.value("ts"_ls), result.ts);
+ }
+};
+
} // namespace QMatrixClient
class GetNotificationsJob::Private
{
- public:
+public:
QString nextToken;
std::vector<Notification> notifications;
};
BaseJob::Query queryToGetNotifications(const QString& from,
- Omittable<int> limit,
- const QString& only)
+ Omittable<int> limit, const QString& only)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("from"), from);
@@ -57,17 +60,16 @@ QUrl GetNotificationsJob::makeRequestUrl(QUrl baseUrl, const QString& from,
}
static const auto GetNotificationsJobName =
- QStringLiteral("GetNotificationsJob");
+ QStringLiteral("GetNotificationsJob");
GetNotificationsJob::GetNotificationsJob(const QString& from,
Omittable<int> limit,
const QString& only)
: BaseJob(HttpVerb::Get, GetNotificationsJobName,
basePath % "/notifications",
- queryToGetNotifications(from, limit, only)),
- d(new Private)
-{
-}
+ queryToGetNotifications(from, limit, only))
+ , d(new Private)
+{}
GetNotificationsJob::~GetNotificationsJob() = default;
@@ -84,8 +86,9 @@ BaseJob::Status GetNotificationsJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("next_token"_ls), d->nextToken);
if (!json.contains("notifications"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'notifications' not found in the response" };
fromJson(json.value("notifications"_ls), d->notifications);
+
return Success;
}
diff --git a/lib/csapi/notifications.h b/lib/csapi/notifications.h
index 49bc33e9..4170d539 100644
--- a/lib/csapi/notifications.h
+++ b/lib/csapi/notifications.h
@@ -4,88 +4,94 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "events/eventloader.h"
+#include "jobs/basejob.h"
+
#include <QtCore/QJsonObject>
#include <QtCore/QVariant>
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
- /// Gets a list of events that the user has been notified about
- ///
- /// This API is used to paginate through the list of events that the
- /// user has been, or would have been notified about.
- class GetNotificationsJob : public BaseJob
+// Operations
+
+/// Gets a list of events that the user has been notified about
+/*!
+ * This API is used to paginate through the list of events that the
+ * user has been, or would have been notified about.
+ */
+class GetNotificationsJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// This API is used to paginate through the list of events that theuser has
+ /// been, or would have been notified about.
+ struct Notification
{
- public:
- // Inner data structures
-
- /// This API is used to paginate through the list of events that the
- /// user has been, or would have been notified about.
- struct Notification {
- /// The action(s) to perform when the conditions for this rule are
- /// met. See `Push Rules: API`_.
- QVector<QVariant> actions;
- /// The Event object for the event that triggered the notification.
- EventPtr event;
- /// The profile tag of the rule that matched this event.
- QString profileTag;
- /// Indicates whether the user has sent a read receipt indicating
- /// that they have read this message.
- bool read;
- /// The ID of the room in which the event was posted.
- QString roomId;
- /// The unix timestamp at which the event notification was sent,
- /// in milliseconds.
- int ts;
- };
-
- // Construction/destruction
-
- /*! Gets a list of events that the user has been notified about
- * \param from
- * Pagination token given to retrieve the next set of events.
- * \param limit
- * Limit on the number of events to return in this request.
- * \param only
- * Allows basic filtering of events returned. Supply ``highlight``
- * to return only events where the notification had the highlight
- * tweak set.
- */
- explicit GetNotificationsJob(const QString& from = {},
- Omittable<int> limit = none,
- const QString& only = {});
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetNotificationsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& from = {},
- Omittable<int> limit = none,
- const QString& only = {});
-
- ~GetNotificationsJob() override;
-
- // Result properties
-
- /// 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.
- const QString& nextToken() const;
- /// The list of events that triggered notifications.
- std::vector<Notification>&& notifications();
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// The action(s) to perform when the conditions for this rule are
+ /// met.See `Push Rules: API`_.
+ QVector<QVariant> actions;
+ /// The Event object for the event that triggered the notification.
+ EventPtr event;
+ /// The profile tag of the rule that matched this event.
+ QString profileTag;
+ /// Indicates whether the user has sent a read receipt indicatingthat
+ /// they have read this message.
+ bool read;
+ /// The ID of the room in which the event was posted.
+ QString roomId;
+ /// The unix timestamp at which the event notification was sent,in
+ /// milliseconds.
+ int ts;
};
+
+ // Construction/destruction
+
+ /*! Gets a list of events that the user has been notified about
+ * \param from
+ * Pagination token given to retrieve the next set of events.
+ * \param limit
+ * Limit on the number of events to return in this request.
+ * \param only
+ * Allows basic filtering of events returned. Supply ``highlight``
+ * to return only events where the notification had the highlight
+ * tweak set.
+ */
+ explicit GetNotificationsJob(const QString& from = {},
+ Omittable<int> limit = none,
+ const QString& only = {});
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetNotificationsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& from = {},
+ Omittable<int> limit = none,
+ const QString& only = {});
+
+ ~GetNotificationsJob() override;
+
+ // Result properties
+
+ /// 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.
+ const QString& nextToken() const;
+ /// The list of events that triggered notifications.
+ std::vector<Notification>&& notifications();
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/openid.cpp b/lib/csapi/openid.cpp
index 82a3b055..39ba3b9e 100644
--- a/lib/csapi/openid.cpp
+++ b/lib/csapi/openid.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class RequestOpenIdTokenJob::Private
{
- public:
+public:
QString accessToken;
QString tokenType;
QString matrixServerName;
@@ -22,13 +22,13 @@ class RequestOpenIdTokenJob::Private
};
static const auto RequestOpenIdTokenJobName =
- QStringLiteral("RequestOpenIdTokenJob");
+ QStringLiteral("RequestOpenIdTokenJob");
RequestOpenIdTokenJob::RequestOpenIdTokenJob(const QString& userId,
const QJsonObject& body)
: BaseJob(HttpVerb::Post, RequestOpenIdTokenJobName,
- basePath % "/user/" % userId % "/openid/request_token"),
- d(new Private)
+ basePath % "/user/" % userId % "/openid/request_token")
+ , d(new Private)
{
setRequestData(Data(toJson(body)));
}
@@ -53,20 +53,21 @@ BaseJob::Status RequestOpenIdTokenJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("access_token"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'access_token' not found in the response" };
fromJson(json.value("access_token"_ls), d->accessToken);
if (!json.contains("token_type"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'token_type' not found in the response" };
fromJson(json.value("token_type"_ls), d->tokenType);
if (!json.contains("matrix_server_name"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'matrix_server_name' not found in the response" };
fromJson(json.value("matrix_server_name"_ls), d->matrixServerName);
if (!json.contains("expires_in"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'expires_in' not found in the response" };
fromJson(json.value("expires_in"_ls), d->expiresIn);
+
return Success;
}
diff --git a/lib/csapi/openid.h b/lib/csapi/openid.h
index 6e3c744d..40f1bc40 100644
--- a/lib/csapi/openid.h
+++ b/lib/csapi/openid.h
@@ -4,58 +4,64 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
-
- /// Get an OpenID token object to verify the requester's identity.
- ///
- /// Gets an OpenID token object that the requester may supply to another
- /// service to verify their identity in Matrix. The generated token is only
- /// valid for exchanging for user information from the federation API for
- /// OpenID.
- ///
- /// The access token generated is only valid for the OpenID API. It cannot
- /// be used to request another OpenID access token or call ``/sync``, for
- /// example.
- class RequestOpenIdTokenJob : public BaseJob
- {
- public:
- /*! Get an OpenID token object to verify the requester's identity.
- * \param userId
- * The user to request and OpenID token for. Should be the user who
- * is authenticated for the request.
- * \param body
- * An empty object. Reserved for future expansion.
- */
- explicit RequestOpenIdTokenJob(const QString& userId,
- const QJsonObject& body = {});
- ~RequestOpenIdTokenJob() override;
-
- // Result properties
-
- /// An access token the consumer may use to verify the identity of
- /// the person who generated the token. This is given to the federation
- /// API ``GET /openid/userinfo``.
- const QString& accessToken() const;
- /// The string ``Bearer``.
- const QString& tokenType() const;
- /// The homeserver domain the consumer should use when attempting to
- /// verify the user's identity.
- const QString& matrixServerName() const;
- /// The number of seconds before this token expires and a new one must
- /// be generated.
- int expiresIn() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Get an OpenID token object to verify the requester's identity.
+/*!
+ * Gets an OpenID token object that the requester may supply to another
+ * service to verify their identity in Matrix. The generated token is only
+ * valid for exchanging for user information from the federation API for
+ * OpenID.
+ *
+ * The access token generated is only valid for the OpenID API. It cannot
+ * be used to request another OpenID access token or call ``/sync``, for
+ * example.
+ */
+class RequestOpenIdTokenJob : public BaseJob
+{
+public:
+ /*! Get an OpenID token object to verify the requester's identity.
+ * \param userId
+ * The user to request and OpenID token for. Should be the user who
+ * is authenticated for the request.
+ * \param body
+ * An empty object. Reserved for future expansion.
+ */
+ explicit RequestOpenIdTokenJob(const QString& userId,
+ const QJsonObject& body = {});
+
+ ~RequestOpenIdTokenJob() override;
+
+ // Result properties
+
+ /// An access token the consumer may use to verify the identity of
+ /// the person who generated the token. This is given to the federation
+ /// API ``GET /openid/userinfo``.
+ const QString& accessToken() const;
+ /// The string ``Bearer``.
+ const QString& tokenType() const;
+ /// The homeserver domain the consumer should use when attempting to
+ /// verify the user's identity.
+ const QString& matrixServerName() const;
+ /// The number of seconds before this token expires and a new one must
+ /// be generated.
+ int expiresIn() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/peeking_events.cpp b/lib/csapi/peeking_events.cpp
index d48eca3f..6962d363 100644
--- a/lib/csapi/peeking_events.cpp
+++ b/lib/csapi/peeking_events.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class PeekEventsJob::Private
{
- public:
+public:
QString begin;
QString end;
RoomEvents chunk;
@@ -31,8 +31,7 @@ BaseJob::Query queryToPeekEvents(const QString& from, Omittable<int> timeout,
}
QUrl PeekEventsJob::makeRequestUrl(QUrl baseUrl, const QString& from,
- Omittable<int> timeout,
- const QString& roomId)
+ Omittable<int> timeout, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/events",
queryToPeekEvents(from, timeout, roomId));
@@ -43,10 +42,9 @@ static const auto PeekEventsJobName = QStringLiteral("PeekEventsJob");
PeekEventsJob::PeekEventsJob(const QString& from, Omittable<int> timeout,
const QString& roomId)
: BaseJob(HttpVerb::Get, PeekEventsJobName, basePath % "/events",
- queryToPeekEvents(from, timeout, roomId)),
- d(new Private)
-{
-}
+ queryToPeekEvents(from, timeout, roomId))
+ , d(new Private)
+{}
PeekEventsJob::~PeekEventsJob() = default;
@@ -62,5 +60,6 @@ BaseJob::Status PeekEventsJob::parseJson(const QJsonDocument& data)
fromJson(json.value("start"_ls), d->begin);
fromJson(json.value("end"_ls), d->end);
fromJson(json.value("chunk"_ls), d->chunk);
+
return Success;
}
diff --git a/lib/csapi/peeking_events.h b/lib/csapi/peeking_events.h
index 00552af0..1fe63c4d 100644
--- a/lib/csapi/peeking_events.h
+++ b/lib/csapi/peeking_events.h
@@ -4,70 +4,74 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "events/eventloader.h"
+#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Listen on the event stream.
+/*!
+ * This will listen for new events related to a particular room and return
+ * them to the caller. This will block until an event is received, or until
+ * the ``timeout`` is reached.
+ *
+ * This API is the same as the normal ``/events`` endpoint, but can be
+ * called by users who have not joined the room.
+ *
+ * Note that the normal ``/events`` endpoint has been deprecated. This
+ * API will also be deprecated at some point, but its replacement is not
+ * yet known.
+ */
+class PeekEventsJob : public BaseJob
+{
+public:
+ /*! Listen on the event stream.
+ * \param from
+ * The token to stream from. This token is either from a previous
+ * request to this API or from the initial sync API.
+ * \param timeout
+ * The maximum time in milliseconds to wait for an event.
+ * \param roomId
+ * The room ID for which events should be returned.
+ */
+ explicit PeekEventsJob(const QString& from = {},
+ Omittable<int> timeout = none,
+ const QString& roomId = {});
- /// Listen on the event stream.
- ///
- /// This will listen for new events related to a particular room and return
- /// them to the caller. This will block until an event is received, or until
- /// the ``timeout`` is reached.
- ///
- /// This API is the same as the normal ``/events`` endpoint, but can be
- /// called by users who have not joined the room.
- ///
- /// Note that the normal ``/events`` endpoint has been deprecated. This
- /// API will also be deprecated at some point, but its replacement is not
- /// yet known.
- class PeekEventsJob : public BaseJob
- {
- public:
- /*! Listen on the event stream.
- * \param from
- * The token to stream from. This token is either from a previous
- * request to this API or from the initial sync API.
- * \param timeout
- * The maximum time in milliseconds to wait for an event.
- * \param roomId
- * The room ID for which events should be returned.
- */
- explicit PeekEventsJob(const QString& from = {},
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * PeekEventsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& from = {},
Omittable<int> timeout = none,
const QString& roomId = {});
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * PeekEventsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& from = {},
- Omittable<int> timeout = none,
- const QString& roomId = {});
+ ~PeekEventsJob() override;
- ~PeekEventsJob() override;
+ // Result properties
- // Result properties
+ /// A token which correlates to the first value in ``chunk``. This
+ /// is usually the same token supplied to ``from=``.
+ const QString& begin() const;
+ /// A token which correlates to the last value in ``chunk``. This
+ /// token should be used in the next request to ``/events``.
+ const QString& end() const;
+ /// An array of events.
+ RoomEvents&& chunk();
- /// A token which correlates to the first value in ``chunk``. This
- /// is usually the same token supplied to ``from=``.
- const QString& begin() const;
- /// A token which correlates to the last value in ``chunk``. This
- /// token should be used in the next request to ``/events``.
- const QString& end() const;
- /// An array of events.
- RoomEvents&& chunk();
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- protected:
- Status parseJson(const QJsonDocument& data) override;
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/presence.cpp b/lib/csapi/presence.cpp
index 4f9b9c78..b6e8caf2 100644
--- a/lib/csapi/presence.cpp
+++ b/lib/csapi/presence.cpp
@@ -27,7 +27,7 @@ SetPresenceJob::SetPresenceJob(const QString& userId, const QString& presence,
class GetPresenceJob::Private
{
- public:
+public:
QString presence;
Omittable<int> lastActiveAgo;
QString statusMsg;
@@ -36,18 +36,17 @@ class GetPresenceJob::Private
QUrl GetPresenceJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
- return BaseJob::makeRequestUrl(
- std::move(baseUrl), basePath % "/presence/" % userId % "/status");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ basePath % "/presence/" % userId % "/status");
}
static const auto GetPresenceJobName = QStringLiteral("GetPresenceJob");
GetPresenceJob::GetPresenceJob(const QString& userId)
: BaseJob(HttpVerb::Get, GetPresenceJobName,
- basePath % "/presence/" % userId % "/status"),
- d(new Private)
-{
-}
+ basePath % "/presence/" % userId % "/status")
+ , d(new Private)
+{}
GetPresenceJob::~GetPresenceJob() = default;
@@ -69,11 +68,12 @@ BaseJob::Status GetPresenceJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("presence"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'presence' not found in the response" };
fromJson(json.value("presence"_ls), d->presence);
fromJson(json.value("last_active_ago"_ls), d->lastActiveAgo);
fromJson(json.value("status_msg"_ls), d->statusMsg);
fromJson(json.value("currently_active"_ls), d->currentlyActive);
+
return Success;
}
diff --git a/lib/csapi/presence.h b/lib/csapi/presence.h
index 881d9d5e..82c3a300 100644
--- a/lib/csapi/presence.h
+++ b/lib/csapi/presence.h
@@ -4,73 +4,78 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
+namespace QMatrixClient
+{
-namespace QMatrixClient {
- // Operations
+// Operations
- /// Update this user's presence state.
- ///
- /// This API sets the given user's presence state. When setting the status,
- /// the activity time is updated to reflect that activity; the client does
- /// not need to specify the ``last_active_ago`` field. You cannot set the
- /// presence state of another user.
- class SetPresenceJob : public BaseJob
- {
- public:
- /*! Update this user's presence state.
- * \param userId
- * The user whose presence state to update.
- * \param presence
- * The new presence state.
- * \param statusMsg
- * The status message to attach to this state.
- */
- explicit SetPresenceJob(const QString& userId, const QString& presence,
- const QString& statusMsg = {});
- };
+/// Update this user's presence state.
+/*!
+ * This API sets the given user's presence state. When setting the status,
+ * the activity time is updated to reflect that activity; the client does
+ * not need to specify the ``last_active_ago`` field. You cannot set the
+ * presence state of another user.
+ */
+class SetPresenceJob : public BaseJob
+{
+public:
+ /*! Update this user's presence state.
+ * \param userId
+ * The user whose presence state to update.
+ * \param presence
+ * The new presence state.
+ * \param statusMsg
+ * The status message to attach to this state.
+ */
+ explicit SetPresenceJob(const QString& userId, const QString& presence,
+ const QString& statusMsg = {});
+};
+
+/// Get this user's presence state.
+/*!
+ * Get the given user's presence state.
+ */
+class GetPresenceJob : public BaseJob
+{
+public:
+ /*! Get this user's presence state.
+ * \param userId
+ * The user whose presence state to get.
+ */
+ explicit GetPresenceJob(const QString& userId);
- /// Get this user's presence state.
- ///
- /// Get the given user's presence state.
- class GetPresenceJob : public BaseJob
- {
- public:
- /*! Get this user's presence state.
- * \param userId
- * The user whose presence state to get.
- */
- explicit GetPresenceJob(const QString& userId);
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetPresenceJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetPresenceJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
+ ~GetPresenceJob() override;
- ~GetPresenceJob() override;
+ // Result properties
- // Result properties
+ /// This user's presence.
+ const QString& presence() const;
+ /// The length of time in milliseconds since an action was performed
+ /// by this user.
+ Omittable<int> lastActiveAgo() const;
+ /// The state message for this user if one was set.
+ const QString& statusMsg() const;
+ /// Whether the user is currently active
+ Omittable<bool> currentlyActive() const;
- /// This user's presence.
- const QString& presence() const;
- /// The length of time in milliseconds since an action was performed
- /// by this user.
- Omittable<int> lastActiveAgo() const;
- /// The state message for this user if one was set.
- const QString& statusMsg() const;
- /// Whether the user is currently active
- Omittable<bool> currentlyActive() const;
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- protected:
- Status parseJson(const QJsonDocument& data) override;
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/profile.cpp b/lib/csapi/profile.cpp
index fefc18f2..630452f6 100644
--- a/lib/csapi/profile.cpp
+++ b/lib/csapi/profile.cpp
@@ -26,25 +26,23 @@ SetDisplayNameJob::SetDisplayNameJob(const QString& userId,
class GetDisplayNameJob::Private
{
- public:
+public:
QString displayname;
};
QUrl GetDisplayNameJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/profile/" % userId
- % "/displayname");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), basePath % "/profile/" % userId % "/displayname");
}
static const auto GetDisplayNameJobName = QStringLiteral("GetDisplayNameJob");
GetDisplayNameJob::GetDisplayNameJob(const QString& userId)
: BaseJob(HttpVerb::Get, GetDisplayNameJobName,
- basePath % "/profile/" % userId % "/displayname", false),
- d(new Private)
-{
-}
+ basePath % "/profile/" % userId % "/displayname", false)
+ , d(new Private)
+{}
GetDisplayNameJob::~GetDisplayNameJob() = default;
@@ -54,13 +52,13 @@ BaseJob::Status GetDisplayNameJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("displayname"_ls), d->displayname);
+
return Success;
}
static const auto SetAvatarUrlJobName = QStringLiteral("SetAvatarUrlJob");
-SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId,
- const QString& avatarUrl)
+SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId, const QString& avatarUrl)
: BaseJob(HttpVerb::Put, SetAvatarUrlJobName,
basePath % "/profile/" % userId % "/avatar_url")
{
@@ -71,25 +69,23 @@ SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId,
class GetAvatarUrlJob::Private
{
- public:
+public:
QString avatarUrl;
};
QUrl GetAvatarUrlJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/profile/" % userId
- % "/avatar_url");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), basePath % "/profile/" % userId % "/avatar_url");
}
static const auto GetAvatarUrlJobName = QStringLiteral("GetAvatarUrlJob");
GetAvatarUrlJob::GetAvatarUrlJob(const QString& userId)
: BaseJob(HttpVerb::Get, GetAvatarUrlJobName,
- basePath % "/profile/" % userId % "/avatar_url", false),
- d(new Private)
-{
-}
+ basePath % "/profile/" % userId % "/avatar_url", false)
+ , d(new Private)
+{}
GetAvatarUrlJob::~GetAvatarUrlJob() = default;
@@ -99,12 +95,13 @@ BaseJob::Status GetAvatarUrlJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("avatar_url"_ls), d->avatarUrl);
+
return Success;
}
class GetUserProfileJob::Private
{
- public:
+public:
QString avatarUrl;
QString displayname;
};
@@ -119,10 +116,9 @@ static const auto GetUserProfileJobName = QStringLiteral("GetUserProfileJob");
GetUserProfileJob::GetUserProfileJob(const QString& userId)
: BaseJob(HttpVerb::Get, GetUserProfileJobName,
- basePath % "/profile/" % userId, false),
- d(new Private)
-{
-}
+ basePath % "/profile/" % userId, false)
+ , d(new Private)
+{}
GetUserProfileJob::~GetUserProfileJob() = default;
@@ -135,5 +131,6 @@ BaseJob::Status GetUserProfileJob::parseJson(const QJsonDocument& data)
auto json = data.object();
fromJson(json.value("avatar_url"_ls), d->avatarUrl);
fromJson(json.value("displayname"_ls), d->displayname);
+
return Success;
}
diff --git a/lib/csapi/profile.h b/lib/csapi/profile.h
index 9a6ab56b..95d3ec97 100644
--- a/lib/csapi/profile.h
+++ b/lib/csapi/profile.h
@@ -6,156 +6,162 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Set the user's display name.
- ///
- /// This API sets the given user's display name. You must have permission to
- /// set this user's display name, e.g. you need to have their
- /// ``access_token``.
- class SetDisplayNameJob : public BaseJob
- {
- public:
- /*! Set the user's display name.
- * \param userId
- * The user whose display name to set.
- * \param displayname
- * The new display name for this user.
- */
- explicit SetDisplayNameJob(const QString& userId,
- const QString& displayname = {});
- };
-
- /// Get the user's display name.
- ///
- /// Get the user's display name. This API may be used to fetch the user's
- /// own displayname or to query the name of other users; either locally or
- /// on remote homeservers.
- class GetDisplayNameJob : public BaseJob
- {
- public:
- /*! Get the user's display name.
- * \param userId
- * The user whose display name to get.
- */
- explicit GetDisplayNameJob(const QString& userId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetDisplayNameJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
-
- ~GetDisplayNameJob() override;
-
- // Result properties
-
- /// The user's display name if they have set one, otherwise not present.
- const QString& displayname() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Set the user's avatar URL.
- ///
- /// This API sets the given user's avatar URL. You must have permission to
- /// set this user's avatar URL, e.g. you need to have their
- /// ``access_token``.
- class SetAvatarUrlJob : public BaseJob
- {
- public:
- /*! Set the user's avatar URL.
- * \param userId
- * The user whose avatar URL to set.
- * \param avatarUrl
- * The new avatar URL for this user.
- */
- explicit SetAvatarUrlJob(const QString& userId,
- const QString& avatarUrl = {});
- };
-
- /// Get the user's avatar URL.
- ///
- /// Get the user's avatar URL. This API may be used to fetch the user's
- /// own avatar URL or to query the URL of other users; either locally or
- /// on remote homeservers.
- class GetAvatarUrlJob : public BaseJob
- {
- public:
- /*! Get the user's avatar URL.
- * \param userId
- * The user whose avatar URL to get.
- */
- explicit GetAvatarUrlJob(const QString& userId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetAvatarUrlJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
-
- ~GetAvatarUrlJob() override;
-
- // Result properties
-
- /// The user's avatar URL if they have set one, otherwise not present.
- const QString& avatarUrl() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Get this user's profile information.
- ///
- /// Get the combined profile information for this user. This API may be used
- /// to fetch the user's own profile information or other users; either
- /// locally or on remote homeservers. This API may return keys which are not
- /// limited to ``displayname`` or ``avatar_url``.
- class GetUserProfileJob : public BaseJob
- {
- public:
- /*! Get this user's profile information.
- * \param userId
- * The user whose profile information to get.
- */
- explicit GetUserProfileJob(const QString& userId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetUserProfileJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
-
- ~GetUserProfileJob() override;
-
- // Result properties
-
- /// The user's avatar URL if they have set one, otherwise not present.
- const QString& avatarUrl() const;
- /// The user's display name if they have set one, otherwise not present.
- const QString& displayname() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Set the user's display name.
+/*!
+ * This API sets the given user's display name. You must have permission to
+ * set this user's display name, e.g. you need to have their ``access_token``.
+ */
+class SetDisplayNameJob : public BaseJob
+{
+public:
+ /*! Set the user's display name.
+ * \param userId
+ * The user whose display name to set.
+ * \param displayname
+ * The new display name for this user.
+ */
+ explicit SetDisplayNameJob(const QString& userId,
+ const QString& displayname = {});
+};
+
+/// Get the user's display name.
+/*!
+ * Get the user's display name. This API may be used to fetch the user's
+ * own displayname or to query the name of other users; either locally or
+ * on remote homeservers.
+ */
+class GetDisplayNameJob : public BaseJob
+{
+public:
+ /*! Get the user's display name.
+ * \param userId
+ * The user whose display name to get.
+ */
+ explicit GetDisplayNameJob(const QString& userId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetDisplayNameJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
+
+ ~GetDisplayNameJob() override;
+
+ // Result properties
+
+ /// The user's display name if they have set one, otherwise not present.
+ const QString& displayname() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Set the user's avatar URL.
+/*!
+ * This API sets the given user's avatar URL. You must have permission to
+ * set this user's avatar URL, e.g. you need to have their ``access_token``.
+ */
+class SetAvatarUrlJob : public BaseJob
+{
+public:
+ /*! Set the user's avatar URL.
+ * \param userId
+ * The user whose avatar URL to set.
+ * \param avatarUrl
+ * The new avatar URL for this user.
+ */
+ explicit SetAvatarUrlJob(const QString& userId,
+ const QString& avatarUrl = {});
+};
+
+/// Get the user's avatar URL.
+/*!
+ * Get the user's avatar URL. This API may be used to fetch the user's
+ * own avatar URL or to query the URL of other users; either locally or
+ * on remote homeservers.
+ */
+class GetAvatarUrlJob : public BaseJob
+{
+public:
+ /*! Get the user's avatar URL.
+ * \param userId
+ * The user whose avatar URL to get.
+ */
+ explicit GetAvatarUrlJob(const QString& userId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetAvatarUrlJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
+
+ ~GetAvatarUrlJob() override;
+
+ // Result properties
+
+ /// The user's avatar URL if they have set one, otherwise not present.
+ const QString& avatarUrl() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Get this user's profile information.
+/*!
+ * Get the combined profile information for this user. This API may be used
+ * to fetch the user's own profile information or other users; either
+ * locally or on remote homeservers. This API may return keys which are not
+ * limited to ``displayname`` or ``avatar_url``.
+ */
+class GetUserProfileJob : public BaseJob
+{
+public:
+ /*! Get this user's profile information.
+ * \param userId
+ * The user whose profile information to get.
+ */
+ explicit GetUserProfileJob(const QString& userId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetUserProfileJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
+
+ ~GetUserProfileJob() override;
+
+ // Result properties
+
+ /// The user's avatar URL if they have set one, otherwise not present.
+ const QString& avatarUrl() const;
+ /// The user's display name if they have set one, otherwise not present.
+ const QString& displayname() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/pusher.cpp b/lib/csapi/pusher.cpp
index 86b36c6d..41a0cffe 100644
--- a/lib/csapi/pusher.cpp
+++ b/lib/csapi/pusher.cpp
@@ -12,38 +12,42 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<GetPushersJob::PusherData> {
- static void fillFrom(const QJsonObject& jo,
- GetPushersJob::PusherData& result)
- {
- fromJson(jo.value("url"_ls), result.url);
- fromJson(jo.value("format"_ls), result.format);
- }
- };
-
- template <> struct JsonObjectConverter<GetPushersJob::Pusher> {
- static void fillFrom(const QJsonObject& jo,
- GetPushersJob::Pusher& result)
- {
- fromJson(jo.value("pushkey"_ls), result.pushkey);
- fromJson(jo.value("kind"_ls), result.kind);
- fromJson(jo.value("app_id"_ls), result.appId);
- fromJson(jo.value("app_display_name"_ls), result.appDisplayName);
- fromJson(jo.value("device_display_name"_ls),
- result.deviceDisplayName);
- fromJson(jo.value("profile_tag"_ls), result.profileTag);
- fromJson(jo.value("lang"_ls), result.lang);
- fromJson(jo.value("data"_ls), result.data);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetPushersJob::PusherData>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetPushersJob::PusherData& result)
+ {
+ fromJson(jo.value("url"_ls), result.url);
+ fromJson(jo.value("format"_ls), result.format);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetPushersJob::Pusher>
+{
+ static void fillFrom(const QJsonObject& jo, GetPushersJob::Pusher& result)
+ {
+ fromJson(jo.value("pushkey"_ls), result.pushkey);
+ fromJson(jo.value("kind"_ls), result.kind);
+ fromJson(jo.value("app_id"_ls), result.appId);
+ fromJson(jo.value("app_display_name"_ls), result.appDisplayName);
+ fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName);
+ fromJson(jo.value("profile_tag"_ls), result.profileTag);
+ fromJson(jo.value("lang"_ls), result.lang);
+ fromJson(jo.value("data"_ls), result.data);
+ }
+};
+
} // namespace QMatrixClient
class GetPushersJob::Private
{
- public:
+public:
QVector<Pusher> pushers;
};
@@ -55,10 +59,9 @@ QUrl GetPushersJob::makeRequestUrl(QUrl baseUrl)
static const auto GetPushersJobName = QStringLiteral("GetPushersJob");
GetPushersJob::GetPushersJob()
- : BaseJob(HttpVerb::Get, GetPushersJobName, basePath % "/pushers"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetPushersJobName, basePath % "/pushers")
+ , d(new Private)
+{}
GetPushersJob::~GetPushersJob() = default;
@@ -71,27 +74,30 @@ BaseJob::Status GetPushersJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("pushers"_ls), d->pushers);
+
return Success;
}
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<PostPusherJob::PusherData> {
- static void dumpTo(QJsonObject& jo,
- const PostPusherJob::PusherData& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("url"), pod.url);
- addParam<IfNotEmpty>(jo, QStringLiteral("format"), pod.format);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<PostPusherJob::PusherData>
+{
+ static void dumpTo(QJsonObject& jo, const PostPusherJob::PusherData& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("url"), pod.url);
+ addParam<IfNotEmpty>(jo, QStringLiteral("format"), pod.format);
+ }
+};
+
} // namespace QMatrixClient
static const auto PostPusherJobName = QStringLiteral("PostPusherJob");
PostPusherJob::PostPusherJob(const QString& pushkey, const QString& kind,
- const QString& appId,
- const QString& appDisplayName,
+ const QString& appId, const QString& appDisplayName,
const QString& deviceDisplayName,
const QString& lang, const PusherData& data,
const QString& profileTag, Omittable<bool> append)
diff --git a/lib/csapi/pusher.h b/lib/csapi/pusher.h
index 947d7fc8..a909b9a0 100644
--- a/lib/csapi/pusher.h
+++ b/lib/csapi/pusher.h
@@ -4,168 +4,169 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets the current pushers for the authenticated user
+/*!
+ * Gets all currently active pushers for the authenticated user.
+ */
+class GetPushersJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// A dictionary of information for the pusher implementationitself.
+ struct PusherData
+ {
+ /// Required if ``kind`` is ``http``. The URL to use to
+ /// sendnotifications to.
+ QString url;
+ /// The format to use when sending notifications to the PushGateway.
+ QString format;
+ };
- /// Gets the current pushers for the authenticated user
- ///
/// Gets all currently active pushers for the authenticated user.
- class GetPushersJob : public BaseJob
+ struct Pusher
{
- public:
- // Inner data structures
-
- /// A dictionary of information for the pusher implementation
- /// itself.
- struct PusherData {
- /// Required if ``kind`` is ``http``. The URL to use to send
- /// notifications to.
- QString url;
- /// The format to use when sending notifications to the Push
- /// Gateway.
- QString format;
- };
-
- /// Gets all currently active pushers for the authenticated user.
- struct Pusher {
- /// This is a unique identifier for this pusher. See ``/set`` for
- /// more detail.
- /// Max length, 512 bytes.
- QString pushkey;
- /// The kind of pusher. ``"http"`` is a pusher that
- /// sends HTTP pokes.
- QString kind;
- /// This is a reverse-DNS style identifier for the application.
- /// Max length, 64 chars.
- QString appId;
- /// A string that will allow the user to identify what application
- /// owns this pusher.
- QString appDisplayName;
- /// A string that will allow the user to identify what device owns
- /// this pusher.
- QString deviceDisplayName;
- /// This string determines which set of device specific rules this
- /// pusher executes.
- QString profileTag;
- /// The preferred language for receiving notifications (e.g. 'en'
- /// or 'en-US')
- QString lang;
- /// A dictionary of information for the pusher implementation
- /// itself.
- PusherData data;
- };
-
- // Construction/destruction
-
- explicit GetPushersJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetPushersJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetPushersJob() override;
-
- // Result properties
-
- /// An array containing the current pushers for the user
- const QVector<Pusher>& pushers() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// This is a unique identifier for this pusher. See ``/set`` formore
+ /// detail.Max length, 512 bytes.
+ QString pushkey;
+ /// The kind of pusher. ``"http"`` is a pusher thatsends HTTP pokes.
+ QString kind;
+ /// This is a reverse-DNS style identifier for the application.Max
+ /// length, 64 chars.
+ QString appId;
+ /// A string that will allow the user to identify what applicationowns
+ /// this pusher.
+ QString appDisplayName;
+ /// A string that will allow the user to identify what device ownsthis
+ /// pusher.
+ QString deviceDisplayName;
+ /// This string determines which set of device specific rules thispusher
+ /// executes.
+ QString profileTag;
+ /// The preferred language for receiving notifications (e.g. 'en'or
+ /// 'en-US')
+ QString lang;
+ /// A dictionary of information for the pusher implementationitself.
+ PusherData data;
};
- /// Modify a pusher for this user on the homeserver.
- ///
- /// This endpoint allows the creation, modification and deletion of
- /// `pushers`_ for this user ID. The behaviour of this endpoint varies
- /// depending on the values in the JSON body.
- class PostPusherJob : public BaseJob
+ // Construction/destruction
+
+ explicit GetPushersJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetPushersJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetPushersJob() override;
+
+ // Result properties
+
+ /// An array containing the current pushers for the user
+ const QVector<Pusher>& pushers() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Modify a pusher for this user on the homeserver.
+/*!
+ * This endpoint allows the creation, modification and deletion of `pushers`_
+ * for this user ID. The behaviour of this endpoint varies depending on the
+ * values in the JSON body.
+ */
+class PostPusherJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// A dictionary of information for the pusher implementationitself. If
+ /// ``kind`` is ``http``, this should contain ``url``which is the URL to use
+ /// to send notifications to.
+ struct PusherData
{
- public:
- // Inner data structures
-
- /// A dictionary of information for the pusher implementation
- /// itself. If ``kind`` is ``http``, this should contain ``url``
- /// which is the URL to use to send notifications to.
- struct PusherData {
- /// 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;
- /// 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
- /// `Push Gateway Specification`_. Currently the only format
- /// available is 'event_id_only'.
- QString format;
- };
-
- // Construction/destruction
-
- /*! Modify a pusher for this user on the homeserver.
- * \param pushkey
- * This is a unique identifier for this pusher. The value you
- * should use for this is the routing or destination address
- * information for the notification, for example, the APNS token
- * for APNS or the Registration ID for GCM. If your notification
- * client has no such concept, use any unique identifier.
- * Max length, 512 bytes.
- *
- * If the ``kind`` is ``"email"``, this is the email address to
- * send notifications to.
- * \param kind
- * The kind of pusher to configure. ``"http"`` makes a pusher that
- * sends HTTP pokes. ``"email"`` makes a pusher that emails the
- * user with unread notifications. ``null`` deletes the pusher.
- * \param appId
- * This is a reverse-DNS style identifier for the application.
- * It is recommended that this end with the platform, such that
- * different platform versions get different app identifiers.
- * Max length, 64 chars.
- *
- * If the ``kind`` is ``"email"``, this is ``"m.email"``.
- * \param appDisplayName
- * A string that will allow the user to identify what application
- * owns this pusher.
- * \param deviceDisplayName
- * A string that will allow the user to identify what device owns
- * this pusher.
- * \param lang
- * The preferred language for receiving notifications (e.g. 'en'
- * or 'en-US').
- * \param data
- * A dictionary of information for the pusher implementation
- * itself. If ``kind`` is ``http``, this should contain ``url``
- * which is the URL to use to send notifications to.
- * \param profileTag
- * This string determines which set of device specific rules this
- * pusher executes.
- * \param append
- * If true, the homeserver should add another pusher with the
- * given pushkey and App ID in addition to any others with
- * different user IDs. Otherwise, the homeserver must remove any
- * other pushers with the same App ID and pushkey for different
- * users. The default is ``false``.
- */
- explicit PostPusherJob(const QString& pushkey, const QString& kind,
- const QString& appId,
- const QString& appDisplayName,
- const QString& deviceDisplayName,
- const QString& lang, const PusherData& data,
- const QString& profileTag = {},
- Omittable<bool> append = none);
+ /// Required if ``kind`` is ``http``. The URL to use to sendnotifications
+ /// to. MUST be an HTTPS URL with a path of ``/_matrix/push/v1/notify``.
+ QString url;
+ /// The format to send notifications in to Push Gateways if the``kind``
+ /// is ``http``. The details about what fields thehomeserver should send
+ /// to the push gateway are defined in the`Push Gateway Specification`_.
+ /// Currently the only formatavailable is 'event_id_only'.
+ QString format;
};
+
+ // Construction/destruction
+
+ /*! Modify a pusher for this user on the homeserver.
+ * \param pushkey
+ * This is a unique identifier for this pusher. The value you
+ * should use for this is the routing or destination address
+ * information for the notification, for example, the APNS token
+ * for APNS or the Registration ID for GCM. If your notification
+ * client has no such concept, use any unique identifier.
+ * Max length, 512 bytes.
+ *
+ * If the ``kind`` is ``"email"``, this is the email address to
+ * send notifications to.
+ * \param kind
+ * The kind of pusher to configure. ``"http"`` makes a pusher that
+ * sends HTTP pokes. ``"email"`` makes a pusher that emails the
+ * user with unread notifications. ``null`` deletes the pusher.
+ * \param appId
+ * This is a reverse-DNS style identifier for the application.
+ * It is recommended that this end with the platform, such that
+ * different platform versions get different app identifiers.
+ * Max length, 64 chars.
+ *
+ * If the ``kind`` is ``"email"``, this is ``"m.email"``.
+ * \param appDisplayName
+ * A string that will allow the user to identify what application
+ * owns this pusher.
+ * \param deviceDisplayName
+ * A string that will allow the user to identify what device owns
+ * this pusher.
+ * \param lang
+ * The preferred language for receiving notifications (e.g. 'en'
+ * or 'en-US').
+ * \param data
+ * A dictionary of information for the pusher implementation
+ * itself. If ``kind`` is ``http``, this should contain ``url``
+ * which is the URL to use to send notifications to.
+ * \param profileTag
+ * This string determines which set of device specific rules this
+ * pusher executes.
+ * \param append
+ * If true, the homeserver should add another pusher with the
+ * given pushkey and App ID in addition to any others with
+ * different user IDs. Otherwise, the homeserver must remove any
+ * other pushers with the same App ID and pushkey for different
+ * users. The default is ``false``.
+ */
+ explicit PostPusherJob(const QString& pushkey, const QString& kind,
+ const QString& appId, const QString& appDisplayName,
+ const QString& deviceDisplayName,
+ const QString& lang, const PusherData& data,
+ const QString& profileTag = {},
+ Omittable<bool> append = none);
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp
index e70cbbde..5842369f 100644
--- a/lib/csapi/pushrules.cpp
+++ b/lib/csapi/pushrules.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetPushRulesJob::Private
{
- public:
+public:
PushRuleset global;
};
@@ -26,10 +26,9 @@ QUrl GetPushRulesJob::makeRequestUrl(QUrl baseUrl)
static const auto GetPushRulesJobName = QStringLiteral("GetPushRulesJob");
GetPushRulesJob::GetPushRulesJob()
- : BaseJob(HttpVerb::Get, GetPushRulesJobName, basePath % "/pushrules"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetPushRulesJobName, basePath % "/pushrules")
+ , d(new Private)
+{}
GetPushRulesJob::~GetPushRulesJob() = default;
@@ -39,23 +38,25 @@ BaseJob::Status GetPushRulesJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("global"_ls))
- return { JsonParseError, "The key 'global' not found in the response" };
+ return { IncorrectResponse,
+ "The key 'global' not found in the response" };
fromJson(json.value("global"_ls), d->global);
+
return Success;
}
class GetPushRuleJob::Private
{
- public:
+public:
PushRule data;
};
QUrl GetPushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind, const QString& ruleId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/pushrules/"
+ % scope % "/" % kind
+ % "/" % ruleId);
}
static const auto GetPushRuleJobName = QStringLiteral("GetPushRuleJob");
@@ -63,10 +64,9 @@ static const auto GetPushRuleJobName = QStringLiteral("GetPushRuleJob");
GetPushRuleJob::GetPushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, GetPushRuleJobName,
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId),
- d(new Private)
-{
-}
+ basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId)
+ , d(new Private)
+{}
GetPushRuleJob::~GetPushRuleJob() = default;
@@ -82,9 +82,9 @@ QUrl DeletePushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind,
const QString& ruleId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/pushrules/"
+ % scope % "/" % kind
+ % "/" % ruleId);
}
static const auto DeletePushRuleJobName = QStringLiteral("DeletePushRuleJob");
@@ -93,8 +93,7 @@ DeletePushRuleJob::DeletePushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Delete, DeletePushRuleJobName,
basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId)
-{
-}
+{}
BaseJob::Query queryToSetPushRule(const QString& before, const QString& after)
{
@@ -107,8 +106,7 @@ BaseJob::Query queryToSetPushRule(const QString& before, const QString& after)
static const auto SetPushRuleJobName = QStringLiteral("SetPushRuleJob");
SetPushRuleJob::SetPushRuleJob(const QString& scope, const QString& kind,
- const QString& ruleId,
- const QStringList& actions,
+ const QString& ruleId, const QStringList& actions,
const QString& before, const QString& after,
const QVector<PushCondition>& conditions,
const QString& pattern)
@@ -125,7 +123,7 @@ SetPushRuleJob::SetPushRuleJob(const QString& scope, const QString& kind,
class IsPushRuleEnabledJob::Private
{
- public:
+public:
bool enabled;
};
@@ -135,21 +133,20 @@ QUrl IsPushRuleEnabledJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId % "/enabled");
+ % "/" % ruleId % "/enabled");
}
static const auto IsPushRuleEnabledJobName =
- QStringLiteral("IsPushRuleEnabledJob");
+ QStringLiteral("IsPushRuleEnabledJob");
IsPushRuleEnabledJob::IsPushRuleEnabledJob(const QString& scope,
const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, IsPushRuleEnabledJobName,
basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/enabled"),
- d(new Private)
-{
-}
+ % "/enabled")
+ , d(new Private)
+{}
IsPushRuleEnabledJob::~IsPushRuleEnabledJob() = default;
@@ -159,22 +156,22 @@ BaseJob::Status IsPushRuleEnabledJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("enabled"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'enabled' not found in the response" };
fromJson(json.value("enabled"_ls), d->enabled);
+
return Success;
}
static const auto SetPushRuleEnabledJobName =
- QStringLiteral("SetPushRuleEnabledJob");
+ QStringLiteral("SetPushRuleEnabledJob");
SetPushRuleEnabledJob::SetPushRuleEnabledJob(const QString& scope,
const QString& kind,
- const QString& ruleId,
- bool enabled)
+ const QString& ruleId, bool enabled)
: BaseJob(HttpVerb::Put, SetPushRuleEnabledJobName,
basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/enabled")
+ % "/enabled")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("enabled"), enabled);
@@ -183,7 +180,7 @@ SetPushRuleEnabledJob::SetPushRuleEnabledJob(const QString& scope,
class GetPushRuleActionsJob::Private
{
- public:
+public:
QStringList actions;
};
@@ -193,21 +190,20 @@ QUrl GetPushRuleActionsJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/pushrules/" % scope % "/" % kind
- % "/" % ruleId % "/actions");
+ % "/" % ruleId % "/actions");
}
static const auto GetPushRuleActionsJobName =
- QStringLiteral("GetPushRuleActionsJob");
+ QStringLiteral("GetPushRuleActionsJob");
GetPushRuleActionsJob::GetPushRuleActionsJob(const QString& scope,
const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, GetPushRuleActionsJobName,
basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/actions"),
- d(new Private)
-{
-}
+ % "/actions")
+ , d(new Private)
+{}
GetPushRuleActionsJob::~GetPushRuleActionsJob() = default;
@@ -217,14 +213,15 @@ BaseJob::Status GetPushRuleActionsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("actions"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'actions' not found in the response" };
fromJson(json.value("actions"_ls), d->actions);
+
return Success;
}
static const auto SetPushRuleActionsJobName =
- QStringLiteral("SetPushRuleActionsJob");
+ QStringLiteral("SetPushRuleActionsJob");
SetPushRuleActionsJob::SetPushRuleActionsJob(const QString& scope,
const QString& kind,
@@ -232,7 +229,7 @@ SetPushRuleActionsJob::SetPushRuleActionsJob(const QString& scope,
const QStringList& actions)
: BaseJob(HttpVerb::Put, SetPushRuleActionsJobName,
basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/actions")
+ % "/actions")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("actions"), actions);
diff --git a/lib/csapi/pushrules.h b/lib/csapi/pushrules.h
index 5191d129..9074addb 100644
--- a/lib/csapi/pushrules.h
+++ b/lib/csapi/pushrules.h
@@ -4,287 +4,297 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/push_condition.h"
#include "csapi/definitions/push_rule.h"
#include "csapi/definitions/push_ruleset.h"
+
+#include "jobs/basejob.h"
+
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
-
- /// Retrieve all push rulesets.
- ///
- /// Retrieve all push rulesets for this user. Clients can "drill-down" on
- /// the rulesets by suffixing a ``scope`` to this path e.g.
- /// ``/pushrules/global/``. This will return a subset of this data under the
- /// specified key e.g. the ``global`` key.
- class GetPushRulesJob : public BaseJob
- {
- public:
- explicit GetPushRulesJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetPushRulesJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetPushRulesJob() override;
-
- // Result properties
-
- /// The global ruleset.
- const PushRuleset& global() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Retrieve a push rule.
- ///
- /// Retrieve a single specified push rule.
- class GetPushRuleJob : public BaseJob
- {
- public:
- /*! Retrieve a push rule.
- * \param scope
- * ``global`` to specify global rules.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- */
- explicit GetPushRuleJob(const QString& scope, const QString& kind,
- const QString& ruleId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetPushRuleJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
- const QString& kind, const QString& ruleId);
-
- ~GetPushRuleJob() override;
-
- // Result properties
-
- /// The push rule.
- const PushRule& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Delete a push rule.
- ///
- /// This endpoint removes the push rule defined in the path.
- class DeletePushRuleJob : public BaseJob
- {
- public:
- /*! Delete a push rule.
- * \param scope
- * ``global`` to specify global rules.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- */
- explicit DeletePushRuleJob(const QString& scope, const QString& kind,
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Retrieve all push rulesets.
+/*!
+ * Retrieve all push rulesets for this user. Clients can "drill-down" on
+ * the rulesets by suffixing a ``scope`` to this path e.g.
+ * ``/pushrules/global/``. This will return a subset of this data under the
+ * specified key e.g. the ``global`` key.
+ */
+class GetPushRulesJob : public BaseJob
+{
+public:
+ explicit GetPushRulesJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetPushRulesJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetPushRulesJob() override;
+
+ // Result properties
+
+ /// The global ruleset.
+ const PushRuleset& global() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Retrieve a push rule.
+/*!
+ * Retrieve a single specified push rule.
+ */
+class GetPushRuleJob : public BaseJob
+{
+public:
+ /*! Retrieve a push rule.
+ * \param scope
+ * ``global`` to specify global rules.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ */
+ explicit GetPushRuleJob(const QString& scope, const QString& kind,
+ const QString& ruleId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetPushRuleJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
+ const QString& kind, const QString& ruleId);
+
+ ~GetPushRuleJob() override;
+
+ // Result properties
+
+ /// The push rule.
+ const PushRule& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Delete a push rule.
+/*!
+ * This endpoint removes the push rule defined in the path.
+ */
+class DeletePushRuleJob : public BaseJob
+{
+public:
+ /*! Delete a push rule.
+ * \param scope
+ * ``global`` to specify global rules.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ */
+ explicit DeletePushRuleJob(const QString& scope, const QString& kind,
+ const QString& ruleId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * DeletePushRuleJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
+ const QString& kind, const QString& ruleId);
+};
+
+/// Add or change a push rule.
+/*!
+ * This endpoint allows the creation, modification and deletion of pushers
+ * for this user ID. The behaviour of this endpoint varies depending on the
+ * values in the JSON body.
+ *
+ * When creating push rules, they MUST be enabled by default.
+ */
+class SetPushRuleJob : public BaseJob
+{
+public:
+ /*! Add or change a push rule.
+ * \param scope
+ * ``global`` to specify global rules.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ * \param actions
+ * The action(s) to perform when the conditions for this rule are met.
+ * \param before
+ * Use 'before' with a ``rule_id`` as its value to make the new rule the
+ * next-most important rule with respect to the given user defined rule.
+ * It is not possible to add a rule relative to a predefined server rule.
+ * \param after
+ * This makes the new rule the next-less important rule relative to the
+ * given user defined rule. It is not possible to add a rule relative
+ * to a predefined server rule.
+ * \param conditions
+ * The conditions that must hold true for an event in order for a
+ * rule to be applied to an event. A rule with no conditions
+ * always matches. Only applicable to ``underride`` and ``override``
+ * rules. \param pattern Only applicable to ``content`` rules. The
+ * glob-style pattern to match against.
+ */
+ explicit SetPushRuleJob(const QString& scope, const QString& kind,
+ const QString& ruleId, const QStringList& actions,
+ const QString& before = {},
+ const QString& after = {},
+ const QVector<PushCondition>& conditions = {},
+ const QString& pattern = {});
+};
+
+/// Get whether a push rule is enabled
+/*!
+ * This endpoint gets whether the specified push rule is enabled.
+ */
+class IsPushRuleEnabledJob : public BaseJob
+{
+public:
+ /*! Get whether a push rule is enabled
+ * \param scope
+ * Either ``global`` or ``device/<profile_tag>`` to specify global
+ * rules or device rules for the given ``profile_tag``.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ */
+ explicit IsPushRuleEnabledJob(const QString& scope, const QString& kind,
+ const QString& ruleId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * IsPushRuleEnabledJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
+ const QString& kind, const QString& ruleId);
+
+ ~IsPushRuleEnabledJob() override;
+
+ // Result properties
+
+ /// Whether the push rule is enabled or not.
+ bool enabled() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Enable or disable a push rule.
+/*!
+ * This endpoint allows clients to enable or disable the specified push rule.
+ */
+class SetPushRuleEnabledJob : public BaseJob
+{
+public:
+ /*! Enable or disable a push rule.
+ * \param scope
+ * ``global`` to specify global rules.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ * \param enabled
+ * Whether the push rule is enabled or not.
+ */
+ explicit SetPushRuleEnabledJob(const QString& scope, const QString& kind,
+ const QString& ruleId, bool enabled);
+};
+
+/// The actions for a push rule
+/*!
+ * This endpoint get the actions for the specified push rule.
+ */
+class GetPushRuleActionsJob : public BaseJob
+{
+public:
+ /*! The actions for a push rule
+ * \param scope
+ * Either ``global`` or ``device/<profile_tag>`` to specify global
+ * rules or device rules for the given ``profile_tag``.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ */
+ explicit GetPushRuleActionsJob(const QString& scope, const QString& kind,
const QString& ruleId);
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * DeletePushRuleJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
- const QString& kind, const QString& ruleId);
- };
-
- /// Add or change a push rule.
- ///
- /// This endpoint allows the creation, modification and deletion of pushers
- /// for this user ID. The behaviour of this endpoint varies depending on the
- /// values in the JSON body.
- ///
- /// When creating push rules, they MUST be enabled by default.
- class SetPushRuleJob : public BaseJob
- {
- public:
- /*! Add or change a push rule.
- * \param scope
- * ``global`` to specify global rules.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- * \param actions
- * The action(s) to perform when the conditions for this rule are met.
- * \param before
- * Use 'before' with a ``rule_id`` as its value to make the new rule
- * the next-most important rule with respect to the given user defined
- * rule. It is not possible to add a rule relative to a predefined
- * server rule. \param after This makes the new rule the next-less
- * important rule relative to the given user defined rule. It is not
- * possible to add a rule relative to a predefined server rule. \param
- * conditions The conditions that must hold true for an event in order
- * for a rule to be applied to an event. A rule with no conditions
- * always matches. Only applicable to ``underride`` and ``override``
- * rules. \param pattern Only applicable to ``content`` rules. The
- * glob-style pattern to match against.
- */
- explicit SetPushRuleJob(const QString& scope, const QString& kind,
- const QString& ruleId,
- const QStringList& actions,
- const QString& before = {},
- const QString& after = {},
- const QVector<PushCondition>& conditions = {},
- const QString& pattern = {});
- };
-
- /// Get whether a push rule is enabled
- ///
- /// This endpoint gets whether the specified push rule is enabled.
- class IsPushRuleEnabledJob : public BaseJob
- {
- public:
- /*! Get whether a push rule is enabled
- * \param scope
- * Either ``global`` or ``device/<profile_tag>`` to specify global
- * rules or device rules for the given ``profile_tag``.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- */
- explicit IsPushRuleEnabledJob(const QString& scope, const QString& kind,
- const QString& ruleId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * IsPushRuleEnabledJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
- const QString& kind, const QString& ruleId);
-
- ~IsPushRuleEnabledJob() override;
-
- // Result properties
-
- /// Whether the push rule is enabled or not.
- bool enabled() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Enable or disable a push rule.
- ///
- /// This endpoint allows clients to enable or disable the specified push
- /// rule.
- class SetPushRuleEnabledJob : public BaseJob
- {
- public:
- /*! Enable or disable a push rule.
- * \param scope
- * ``global`` to specify global rules.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- * \param enabled
- * Whether the push rule is enabled or not.
- */
- explicit SetPushRuleEnabledJob(const QString& scope,
- const QString& kind,
- const QString& ruleId, bool enabled);
- };
-
- /// The actions for a push rule
- ///
- /// This endpoint get the actions for the specified push rule.
- class GetPushRuleActionsJob : public BaseJob
- {
- public:
- /*! The actions for a push rule
- * \param scope
- * Either ``global`` or ``device/<profile_tag>`` to specify global
- * rules or device rules for the given ``profile_tag``.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- */
- explicit GetPushRuleActionsJob(const QString& scope,
- const QString& kind,
- const QString& ruleId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetPushRuleActionsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
- const QString& kind, const QString& ruleId);
-
- ~GetPushRuleActionsJob() override;
-
- // Result properties
-
- /// The action(s) to perform for this rule.
- const QStringList& actions() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Set the actions for a push rule.
- ///
- /// This endpoint allows clients to change the actions of a push rule.
- /// This can be used to change the actions of builtin rules.
- class SetPushRuleActionsJob : public BaseJob
- {
- public:
- /*! Set the actions for a push rule.
- * \param scope
- * ``global`` to specify global rules.
- * \param kind
- * The kind of rule
- * \param ruleId
- * The identifier for the rule.
- * \param actions
- * The action(s) to perform for this rule.
- */
- explicit SetPushRuleActionsJob(const QString& scope,
- const QString& kind,
- const QString& ruleId,
- const QStringList& actions);
- };
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetPushRuleActionsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
+ const QString& kind, const QString& ruleId);
+
+ ~GetPushRuleActionsJob() override;
+
+ // Result properties
+
+ /// The action(s) to perform for this rule.
+ const QStringList& actions() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Set the actions for a push rule.
+/*!
+ * This endpoint allows clients to change the actions of a push rule.
+ * This can be used to change the actions of builtin rules.
+ */
+class SetPushRuleActionsJob : public BaseJob
+{
+public:
+ /*! Set the actions for a push rule.
+ * \param scope
+ * ``global`` to specify global rules.
+ * \param kind
+ * The kind of rule
+ * \param ruleId
+ * The identifier for the rule.
+ * \param actions
+ * The action(s) to perform for this rule.
+ */
+ explicit SetPushRuleActionsJob(const QString& scope, const QString& kind,
+ const QString& ruleId,
+ const QStringList& actions);
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/read_markers.h b/lib/csapi/read_markers.h
index 6afa5572..e1fbc263 100644
--- a/lib/csapi/read_markers.h
+++ b/lib/csapi/read_markers.h
@@ -6,29 +6,32 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Set the position of the read marker for a room.
+/*!
+ * Sets the position of the read marker for a given room, and optionally
+ * the read receipt's location.
+ */
+class SetReadMarkerJob : public BaseJob
+{
+public:
+ /*! Set the position of the read marker for a room.
+ * \param roomId
+ * The room ID to set the read marker in for the user.
+ * \param mFullyRead
+ * The event ID the read marker should be located at. The
+ * event MUST belong to the room.
+ * \param mRead
+ * The event ID to set the read receipt location at. This is
+ * equivalent to calling ``/receipt/m.read/$elsewhere:example.org``
+ * and is provided here to save that extra call.
+ */
+ explicit SetReadMarkerJob(const QString& roomId, const QString& mFullyRead,
+ const QString& mRead = {});
+};
- /// Set the position of the read marker for a room.
- ///
- /// Sets the position of the read marker for a given room, and optionally
- /// the read receipt's location.
- class SetReadMarkerJob : public BaseJob
- {
- public:
- /*! Set the position of the read marker for a room.
- * \param roomId
- * The room ID to set the read marker in for the user.
- * \param mFullyRead
- * The event ID the read marker should be located at. The
- * event MUST belong to the room.
- * \param mRead
- * The event ID to set the read receipt location at. This is
- * equivalent to calling ``/receipt/m.read/$elsewhere:example.org``
- * and is provided here to save that extra call.
- */
- explicit SetReadMarkerJob(const QString& roomId,
- const QString& mFullyRead,
- const QString& mRead = {});
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/receipts.cpp b/lib/csapi/receipts.cpp
index 25d0dd8e..28d7032f 100644
--- a/lib/csapi/receipts.cpp
+++ b/lib/csapi/receipts.cpp
@@ -14,13 +14,12 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
static const auto PostReceiptJobName = QStringLiteral("PostReceiptJob");
-PostReceiptJob::PostReceiptJob(const QString& roomId,
- const QString& receiptType,
+PostReceiptJob::PostReceiptJob(const QString& roomId, const QString& receiptType,
const QString& eventId,
const QJsonObject& receipt)
: BaseJob(HttpVerb::Post, PostReceiptJobName,
basePath % "/rooms/" % roomId % "/receipt/" % receiptType % "/"
- % eventId)
+ % eventId)
{
setRequestData(Data(toJson(receipt)));
}
diff --git a/lib/csapi/receipts.h b/lib/csapi/receipts.h
index 4e40188a..bb037c08 100644
--- a/lib/csapi/receipts.h
+++ b/lib/csapi/receipts.h
@@ -8,30 +8,33 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Send a receipt for the given event ID.
+/*!
+ * This API updates the marker for the given receipt type to the event ID
+ * specified.
+ */
+class PostReceiptJob : public BaseJob
+{
+public:
+ /*! Send a receipt for the given event ID.
+ * \param roomId
+ * The room in which to send the event.
+ * \param receiptType
+ * The type of receipt to send.
+ * \param eventId
+ * The event ID to acknowledge up to.
+ * \param receipt
+ * Extra receipt information to attach to ``content`` if any. The
+ * server will automatically set the ``ts`` field.
+ */
+ explicit PostReceiptJob(const QString& roomId, const QString& receiptType,
+ const QString& eventId,
+ const QJsonObject& receipt = {});
+};
- /// Send a receipt for the given event ID.
- ///
- /// This API updates the marker for the given receipt type to the event ID
- /// specified.
- class PostReceiptJob : public BaseJob
- {
- public:
- /*! Send a receipt for the given event ID.
- * \param roomId
- * The room in which to send the event.
- * \param receiptType
- * The type of receipt to send.
- * \param eventId
- * The event ID to acknowledge up to.
- * \param receipt
- * Extra receipt information to attach to ``content`` if any. The
- * server will automatically set the ``ts`` field.
- */
- explicit PostReceiptJob(const QString& roomId,
- const QString& receiptType,
- const QString& eventId,
- const QJsonObject& receipt = {});
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/redaction.cpp b/lib/csapi/redaction.cpp
index 713c5102..f944cdd4 100644
--- a/lib/csapi/redaction.cpp
+++ b/lib/csapi/redaction.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class RedactEventJob::Private
{
- public:
+public:
QString eventId;
};
@@ -23,9 +23,8 @@ static const auto RedactEventJobName = QStringLiteral("RedactEventJob");
RedactEventJob::RedactEventJob(const QString& roomId, const QString& eventId,
const QString& txnId, const QString& reason)
: BaseJob(HttpVerb::Put, RedactEventJobName,
- basePath % "/rooms/" % roomId % "/redact/" % eventId % "/"
- % txnId),
- d(new Private)
+ basePath % "/rooms/" % roomId % "/redact/" % eventId % "/" % txnId)
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason);
@@ -40,5 +39,6 @@ BaseJob::Status RedactEventJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("event_id"_ls), d->eventId);
+
return Success;
}
diff --git a/lib/csapi/redaction.h b/lib/csapi/redaction.h
index ab235b31..c75421cb 100644
--- a/lib/csapi/redaction.h
+++ b/lib/csapi/redaction.h
@@ -6,47 +6,51 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Strips all non-integrity-critical information out of an event.
- ///
- /// Strips all information out of an event which isn't critical to the
- /// integrity of the server-side representation of the room.
- ///
- /// This cannot be undone.
- ///
- /// Users may redact their own events, and any user with a power level
- /// greater than or equal to the `redact` power level of the room may
- /// redact events there.
- class RedactEventJob : public BaseJob
- {
- public:
- /*! Strips all non-integrity-critical information out of an event.
- * \param roomId
- * The room from which to redact the event.
- * \param eventId
- * The ID of the event to redact
- * \param txnId
- * The transaction ID for this event. Clients should generate a
- * unique ID; it will be used by the server to ensure idempotency of
- * requests. \param reason The reason for the event being redacted.
- */
- explicit RedactEventJob(const QString& roomId, const QString& eventId,
- const QString& txnId,
- const QString& reason = {});
- ~RedactEventJob() override;
-
- // Result properties
-
- /// A unique identifier for the event.
- const QString& eventId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Strips all non-integrity-critical information out of an event.
+/*!
+ * Strips all information out of an event which isn't critical to the
+ * integrity of the server-side representation of the room.
+ *
+ * This cannot be undone.
+ *
+ * Users may redact their own events, and any user with a power level
+ * greater than or equal to the `redact` power level of the room may
+ * redact events there.
+ */
+class RedactEventJob : public BaseJob
+{
+public:
+ /*! Strips all non-integrity-critical information out of an event.
+ * \param roomId
+ * The room from which to redact the event.
+ * \param eventId
+ * The ID of the event to redact
+ * \param txnId
+ * The transaction ID for this event. Clients should generate a
+ * unique ID; it will be used by the server to ensure idempotency of
+ * requests. \param reason The reason for the event being redacted.
+ */
+ explicit RedactEventJob(const QString& roomId, const QString& eventId,
+ const QString& txnId, const QString& reason = {});
+
+ ~RedactEventJob() override;
+
+ // Result properties
+
+ /// A unique identifier for the event.
+ const QString& eventId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp
index b5e7d985..52b4098d 100644
--- a/lib/csapi/registration.cpp
+++ b/lib/csapi/registration.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class RegisterJob::Private
{
- public:
+public:
QString userId;
QString accessToken;
QString homeServer;
@@ -37,8 +37,8 @@ RegisterJob::RegisterJob(const QString& kind,
const QString& initialDeviceDisplayName,
Omittable<bool> inhibitLogin)
: BaseJob(HttpVerb::Post, RegisterJobName, basePath % "/register",
- queryToRegister(kind), {}, false),
- d(new Private)
+ queryToRegister(kind), {}, false)
+ , d(new Private)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
@@ -66,30 +66,31 @@ BaseJob::Status RegisterJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("user_id"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'user_id' not found in the response" };
fromJson(json.value("user_id"_ls), d->userId);
fromJson(json.value("access_token"_ls), d->accessToken);
fromJson(json.value("home_server"_ls), d->homeServer);
fromJson(json.value("device_id"_ls), d->deviceId);
+
return Success;
}
class RequestTokenToRegisterEmailJob::Private
{
- public:
+public:
Sid data;
};
static const auto RequestTokenToRegisterEmailJobName =
- QStringLiteral("RequestTokenToRegisterEmailJob");
+ QStringLiteral("RequestTokenToRegisterEmailJob");
RequestTokenToRegisterEmailJob::RequestTokenToRegisterEmailJob(
- const QString& clientSecret, const QString& email, int sendAttempt,
- const QString& idServer, const QString& nextLink)
+ const QString& clientSecret, const QString& email, int sendAttempt,
+ const QString& idServer, const QString& nextLink)
: BaseJob(HttpVerb::Post, RequestTokenToRegisterEmailJobName,
- basePath % "/register/email/requestToken", false),
- d(new Private)
+ basePath % "/register/email/requestToken", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -113,20 +114,20 @@ RequestTokenToRegisterEmailJob::parseJson(const QJsonDocument& data)
class RequestTokenToRegisterMSISDNJob::Private
{
- public:
+public:
Sid data;
};
static const auto RequestTokenToRegisterMSISDNJobName =
- QStringLiteral("RequestTokenToRegisterMSISDNJob");
+ QStringLiteral("RequestTokenToRegisterMSISDNJob");
RequestTokenToRegisterMSISDNJob::RequestTokenToRegisterMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt, const QString& idServer,
- const QString& nextLink)
+ const QString& clientSecret, const QString& country,
+ const QString& phoneNumber, int sendAttempt, const QString& idServer,
+ const QString& nextLink)
: BaseJob(HttpVerb::Post, RequestTokenToRegisterMSISDNJobName,
- basePath % "/register/msisdn/requestToken", false),
- d(new Private)
+ basePath % "/register/msisdn/requestToken", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -164,19 +165,19 @@ ChangePasswordJob::ChangePasswordJob(const QString& newPassword,
class RequestTokenToResetPasswordEmailJob::Private
{
- public:
+public:
Sid data;
};
static const auto RequestTokenToResetPasswordEmailJobName =
- QStringLiteral("RequestTokenToResetPasswordEmailJob");
+ QStringLiteral("RequestTokenToResetPasswordEmailJob");
RequestTokenToResetPasswordEmailJob::RequestTokenToResetPasswordEmailJob(
- const QString& clientSecret, const QString& email, int sendAttempt,
- const QString& idServer, const QString& nextLink)
+ const QString& clientSecret, const QString& email, int sendAttempt,
+ const QString& idServer, const QString& nextLink)
: BaseJob(HttpVerb::Post, RequestTokenToResetPasswordEmailJobName,
- basePath % "/account/password/email/requestToken", false),
- d(new Private)
+ basePath % "/account/password/email/requestToken", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -188,7 +189,7 @@ RequestTokenToResetPasswordEmailJob::RequestTokenToResetPasswordEmailJob(
}
RequestTokenToResetPasswordEmailJob::~RequestTokenToResetPasswordEmailJob() =
- default;
+ default;
const Sid& RequestTokenToResetPasswordEmailJob::data() const { return d->data; }
@@ -201,20 +202,20 @@ RequestTokenToResetPasswordEmailJob::parseJson(const QJsonDocument& data)
class RequestTokenToResetPasswordMSISDNJob::Private
{
- public:
+public:
Sid data;
};
static const auto RequestTokenToResetPasswordMSISDNJobName =
- QStringLiteral("RequestTokenToResetPasswordMSISDNJob");
+ QStringLiteral("RequestTokenToResetPasswordMSISDNJob");
RequestTokenToResetPasswordMSISDNJob::RequestTokenToResetPasswordMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt, const QString& idServer,
- const QString& nextLink)
+ const QString& clientSecret, const QString& country,
+ const QString& phoneNumber, int sendAttempt, const QString& idServer,
+ const QString& nextLink)
: BaseJob(HttpVerb::Post, RequestTokenToResetPasswordMSISDNJobName,
- basePath % "/account/password/msisdn/requestToken", false),
- d(new Private)
+ basePath % "/account/password/msisdn/requestToken", false)
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
@@ -227,7 +228,7 @@ RequestTokenToResetPasswordMSISDNJob::RequestTokenToResetPasswordMSISDNJob(
}
RequestTokenToResetPasswordMSISDNJob::~RequestTokenToResetPasswordMSISDNJob() =
- default;
+ default;
const Sid& RequestTokenToResetPasswordMSISDNJob::data() const
{
@@ -242,10 +243,10 @@ RequestTokenToResetPasswordMSISDNJob::parseJson(const QJsonDocument& data)
}
static const auto DeactivateAccountJobName =
- QStringLiteral("DeactivateAccountJob");
+ QStringLiteral("DeactivateAccountJob");
DeactivateAccountJob::DeactivateAccountJob(
- const Omittable<AuthenticationData>& auth)
+ const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Post, DeactivateAccountJobName,
basePath % "/account/deactivate")
{
@@ -256,7 +257,7 @@ DeactivateAccountJob::DeactivateAccountJob(
class CheckUsernameAvailabilityJob::Private
{
- public:
+public:
Omittable<bool> available;
};
@@ -276,16 +277,14 @@ QUrl CheckUsernameAvailabilityJob::makeRequestUrl(QUrl baseUrl,
}
static const auto CheckUsernameAvailabilityJobName =
- QStringLiteral("CheckUsernameAvailabilityJob");
+ QStringLiteral("CheckUsernameAvailabilityJob");
-CheckUsernameAvailabilityJob::CheckUsernameAvailabilityJob(
- const QString& username)
+CheckUsernameAvailabilityJob::CheckUsernameAvailabilityJob(const QString& username)
: BaseJob(HttpVerb::Get, CheckUsernameAvailabilityJobName,
basePath % "/register/available",
- queryToCheckUsernameAvailability(username), {}, false),
- d(new Private)
-{
-}
+ queryToCheckUsernameAvailability(username), {}, false)
+ , d(new Private)
+{}
CheckUsernameAvailabilityJob::~CheckUsernameAvailabilityJob() = default;
@@ -294,10 +293,10 @@ Omittable<bool> CheckUsernameAvailabilityJob::available() const
return d->available;
}
-BaseJob::Status
-CheckUsernameAvailabilityJob::parseJson(const QJsonDocument& data)
+BaseJob::Status CheckUsernameAvailabilityJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("available"_ls), d->available);
+
return Success;
}
diff --git a/lib/csapi/registration.h b/lib/csapi/registration.h
index 02f4ddaf..40f1caa6 100644
--- a/lib/csapi/registration.h
+++ b/lib/csapi/registration.h
@@ -4,463 +4,480 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/../identity/definitions/sid.h"
#include "csapi/definitions/auth_data.h"
-namespace QMatrixClient {
- // Operations
+#include "jobs/basejob.h"
- /// Register for an account on this homeserver.
- ///
- /// This API endpoint uses the `User-Interactive Authentication API`_.
- ///
- /// Register for an account on this homeserver.
- ///
- /// There are two kinds of user account:
- ///
- /// - `user` accounts. These accounts may use the full API described in this
- /// specification.
- ///
- /// - `guest` accounts. These accounts may have limited permissions and may
- /// not be supported by all servers.
- ///
- /// If registration is successful, this endpoint will issue an access token
- /// the client can use to authorize itself in subsequent requests.
- ///
- /// If the client does not supply a ``device_id``, the server must
- /// auto-generate one.
- ///
- /// The server SHOULD register an account with a User ID based on the
- /// ``username`` provided, if any. Note that the grammar of Matrix User ID
- /// localparts is restricted, so the server MUST either map the provided
- /// ``username`` onto a ``user_id`` in a logical manner, or reject
- /// ``username``\s which do not comply to the grammar, with
- /// ``M_INVALID_USERNAME``.
- ///
- /// Matrix clients MUST NOT assume that localpart of the registered
- /// ``user_id`` matches the provided ``username``.
- ///
- /// The returned access token must be associated with the ``device_id``
- /// supplied by the client or generated by the server. The server may
- /// invalidate any access token previously associated with that device. See
- /// `Relationship between access tokens and devices`_.
- class RegisterJob : public BaseJob
- {
- public:
- /*! Register for an account on this homeserver.
- * \param kind
- * The kind of account to register. Defaults to `user`.
- * \param auth
- * Additional authentication information for the
- * user-interactive authentication API. Note that this
- * information is *not* used to define how the registered user
- * should be authenticated, but is instead used to
- * authenticate the ``register`` call itself. It should be
- * left empty, or omitted, unless an earlier call returned an
- * response with status code 401.
- * \param bindEmail
- * If true, the server binds the email used for authentication to
- * the Matrix ID with the identity server.
- * \param username
- * The basis for the localpart of the desired Matrix ID. If omitted,
- * the homeserver MUST generate a Matrix ID local part.
- * \param password
- * The desired password for the account.
- * \param deviceId
- * ID of the client device. If this does not correspond to a
- * known client device, a new device will be created. The server
- * will auto-generate a device_id if this is not specified.
- * \param initialDeviceDisplayName
- * A display name to assign to the newly-created device. Ignored
- * if ``device_id`` corresponds to a known device.
- * \param inhibitLogin
- * If true, an ``access_token`` and ``device_id`` should not be
- * returned from this call, therefore preventing an automatic
- * login. Defaults to false.
- */
- explicit RegisterJob(const QString& kind = QStringLiteral("user"),
- const Omittable<AuthenticationData>& auth = none,
- Omittable<bool> bindEmail = none,
- const QString& username = {},
- const QString& password = {},
- const QString& deviceId = {},
- const QString& initialDeviceDisplayName = {},
- Omittable<bool> inhibitLogin = none);
- ~RegisterJob() override;
-
- // Result properties
-
- /// The fully-qualified Matrix user ID (MXID) that has been registered.
- ///
- /// Any user ID returned by this API must conform to the grammar given
- /// in the `Matrix specification
- /// <https://matrix.org/docs/spec/appendices.html#user-identifiers>`_.
- const QString& userId() const;
- /// An access token for the account.
- /// This access token can then be used to authorize other requests.
- /// Required if the ``inhibit_login`` option is false.
- const QString& accessToken() const;
- /// The server_name of the homeserver on which the account has
- /// been registered.
- ///
- /// **Deprecated**. Clients should extract the server_name from
- /// ``user_id`` (by splitting at the first colon) if they require
- /// it. Note also that ``homeserver`` is not spelt this way.
- const QString& homeServer() const;
- /// 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.
- const QString& deviceId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Begins the validation process for an email to be used during
- /// registration.
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Register for an account on this homeserver.
+/*!
+ * This API endpoint uses the `User-Interactive Authentication API`_.
+ *
+ * Register for an account on this homeserver.
+ *
+ * There are two kinds of user account:
+ *
+ * - `user` accounts. These accounts may use the full API described in this
+ * specification.
+ *
+ * - `guest` accounts. These accounts may have limited permissions and may not
+ * be supported by all servers.
+ *
+ * If registration is successful, this endpoint will issue an access token
+ * the client can use to authorize itself in subsequent requests.
+ *
+ * If the client does not supply a ``device_id``, the server must
+ * auto-generate one.
+ *
+ * The server SHOULD register an account with a User ID based on the
+ * ``username`` provided, if any. Note that the grammar of Matrix User ID
+ * localparts is restricted, so the server MUST either map the provided
+ * ``username`` onto a ``user_id`` in a logical manner, or reject
+ * ``username``\s which do not comply to the grammar, with
+ * ``M_INVALID_USERNAME``.
+ *
+ * Matrix clients MUST NOT assume that localpart of the registered
+ * ``user_id`` matches the provided ``username``.
+ *
+ * The returned access token must be associated with the ``device_id``
+ * supplied by the client or generated by the server. The server may
+ * invalidate any access token previously associated with that device. See
+ * `Relationship between access tokens and devices`_.
+ */
+class RegisterJob : public BaseJob
+{
+public:
+ /*! Register for an account on this homeserver.
+ * \param kind
+ * The kind of account to register. Defaults to `user`.
+ * \param auth
+ * Additional authentication information for the
+ * user-interactive authentication API. Note that this
+ * information is *not* used to define how the registered user
+ * should be authenticated, but is instead used to
+ * authenticate the ``register`` call itself. It should be
+ * left empty, or omitted, unless an earlier call returned an
+ * response with status code 401.
+ * \param bindEmail
+ * If true, the server binds the email used for authentication to
+ * the Matrix ID with the identity server.
+ * \param username
+ * The basis for the localpart of the desired Matrix ID. If omitted,
+ * the homeserver MUST generate a Matrix ID local part.
+ * \param password
+ * The desired password for the account.
+ * \param deviceId
+ * ID of the client device. If this does not correspond to a
+ * known client device, a new device will be created. The server
+ * will auto-generate a device_id if this is not specified.
+ * \param initialDeviceDisplayName
+ * A display name to assign to the newly-created device. Ignored
+ * if ``device_id`` corresponds to a known device.
+ * \param inhibitLogin
+ * If true, an ``access_token`` and ``device_id`` should not be
+ * returned from this call, therefore preventing an automatic
+ * login. Defaults to false.
+ */
+ explicit RegisterJob(const QString& kind = QStringLiteral("user"),
+ const Omittable<AuthenticationData>& auth = none,
+ Omittable<bool> bindEmail = none,
+ const QString& username = {},
+ const QString& password = {},
+ const QString& deviceId = {},
+ const QString& initialDeviceDisplayName = {},
+ Omittable<bool> inhibitLogin = none);
+
+ ~RegisterJob() override;
+
+ // Result properties
+
+ /// The fully-qualified Matrix user ID (MXID) that has been registered.
///
- /// Proxies the Identity Service API ``validate/email/requestToken``, but
- /// first checks that the given email address is not already associated
- /// with an account on this homeserver. See the Identity Service API for
- /// further information.
- class RequestTokenToRegisterEmailJob : public BaseJob
- {
- public:
- /*! Begins the validation process for an email to be used during registration.
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the
- * characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- * it must not be empty. \param email The email address to validate.
- * \param sendAttempt
- * The server will only send an email if the ``send_attempt``
- * is a number greater than the most recent one which it has seen,
- * scoped to that ``email`` + ``client_secret`` pair. This is to
- * avoid repeatedly sending the same email in the case of request
- * retries between the POSTing user and the identity server.
- * The client should increment this value if they desire a new
- * email (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
- */
- explicit RequestTokenToRegisterEmailJob(const QString& clientSecret,
- const QString& email,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
- ~RequestTokenToRegisterEmailJob() override;
-
- // Result properties
-
- /// An email has been sent to the specified address.
- /// Note that this may be an email containing the validation token or it
- /// may be informing the user of an error.
- const Sid& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Requests a validation token be sent to the given phone number for the
- /// purpose of registering an account
+ /// Any user ID returned by this API must conform to the grammar given in
+ /// the `Matrix specification
+ /// <https://matrix.org/docs/spec/appendices.html#user-identifiers>`_.
+ const QString& userId() const;
+ /// An access token for the account.
+ /// This access token can then be used to authorize other requests.
+ /// Required if the ``inhibit_login`` option is false.
+ const QString& accessToken() const;
+ /// The server_name of the homeserver on which the account has
+ /// been registered.
///
- /// Proxies the Identity Service API ``validate/msisdn/requestToken``, but
- /// first checks that the given phone number is not already associated
- /// with an account on this homeserver. See the Identity Service API for
- /// further information.
- class RequestTokenToRegisterMSISDNJob : public BaseJob
- {
- public:
- /*! Requests a validation token be sent to the given phone number for the purpose of registering an account
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the
- * characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- * it must not be empty. \param country The two-letter uppercase ISO
- * country code that the number in
- * ``phone_number`` should be parsed as if it were dialled from.
- * \param phoneNumber
- * The phone number to validate.
- * \param sendAttempt
- * The server will only send an SMS if the ``send_attempt`` is a
- * number greater than the most recent one which it has seen,
- * scoped to that ``country`` + ``phone_number`` + ``client_secret``
- * triple. This is to avoid repeatedly sending the same SMS in
- * the case of request retries between the POSTing user and the
- * identity server. The client should increment this value if
- * they desire a new SMS (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
- */
- explicit RequestTokenToRegisterMSISDNJob(const QString& clientSecret,
- const QString& country,
- const QString& phoneNumber,
+ /// **Deprecated**. Clients should extract the server_name from
+ /// ``user_id`` (by splitting at the first colon) if they require
+ /// it. Note also that ``homeserver`` is not spelt this way.
+ const QString& homeServer() const;
+ /// 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.
+ const QString& deviceId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Begins the validation process for an email to be used during registration.
+/*!
+ * Proxies the Identity Service API ``validate/email/requestToken``, but
+ * first checks that the given email address is not already associated
+ * with an account on this homeserver. See the Identity Service API for
+ * further information.
+ */
+class RequestTokenToRegisterEmailJob : public BaseJob
+{
+public:
+ /*! Begins the validation process for an email to be used during
+ * registration. \param clientSecret A unique string generated by the
+ * client, and used to identify the validation attempt. It must be a string
+ * consisting of the characters
+ * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
+ * must not be empty.
+ * \param email
+ * The email address to validate.
+ * \param sendAttempt
+ * The server will only send an email if the ``send_attempt``
+ * is a number greater than the most recent one which it has seen,
+ * scoped to that ``email`` + ``client_secret`` pair. This is to
+ * avoid repeatedly sending the same email in the case of request
+ * retries between the POSTing user and the identity server.
+ * The client should increment this value if they desire a new
+ * email (e.g. a reminder) to be sent.
+ * \param idServer
+ * The hostname of the identity server to communicate with. May
+ * optionally include a port.
+ * \param nextLink
+ * Optional. When the validation is completed, the identity
+ * server will redirect the user to this URL.
+ */
+ explicit RequestTokenToRegisterEmailJob(const QString& clientSecret,
+ const QString& email,
+ int sendAttempt,
+ const QString& idServer,
+ const QString& nextLink = {});
+
+ ~RequestTokenToRegisterEmailJob() override;
+
+ // Result properties
+
+ /// An email has been sent to the specified address.
+ /// Note that this may be an email containing the validation token or it may
+ /// be informing the user of an error.
+ const Sid& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Requests a validation token be sent to the given phone number for the
+/// purpose of registering an account
+/*!
+ * Proxies the Identity Service API ``validate/msisdn/requestToken``, but
+ * first checks that the given phone number is not already associated
+ * with an account on this homeserver. See the Identity Service API for
+ * further information.
+ */
+class RequestTokenToRegisterMSISDNJob : public BaseJob
+{
+public:
+ /*! Requests a validation token be sent to the given phone number for the
+ * purpose of registering an account \param clientSecret A unique string
+ * generated by the client, and used to identify the validation attempt. It
+ * must be a string consisting of the characters
+ * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
+ * must not be empty.
+ * \param country
+ * The two-letter uppercase ISO country code that the number in
+ * ``phone_number`` should be parsed as if it were dialled from.
+ * \param phoneNumber
+ * The phone number to validate.
+ * \param sendAttempt
+ * The server will only send an SMS if the ``send_attempt`` is a
+ * number greater than the most recent one which it has seen,
+ * scoped to that ``country`` + ``phone_number`` + ``client_secret``
+ * triple. This is to avoid repeatedly sending the same SMS in
+ * the case of request retries between the POSTing user and the
+ * identity server. The client should increment this value if
+ * they desire a new SMS (e.g. a reminder) to be sent.
+ * \param idServer
+ * The hostname of the identity server to communicate with. May
+ * optionally include a port.
+ * \param nextLink
+ * Optional. When the validation is completed, the identity
+ * server will redirect the user to this URL.
+ */
+ explicit RequestTokenToRegisterMSISDNJob(const QString& clientSecret,
+ const QString& country,
+ const QString& phoneNumber,
+ int sendAttempt,
+ const QString& idServer,
+ const QString& nextLink = {});
+
+ ~RequestTokenToRegisterMSISDNJob() override;
+
+ // Result properties
+
+ /// An SMS message has been sent to the specified phone number.
+ /// Note that this may be an SMS message containing the validation token or
+ /// it may be informing the user of an error.
+ const Sid& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Changes a user's password.
+/*!
+ * Changes the password for an account on this homeserver.
+ *
+ * This API endpoint uses the `User-Interactive Authentication API`_.
+ *
+ * An access token should be submitted to this endpoint if the client has
+ * an active session.
+ *
+ * The homeserver may change the flows available depending on whether a
+ * valid access token is provided.
+ */
+class ChangePasswordJob : public BaseJob
+{
+public:
+ /*! Changes a user's password.
+ * \param newPassword
+ * The new password for the account.
+ * \param auth
+ * Additional authentication information for the user-interactive
+ * authentication API.
+ */
+ explicit ChangePasswordJob(const QString& newPassword,
+ const Omittable<AuthenticationData>& auth = none);
+};
+
+/// Requests a validation token be sent to the given email address for the
+/// purpose of resetting a user's password
+/*!
+ * Proxies the Identity Service API ``validate/email/requestToken``, but
+ * first checks that the given email address **is** associated with an account
+ * on this homeserver. This API should be used to request
+ * validation tokens when authenticating for the
+ * `account/password` endpoint. This API's parameters and response are
+ * identical to that of the HS API |/register/email/requestToken|_ except that
+ * `M_THREEPID_NOT_FOUND` may be returned if no account matching the
+ * given email address could be found. The server may instead send an
+ * email to the given address prompting the user to create an account.
+ * `M_THREEPID_IN_USE` may not be returned.
+ *
+ * .. |/register/email/requestToken| replace:: ``/register/email/requestToken``
+ *
+ * .. _/register/email/requestToken:
+ * #post-matrix-client-r0-register-email-requesttoken
+ */
+class RequestTokenToResetPasswordEmailJob : public BaseJob
+{
+public:
+ /*! Requests a validation token be sent to the given email address for the
+ * purpose of resetting a user's password \param clientSecret A unique
+ * string generated by the client, and used to identify the validation
+ * attempt. It must be a string consisting of the characters
+ * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
+ * must not be empty.
+ * \param email
+ * The email address to validate.
+ * \param sendAttempt
+ * The server will only send an email if the ``send_attempt``
+ * is a number greater than the most recent one which it has seen,
+ * scoped to that ``email`` + ``client_secret`` pair. This is to
+ * avoid repeatedly sending the same email in the case of request
+ * retries between the POSTing user and the identity server.
+ * The client should increment this value if they desire a new
+ * email (e.g. a reminder) to be sent.
+ * \param idServer
+ * The hostname of the identity server to communicate with. May
+ * optionally include a port.
+ * \param nextLink
+ * Optional. When the validation is completed, the identity
+ * server will redirect the user to this URL.
+ */
+ explicit RequestTokenToResetPasswordEmailJob(const QString& clientSecret,
+ const QString& email,
int sendAttempt,
const QString& idServer,
const QString& nextLink = {});
- ~RequestTokenToRegisterMSISDNJob() override;
-
- // Result properties
-
- /// An SMS message has been sent to the specified phone number.
- /// Note that this may be an SMS message containing the validation token
- /// or it may be informing the user of an error.
- const Sid& data() const;
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ ~RequestTokenToResetPasswordEmailJob() override;
+
+ // Result properties
+
+ /// An email was sent to the given address.
+ const Sid& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Requests a validation token be sent to the given phone number for the
+/// purpose of resetting a user's password.
+/*!
+ * Proxies the Identity Service API ``validate/msisdn/requestToken``, but
+ * first checks that the given phone number **is** associated with an account
+ * on this homeserver. This API should be used to request
+ * validation tokens when authenticating for the
+ * `account/password` endpoint. This API's parameters and response are
+ * identical to that of the HS API |/register/msisdn/requestToken|_ except that
+ * `M_THREEPID_NOT_FOUND` may be returned if no account matching the
+ * given phone number could be found. The server may instead send an
+ * SMS message to the given address prompting the user to create an account.
+ * `M_THREEPID_IN_USE` may not be returned.
+ *
+ * .. |/register/msisdn/requestToken| replace:: ``/register/msisdn/requestToken``
+ *
+ * .. _/register/msisdn/requestToken:
+ * #post-matrix-client-r0-register-email-requesttoken
+ */
+class RequestTokenToResetPasswordMSISDNJob : public BaseJob
+{
+public:
+ /*! Requests a validation token be sent to the given phone number for the
+ * purpose of resetting a user's password. \param clientSecret A unique
+ * string generated by the client, and used to identify the validation
+ * attempt. It must be a string consisting of the characters
+ * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
+ * must not be empty.
+ * \param country
+ * The two-letter uppercase ISO country code that the number in
+ * ``phone_number`` should be parsed as if it were dialled from.
+ * \param phoneNumber
+ * The phone number to validate.
+ * \param sendAttempt
+ * The server will only send an SMS if the ``send_attempt`` is a
+ * number greater than the most recent one which it has seen,
+ * scoped to that ``country`` + ``phone_number`` + ``client_secret``
+ * triple. This is to avoid repeatedly sending the same SMS in
+ * the case of request retries between the POSTing user and the
+ * identity server. The client should increment this value if
+ * they desire a new SMS (e.g. a reminder) to be sent.
+ * \param idServer
+ * The hostname of the identity server to communicate with. May
+ * optionally include a port.
+ * \param nextLink
+ * Optional. When the validation is completed, the identity
+ * server will redirect the user to this URL.
+ */
+ explicit RequestTokenToResetPasswordMSISDNJob(const QString& clientSecret,
+ const QString& country,
+ const QString& phoneNumber,
+ int sendAttempt,
+ const QString& idServer,
+ const QString& nextLink = {});
+
+ ~RequestTokenToResetPasswordMSISDNJob() override;
+
+ // Result properties
+
+ /// An SMS message was sent to the given phone number.
+ const Sid& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Deactivate a user's account.
+/*!
+ * Deactivate the user's account, removing all ability for the user to
+ * login again.
+ *
+ * This API endpoint uses the `User-Interactive Authentication API`_.
+ *
+ * An access token should be submitted to this endpoint if the client has
+ * an active session.
+ *
+ * The homeserver may change the flows available depending on whether a
+ * valid access token is provided.
+ */
+class DeactivateAccountJob : public BaseJob
+{
+public:
+ /*! Deactivate a user's account.
+ * \param auth
+ * Additional authentication information for the user-interactive
+ * authentication API.
+ */
+ explicit DeactivateAccountJob(
+ const Omittable<AuthenticationData>& auth = none);
+};
+
+/// Checks to see if a username is available on the server.
+/*!
+ * Checks to see if a username is available, and valid, for the server.
+ *
+ * The server should check to ensure that, at the time of the request, the
+ * username requested is available for use. This includes verifying that an
+ * application service has not claimed the username and that the username
+ * fits the server's desired requirements (for example, a server could dictate
+ * that it does not permit usernames with underscores).
+ *
+ * Matrix clients may wish to use this API prior to attempting registration,
+ * however the clients must also be aware that using this API does not normally
+ * reserve the username. This can mean that the username becomes unavailable
+ * between checking its availability and attempting to register it.
+ */
+class CheckUsernameAvailabilityJob : public BaseJob
+{
+public:
+ /*! Checks to see if a username is available on the server.
+ * \param username
+ * The username to check the availability of.
+ */
+ explicit CheckUsernameAvailabilityJob(const QString& username);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * CheckUsernameAvailabilityJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& username);
+
+ ~CheckUsernameAvailabilityJob() override;
+
+ // Result properties
+
+ /// A flag to indicate that the username is available. This should always
+ /// be ``true`` when the server replies with 200 OK.
+ Omittable<bool> available() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- /// Changes a user's password.
- ///
- /// Changes the password for an account on this homeserver.
- ///
- /// This API endpoint uses the `User-Interactive Authentication API`_.
- ///
- /// An access token should be submitted to this endpoint if the client has
- /// an active session.
- ///
- /// The homeserver may change the flows available depending on whether a
- /// valid access token is provided.
- class ChangePasswordJob : public BaseJob
- {
- public:
- /*! Changes a user's password.
- * \param newPassword
- * The new password for the account.
- * \param auth
- * Additional authentication information for the user-interactive
- * authentication API.
- */
- explicit ChangePasswordJob(
- const QString& newPassword,
- const Omittable<AuthenticationData>& auth = none);
- };
-
- /// Requests a validation token be sent to the given email address for the
- /// purpose of resetting a user's password
- ///
- /// Proxies the Identity Service API ``validate/email/requestToken``, but
- /// first checks that the given email address **is** associated with an
- /// account on this homeserver. This API should be used to request
- /// validation tokens when authenticating for the
- /// `account/password` endpoint. This API's parameters and response are
- /// identical to that of the HS API |/register/email/requestToken|_ except
- /// that `M_THREEPID_NOT_FOUND` may be returned if no account matching the
- /// given email address could be found. The server may instead send an
- /// email to the given address prompting the user to create an account.
- /// `M_THREEPID_IN_USE` may not be returned.
- ///
- /// .. |/register/email/requestToken| replace::
- /// ``/register/email/requestToken``
- ///
- /// .. _/register/email/requestToken:
- /// #post-matrix-client-r0-register-email-requesttoken
- class RequestTokenToResetPasswordEmailJob : public BaseJob
- {
- public:
- /*! Requests a validation token be sent to the given email address for the purpose of resetting a user's password
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the
- * characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- * it must not be empty. \param email The email address to validate.
- * \param sendAttempt
- * The server will only send an email if the ``send_attempt``
- * is a number greater than the most recent one which it has seen,
- * scoped to that ``email`` + ``client_secret`` pair. This is to
- * avoid repeatedly sending the same email in the case of request
- * retries between the POSTing user and the identity server.
- * The client should increment this value if they desire a new
- * email (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
- */
- explicit RequestTokenToResetPasswordEmailJob(
- const QString& clientSecret, const QString& email,
- int sendAttempt, const QString& idServer,
- const QString& nextLink = {});
- ~RequestTokenToResetPasswordEmailJob() override;
-
- // Result properties
-
- /// An email was sent to the given address.
- const Sid& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Requests a validation token be sent to the given phone number for the
- /// purpose of resetting a user's password.
- ///
- /// Proxies the Identity Service API ``validate/msisdn/requestToken``, but
- /// first checks that the given phone number **is** associated with an
- /// account on this homeserver. This API should be used to request
- /// validation tokens when authenticating for the
- /// `account/password` endpoint. This API's parameters and response are
- /// identical to that of the HS API |/register/msisdn/requestToken|_ except
- /// that `M_THREEPID_NOT_FOUND` may be returned if no account matching the
- /// given phone number could be found. The server may instead send an
- /// SMS message to the given address prompting the user to create an
- /// account. `M_THREEPID_IN_USE` may not be returned.
- ///
- /// .. |/register/msisdn/requestToken| replace::
- /// ``/register/msisdn/requestToken``
- ///
- /// .. _/register/msisdn/requestToken:
- /// #post-matrix-client-r0-register-email-requesttoken
- class RequestTokenToResetPasswordMSISDNJob : public BaseJob
- {
- public:
- /*! Requests a validation token be sent to the given phone number for the purpose of resetting a user's password.
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the
- * characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- * it must not be empty. \param country The two-letter uppercase ISO
- * country code that the number in
- * ``phone_number`` should be parsed as if it were dialled from.
- * \param phoneNumber
- * The phone number to validate.
- * \param sendAttempt
- * The server will only send an SMS if the ``send_attempt`` is a
- * number greater than the most recent one which it has seen,
- * scoped to that ``country`` + ``phone_number`` + ``client_secret``
- * triple. This is to avoid repeatedly sending the same SMS in
- * the case of request retries between the POSTing user and the
- * identity server. The client should increment this value if
- * they desire a new SMS (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
- */
- explicit RequestTokenToResetPasswordMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt,
- const QString& idServer, const QString& nextLink = {});
- ~RequestTokenToResetPasswordMSISDNJob() override;
-
- // Result properties
-
- /// An SMS message was sent to the given phone number.
- const Sid& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Deactivate a user's account.
- ///
- /// Deactivate the user's account, removing all ability for the user to
- /// login again.
- ///
- /// This API endpoint uses the `User-Interactive Authentication API`_.
- ///
- /// An access token should be submitted to this endpoint if the client has
- /// an active session.
- ///
- /// The homeserver may change the flows available depending on whether a
- /// valid access token is provided.
- class DeactivateAccountJob : public BaseJob
- {
- public:
- /*! Deactivate a user's account.
- * \param auth
- * Additional authentication information for the user-interactive
- * authentication API.
- */
- explicit DeactivateAccountJob(
- const Omittable<AuthenticationData>& auth = none);
- };
-
- /// Checks to see if a username is available on the server.
- ///
- /// Checks to see if a username is available, and valid, for the server.
- ///
- /// The server should check to ensure that, at the time of the request, the
- /// username requested is available for use. This includes verifying that an
- /// application service has not claimed the username and that the username
- /// fits the server's desired requirements (for example, a server could
- /// dictate that it does not permit usernames with underscores).
- ///
- /// Matrix clients may wish to use this API prior to attempting
- /// registration, however the clients must also be aware that using this API
- /// does not normally reserve the username. This can mean that the username
- /// becomes unavailable between checking its availability and attempting to
- /// register it.
- class CheckUsernameAvailabilityJob : public BaseJob
- {
- public:
- /*! Checks to see if a username is available on the server.
- * \param username
- * The username to check the availability of.
- */
- explicit CheckUsernameAvailabilityJob(const QString& username);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * CheckUsernameAvailabilityJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& username);
-
- ~CheckUsernameAvailabilityJob() override;
-
- // Result properties
-
- /// A flag to indicate that the username is available. This should
- /// always be ``true`` when the server replies with 200 OK.
- Omittable<bool> available() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/report_content.cpp b/lib/csapi/report_content.cpp
index f7b74834..eb62cd12 100644
--- a/lib/csapi/report_content.cpp
+++ b/lib/csapi/report_content.cpp
@@ -14,9 +14,8 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
static const auto ReportContentJobName = QStringLiteral("ReportContentJob");
-ReportContentJob::ReportContentJob(const QString& roomId,
- const QString& eventId, int score,
- const QString& reason)
+ReportContentJob::ReportContentJob(const QString& roomId, const QString& eventId,
+ int score, const QString& reason)
: BaseJob(HttpVerb::Post, ReportContentJobName,
basePath % "/rooms/" % roomId % "/report/" % eventId)
{
diff --git a/lib/csapi/report_content.h b/lib/csapi/report_content.h
index aca5b30b..c545d800 100644
--- a/lib/csapi/report_content.h
+++ b/lib/csapi/report_content.h
@@ -4,32 +4,36 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
+namespace QMatrixClient
+{
-namespace QMatrixClient {
- // Operations
+// Operations
+
+/// Reports an event as inappropriate.
+/*!
+ * Reports an event as inappropriate to the server, which may then notify
+ * the appropriate people.
+ */
+class ReportContentJob : public BaseJob
+{
+public:
+ /*! Reports an event as inappropriate.
+ * \param roomId
+ * The room in which the event being reported is located.
+ * \param eventId
+ * The event to report.
+ * \param score
+ * The score to rate this content as where -100 is most offensive
+ * and 0 is inoffensive.
+ * \param reason
+ * The reason the content is being reported. May be blank.
+ */
+ explicit ReportContentJob(const QString& roomId, const QString& eventId,
+ int score, const QString& reason);
+};
- /// Reports an event as inappropriate.
- ///
- /// Reports an event as inappropriate to the server, which may then notify
- /// the appropriate people.
- class ReportContentJob : public BaseJob
- {
- public:
- /*! Reports an event as inappropriate.
- * \param roomId
- * The room in which the event being reported is located.
- * \param eventId
- * The event to report.
- * \param score
- * The score to rate this content as where -100 is most offensive
- * and 0 is inoffensive.
- * \param reason
- * The reason the content is being reported. May be blank.
- */
- explicit ReportContentJob(const QString& roomId, const QString& eventId,
- int score, const QString& reason);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/room_send.cpp b/lib/csapi/room_send.cpp
index 2bf42522..a29dd99a 100644
--- a/lib/csapi/room_send.cpp
+++ b/lib/csapi/room_send.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class SendMessageJob::Private
{
- public:
+public:
QString eventId;
};
@@ -23,9 +23,8 @@ static const auto SendMessageJobName = QStringLiteral("SendMessageJob");
SendMessageJob::SendMessageJob(const QString& roomId, const QString& eventType,
const QString& txnId, const QJsonObject& body)
: BaseJob(HttpVerb::Put, SendMessageJobName,
- basePath % "/rooms/" % roomId % "/send/" % eventType % "/"
- % txnId),
- d(new Private)
+ basePath % "/rooms/" % roomId % "/send/" % eventType % "/" % txnId)
+ , d(new Private)
{
setRequestData(Data(toJson(body)));
}
@@ -38,5 +37,6 @@ BaseJob::Status SendMessageJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("event_id"_ls), d->eventId);
+
return Success;
}
diff --git a/lib/csapi/room_send.h b/lib/csapi/room_send.h
index 38e246e1..aa2efd79 100644
--- a/lib/csapi/room_send.h
+++ b/lib/csapi/room_send.h
@@ -8,54 +8,58 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
-
- /// Send a message event to the given room.
- ///
- /// This endpoint is used to send a message event to a room. Message events
- /// allow access to historical events and pagination, making them suited
- /// for "once-off" activity in a room.
- ///
- /// The body of the request should be the content object of the event; the
- /// fields in this object will vary depending on the type of event. See
- /// `Room Events`_ for the m. event specification.
- class SendMessageJob : public BaseJob
- {
- public:
- /*! Send a message event to the given room.
- * \param roomId
- * The room to send the event to.
- * \param eventType
- * The type of event to send.
- * \param txnId
- * The transaction ID for this event. Clients should generate an
- * ID unique across requests with the same access token; it will be
- * used by the server to ensure idempotency of requests.
- * \param body
- * This endpoint is used to send a message event to a room. Message
- * events allow access to historical events and pagination, making them
- * suited for "once-off" activity in a room.
- *
- * The body of the request should be the content object of the event;
- * the fields in this object will vary depending on the type of event.
- * See `Room Events`_ for the m. event specification.
- */
- explicit SendMessageJob(const QString& roomId, const QString& eventType,
- const QString& txnId,
- const QJsonObject& body = {});
- ~SendMessageJob() override;
-
- // Result properties
-
- /// A unique identifier for the event.
- const QString& eventId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Send a message event to the given room.
+/*!
+ * This endpoint is used to send a message event to a room. Message events
+ * allow access to historical events and pagination, making them suited
+ * for "once-off" activity in a room.
+ *
+ * The body of the request should be the content object of the event; the
+ * fields in this object will vary depending on the type of event. See
+ * `Room Events`_ for the m. event specification.
+ */
+class SendMessageJob : public BaseJob
+{
+public:
+ /*! Send a message event to the given room.
+ * \param roomId
+ * The room to send the event to.
+ * \param eventType
+ * The type of event to send.
+ * \param txnId
+ * The transaction ID for this event. Clients should generate an
+ * ID unique across requests with the same access token; it will be
+ * used by the server to ensure idempotency of requests.
+ * \param body
+ * This endpoint is used to send a message event to a room. Message events
+ * allow access to historical events and pagination, making them suited
+ * for "once-off" activity in a room.
+ *
+ * The body of the request should be the content object of the event; the
+ * fields in this object will vary depending on the type of event. See
+ * `Room Events`_ for the m. event specification.
+ */
+ explicit SendMessageJob(const QString& roomId, const QString& eventType,
+ const QString& txnId, const QJsonObject& body = {});
+
+ ~SendMessageJob() override;
+
+ // Result properties
+
+ /// A unique identifier for the event.
+ const QString& eventId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/room_state.cpp b/lib/csapi/room_state.cpp
index 668a2931..ef4afcd0 100644
--- a/lib/csapi/room_state.cpp
+++ b/lib/csapi/room_state.cpp
@@ -14,12 +14,12 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class SetRoomStateWithKeyJob::Private
{
- public:
+public:
QString eventId;
};
static const auto SetRoomStateWithKeyJobName =
- QStringLiteral("SetRoomStateWithKeyJob");
+ QStringLiteral("SetRoomStateWithKeyJob");
SetRoomStateWithKeyJob::SetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
@@ -27,8 +27,8 @@ SetRoomStateWithKeyJob::SetRoomStateWithKeyJob(const QString& roomId,
const QJsonObject& body)
: BaseJob(HttpVerb::Put, SetRoomStateWithKeyJobName,
basePath % "/rooms/" % roomId % "/state/" % eventType % "/"
- % stateKey),
- d(new Private)
+ % stateKey)
+ , d(new Private)
{
setRequestData(Data(toJson(body)));
}
@@ -41,23 +41,23 @@ BaseJob::Status SetRoomStateWithKeyJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("event_id"_ls), d->eventId);
+
return Success;
}
class SetRoomStateJob::Private
{
- public:
+public:
QString eventId;
};
static const auto SetRoomStateJobName = QStringLiteral("SetRoomStateJob");
-SetRoomStateJob::SetRoomStateJob(const QString& roomId,
- const QString& eventType,
+SetRoomStateJob::SetRoomStateJob(const QString& roomId, const QString& eventType,
const QJsonObject& body)
: BaseJob(HttpVerb::Put, SetRoomStateJobName,
- basePath % "/rooms/" % roomId % "/state/" % eventType),
- d(new Private)
+ basePath % "/rooms/" % roomId % "/state/" % eventType)
+ , d(new Private)
{
setRequestData(Data(toJson(body)));
}
@@ -70,5 +70,6 @@ BaseJob::Status SetRoomStateJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("event_id"_ls), d->eventId);
+
return Success;
}
diff --git a/lib/csapi/room_state.h b/lib/csapi/room_state.h
index 07407af2..6ddd5594 100644
--- a/lib/csapi/room_state.h
+++ b/lib/csapi/room_state.h
@@ -8,120 +8,122 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
-
- /// Send a state event to the given room.
- ///
- /// State events can be sent using this endpoint. These events will be
- /// overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all
- /// match.
- ///
- /// Requests to this endpoint **cannot use transaction IDs**
- /// like other ``PUT`` paths because they cannot be differentiated from the
- /// ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
- ///
- /// The body of the request should be the content object of the event; the
- /// fields in this object will vary depending on the type of event. See
- /// `Room Events`_ for the ``m.`` event specification.
- class SetRoomStateWithKeyJob : public BaseJob
- {
- public:
- /*! Send a state event to the given room.
- * \param roomId
- * The room to set the state in
- * \param eventType
- * The type of event to send.
- * \param stateKey
- * The state_key for the state to send. Defaults to the empty string.
- * \param body
- * State events can be sent using this endpoint. These events will be
- * overwritten if ``<room id>``, ``<event type>`` and ``<state key>``
- * all match.
- *
- * Requests to this endpoint **cannot use transaction IDs**
- * like other ``PUT`` paths because they cannot be differentiated from
- * the
- * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
- *
- * The body of the request should be the content object of the event;
- * the fields in this object will vary depending on the type of event.
- * See `Room Events`_ for the ``m.`` event specification.
- */
- explicit SetRoomStateWithKeyJob(const QString& roomId,
- const QString& eventType,
- const QString& stateKey,
- const QJsonObject& body = {});
- ~SetRoomStateWithKeyJob() override;
-
- // Result properties
-
- /// A unique identifier for the event.
- const QString& eventId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Send a state event to the given room.
- ///
- /// State events can be sent using this endpoint. This endpoint is
- /// equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}`
- /// with an empty `stateKey`. Previous state events with matching
- /// `<roomId>` and `<eventType>`, and empty `<stateKey>`, will be
- /// overwritten.
- ///
- /// Requests to this endpoint **cannot use transaction IDs**
- /// like other ``PUT`` paths because they cannot be differentiated from the
- /// ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
- ///
- /// The body of the request should be the content object of the event; the
- /// fields in this object will vary depending on the type of event. See
- /// `Room Events`_ for the ``m.`` event specification.
- class SetRoomStateJob : public BaseJob
- {
- public:
- /*! Send a state event to the given room.
- * \param roomId
- * The room to set the state in
- * \param eventType
- * The type of event to send.
- * \param body
- * State events can be sent using this endpoint. This endpoint is
- * equivalent to calling
- * `/rooms/{roomId}/state/{eventType}/{stateKey}` with an empty
- * `stateKey`. Previous state events with matching
- * `<roomId>` and `<eventType>`, and empty `<stateKey>`, will be
- * overwritten.
- *
- * Requests to this endpoint **cannot use transaction IDs**
- * like other ``PUT`` paths because they cannot be differentiated from
- * the
- * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
- *
- * The body of the request should be the content object of the event;
- * the fields in this object will vary depending on the type of event.
- * See `Room Events`_ for the ``m.`` event specification.
- */
- explicit SetRoomStateJob(const QString& roomId,
- const QString& eventType,
- const QJsonObject& body = {});
- ~SetRoomStateJob() override;
-
- // Result properties
-
- /// A unique identifier for the event.
- const QString& eventId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Send a state event to the given room.
+/*!
+ * State events can be sent using this endpoint. These events will be
+ * overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all
+ * match.
+ *
+ * Requests to this endpoint **cannot use transaction IDs**
+ * like other ``PUT`` paths because they cannot be differentiated from the
+ * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
+ *
+ * The body of the request should be the content object of the event; the
+ * fields in this object will vary depending on the type of event. See
+ * `Room Events`_ for the ``m.`` event specification.
+ */
+class SetRoomStateWithKeyJob : public BaseJob
+{
+public:
+ /*! Send a state event to the given room.
+ * \param roomId
+ * The room to set the state in
+ * \param eventType
+ * The type of event to send.
+ * \param stateKey
+ * The state_key for the state to send. Defaults to the empty string.
+ * \param body
+ * State events can be sent using this endpoint. These events will be
+ * overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all
+ * match.
+ *
+ * Requests to this endpoint **cannot use transaction IDs**
+ * like other ``PUT`` paths because they cannot be differentiated from the
+ * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
+ *
+ * The body of the request should be the content object of the event; the
+ * fields in this object will vary depending on the type of event. See
+ * `Room Events`_ for the ``m.`` event specification.
+ */
+ explicit SetRoomStateWithKeyJob(const QString& roomId,
+ const QString& eventType,
+ const QString& stateKey,
+ const QJsonObject& body = {});
+
+ ~SetRoomStateWithKeyJob() override;
+
+ // Result properties
+
+ /// A unique identifier for the event.
+ const QString& eventId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Send a state event to the given room.
+/*!
+ * State events can be sent using this endpoint. This endpoint is
+ * equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}`
+ * with an empty `stateKey`. Previous state events with matching
+ * `<roomId>` and `<eventType>`, and empty `<stateKey>`, will be overwritten.
+ *
+ * Requests to this endpoint **cannot use transaction IDs**
+ * like other ``PUT`` paths because they cannot be differentiated from the
+ * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
+ *
+ * The body of the request should be the content object of the event; the
+ * fields in this object will vary depending on the type of event. See
+ * `Room Events`_ for the ``m.`` event specification.
+ */
+class SetRoomStateJob : public BaseJob
+{
+public:
+ /*! Send a state event to the given room.
+ * \param roomId
+ * The room to set the state in
+ * \param eventType
+ * The type of event to send.
+ * \param body
+ * State events can be sent using this endpoint. This endpoint is
+ * equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}`
+ * with an empty `stateKey`. Previous state events with matching
+ * `<roomId>` and `<eventType>`, and empty `<stateKey>`, will be
+ * overwritten.
+ *
+ * Requests to this endpoint **cannot use transaction IDs**
+ * like other ``PUT`` paths because they cannot be differentiated from the
+ * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
+ *
+ * The body of the request should be the content object of the event; the
+ * fields in this object will vary depending on the type of event. See
+ * `Room Events`_ for the ``m.`` event specification.
+ */
+ explicit SetRoomStateJob(const QString& roomId, const QString& eventType,
+ const QJsonObject& body = {});
+
+ ~SetRoomStateJob() override;
+
+ // Result properties
+
+ /// A unique identifier for the event.
+ const QString& eventId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/room_upgrades.cpp b/lib/csapi/room_upgrades.cpp
index b9f285e8..a72304d1 100644
--- a/lib/csapi/room_upgrades.cpp
+++ b/lib/csapi/room_upgrades.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class UpgradeRoomJob::Private
{
- public:
+public:
QString replacementRoom;
};
@@ -22,8 +22,8 @@ static const auto UpgradeRoomJobName = QStringLiteral("UpgradeRoomJob");
UpgradeRoomJob::UpgradeRoomJob(const QString& roomId, const QString& newVersion)
: BaseJob(HttpVerb::Post, UpgradeRoomJobName,
- basePath % "/rooms/" % roomId % "/upgrade"),
- d(new Private)
+ basePath % "/rooms/" % roomId % "/upgrade")
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("new_version"), newVersion);
@@ -41,8 +41,9 @@ BaseJob::Status UpgradeRoomJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("replacement_room"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'replacement_room' not found in the response" };
fromJson(json.value("replacement_room"_ls), d->replacementRoom);
+
return Success;
}
diff --git a/lib/csapi/room_upgrades.h b/lib/csapi/room_upgrades.h
index df30a562..94520aca 100644
--- a/lib/csapi/room_upgrades.h
+++ b/lib/csapi/room_upgrades.h
@@ -6,37 +6,39 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Upgrades a room to a new room version.
- ///
- /// Upgrades the given room to a particular room version, migrating as much
- /// data as possible over to the new room. See the `room_upgrades
- /// <#room-upgrades>`_ module for more information on what this entails.
- class UpgradeRoomJob : public BaseJob
- {
- public:
- /*! Upgrades a room to a new room version.
- * \param roomId
- * The ID of the room to upgrade.
- * \param newVersion
- * The new version for the room.
- */
- explicit UpgradeRoomJob(const QString& roomId,
- const QString& newVersion);
- ~UpgradeRoomJob() override;
-
- // Result properties
-
- /// The ID of the new room.
- const QString& replacementRoom() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Upgrades a room to a new room version.
+/*!
+ * Upgrades the given room to a particular room version.
+ */
+class UpgradeRoomJob : public BaseJob
+{
+public:
+ /*! Upgrades a room to a new room version.
+ * \param roomId
+ * The ID of the room to upgrade.
+ * \param newVersion
+ * The new version for the room.
+ */
+ explicit UpgradeRoomJob(const QString& roomId, const QString& newVersion);
+
+ ~UpgradeRoomJob() override;
+
+ // Result properties
+
+ /// The ID of the new room.
+ const QString& replacementRoom() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/rooms.cpp b/lib/csapi/rooms.cpp
index b9de276c..280e8d59 100644
--- a/lib/csapi/rooms.cpp
+++ b/lib/csapi/rooms.cpp
@@ -14,16 +14,16 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetOneRoomEventJob::Private
{
- public:
+public:
EventPtr data;
};
QUrl GetOneRoomEventJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/event/"
- % eventId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/rooms/"
+ % roomId % "/event/"
+ % eventId);
}
static const auto GetOneRoomEventJobName = QStringLiteral("GetOneRoomEventJob");
@@ -31,10 +31,9 @@ static const auto GetOneRoomEventJobName = QStringLiteral("GetOneRoomEventJob");
GetOneRoomEventJob::GetOneRoomEventJob(const QString& roomId,
const QString& eventId)
: BaseJob(HttpVerb::Get, GetOneRoomEventJobName,
- basePath % "/rooms/" % roomId % "/event/" % eventId),
- d(new Private)
-{
-}
+ basePath % "/rooms/" % roomId % "/event/" % eventId)
+ , d(new Private)
+{}
GetOneRoomEventJob::~GetOneRoomEventJob() = default;
@@ -52,42 +51,40 @@ QUrl GetRoomStateWithKeyJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/rooms/" % roomId % "/state/"
- % eventType % "/" % stateKey);
+ % eventType % "/" % stateKey);
}
static const auto GetRoomStateWithKeyJobName =
- QStringLiteral("GetRoomStateWithKeyJob");
+ QStringLiteral("GetRoomStateWithKeyJob");
GetRoomStateWithKeyJob::GetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
const QString& stateKey)
: BaseJob(HttpVerb::Get, GetRoomStateWithKeyJobName,
basePath % "/rooms/" % roomId % "/state/" % eventType % "/"
- % stateKey)
-{
-}
+ % stateKey)
+{}
QUrl GetRoomStateByTypeJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventType)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/state/"
- % eventType);
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/rooms/"
+ % roomId % "/state/"
+ % eventType);
}
static const auto GetRoomStateByTypeJobName =
- QStringLiteral("GetRoomStateByTypeJob");
+ QStringLiteral("GetRoomStateByTypeJob");
GetRoomStateByTypeJob::GetRoomStateByTypeJob(const QString& roomId,
const QString& eventType)
: BaseJob(HttpVerb::Get, GetRoomStateByTypeJobName,
basePath % "/rooms/" % roomId % "/state/" % eventType)
-{
-}
+{}
class GetRoomStateJob::Private
{
- public:
+public:
StateEvents data;
};
@@ -101,10 +98,9 @@ static const auto GetRoomStateJobName = QStringLiteral("GetRoomStateJob");
GetRoomStateJob::GetRoomStateJob(const QString& roomId)
: BaseJob(HttpVerb::Get, GetRoomStateJobName,
- basePath % "/rooms/" % roomId % "/state"),
- d(new Private)
-{
-}
+ basePath % "/rooms/" % roomId % "/state")
+ , d(new Private)
+{}
GetRoomStateJob::~GetRoomStateJob() = default;
@@ -118,7 +114,7 @@ BaseJob::Status GetRoomStateJob::parseJson(const QJsonDocument& data)
class GetMembersByRoomJob::Private
{
- public:
+public:
EventsArray<RoomMemberEvent> chunk;
};
@@ -139,12 +135,12 @@ QUrl GetMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& notMembership)
{
return BaseJob::makeRequestUrl(
- std::move(baseUrl), basePath % "/rooms/" % roomId % "/members",
- queryToGetMembersByRoom(at, membership, notMembership));
+ std::move(baseUrl), basePath % "/rooms/" % roomId % "/members",
+ queryToGetMembersByRoom(at, membership, notMembership));
}
static const auto GetMembersByRoomJobName =
- QStringLiteral("GetMembersByRoomJob");
+ QStringLiteral("GetMembersByRoomJob");
GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId,
const QString& at,
@@ -152,10 +148,9 @@ GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId,
const QString& notMembership)
: BaseJob(HttpVerb::Get, GetMembersByRoomJobName,
basePath % "/rooms/" % roomId % "/members",
- queryToGetMembersByRoom(at, membership, notMembership)),
- d(new Private)
-{
-}
+ queryToGetMembersByRoom(at, membership, notMembership))
+ , d(new Private)
+{}
GetMembersByRoomJob::~GetMembersByRoomJob() = default;
@@ -168,46 +163,48 @@ BaseJob::Status GetMembersByRoomJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("chunk"_ls), d->chunk);
+
return Success;
}
-namespace QMatrixClient {
- // Converters
-
- template <>
- struct JsonObjectConverter<GetJoinedMembersByRoomJob::RoomMember> {
- static void fillFrom(const QJsonObject& jo,
- GetJoinedMembersByRoomJob::RoomMember& result)
- {
- fromJson(jo.value("display_name"_ls), result.displayName);
- fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetJoinedMembersByRoomJob::RoomMember>
+{
+ static void fillFrom(const QJsonObject& jo,
+ GetJoinedMembersByRoomJob::RoomMember& result)
+ {
+ fromJson(jo.value("display_name"_ls), result.displayName);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
+ }
+};
+
} // namespace QMatrixClient
class GetJoinedMembersByRoomJob::Private
{
- public:
+public:
QHash<QString, RoomMember> joined;
};
QUrl GetJoinedMembersByRoomJob::makeRequestUrl(QUrl baseUrl,
const QString& roomId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId
- % "/joined_members");
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl), basePath % "/rooms/" % roomId % "/joined_members");
}
static const auto GetJoinedMembersByRoomJobName =
- QStringLiteral("GetJoinedMembersByRoomJob");
+ QStringLiteral("GetJoinedMembersByRoomJob");
GetJoinedMembersByRoomJob::GetJoinedMembersByRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Get, GetJoinedMembersByRoomJobName,
- basePath % "/rooms/" % roomId % "/joined_members"),
- d(new Private)
-{
-}
+ basePath % "/rooms/" % roomId % "/joined_members")
+ , d(new Private)
+{}
GetJoinedMembersByRoomJob::~GetJoinedMembersByRoomJob() = default;
@@ -221,5 +218,6 @@ BaseJob::Status GetJoinedMembersByRoomJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("joined"_ls), d->joined);
+
return Success;
}
diff --git a/lib/csapi/rooms.h b/lib/csapi/rooms.h
index 20bdd20e..29d7808e 100644
--- a/lib/csapi/rooms.h
+++ b/lib/csapi/rooms.h
@@ -4,261 +4,269 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "events/eventloader.h"
#include "events/roommemberevent.h"
-#include <QtCore/QHash>
+#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+#include <QtCore/QHash>
- /// Get a single event by event ID.
- ///
- /// Get a single event based on ``roomId/eventId``. You must have permission
- /// to retrieve this event e.g. by being a member in the room for this
- /// event.
- class GetOneRoomEventJob : public BaseJob
- {
- public:
- /*! Get a single event by event ID.
- * \param roomId
- * The ID of the room the event is in.
- * \param eventId
- * The event ID to get.
- */
- explicit GetOneRoomEventJob(const QString& roomId,
- const QString& eventId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetOneRoomEventJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& eventId);
-
- ~GetOneRoomEventJob() override;
-
- // Result properties
-
- /// The full event.
- EventPtr&& data();
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
- /// Get the state identified by the type and key.
- ///
- /// Looks up the contents of a state event in a room. If the user is
- /// joined to the room then the state is taken from the current
- /// state of the room. If the user has left the room then the state is
- /// taken from the state of the room when they left.
- class GetRoomStateWithKeyJob : public BaseJob
- {
- public:
- /*! Get the state identified by the type and key.
- * \param roomId
- * The room to look up the state in.
- * \param eventType
- * The type of state to look up.
- * \param stateKey
- * The key of the state to look up.
- */
- explicit GetRoomStateWithKeyJob(const QString& roomId,
- const QString& eventType,
- const QString& stateKey);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomStateWithKeyJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& eventType,
- const QString& stateKey);
- };
+// Operations
- /// Get the state identified by the type, with the empty state key.
- ///
- /// Looks up the contents of a state event in a room. If the user is
- /// joined to the room then the state is taken from the current
- /// state of the room. If the user has left the room then the state is
- /// taken from the state of the room when they left.
- ///
- /// This looks up the state event with the empty state key.
- class GetRoomStateByTypeJob : public BaseJob
- {
- public:
- /*! Get the state identified by the type, with the empty state key.
- * \param roomId
- * The room to look up the state in.
- * \param eventType
- * The type of state to look up.
- */
- explicit GetRoomStateByTypeJob(const QString& roomId,
- const QString& eventType);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomStateByTypeJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+/// Get a single event by event ID.
+/*!
+ * Get a single event based on ``roomId/eventId``. You must have permission to
+ * retrieve this event e.g. by being a member in the room for this event.
+ */
+class GetOneRoomEventJob : public BaseJob
+{
+public:
+ /*! Get a single event by event ID.
+ * \param roomId
+ * The ID of the room the event is in.
+ * \param eventId
+ * The event ID to get.
+ */
+ explicit GetOneRoomEventJob(const QString& roomId, const QString& eventId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetOneRoomEventJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+ const QString& eventId);
+
+ ~GetOneRoomEventJob() override;
+
+ // Result properties
+
+ /// The full event.
+ EventPtr&& data();
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Get the state identified by the type and key.
+/*!
+ * Looks up the contents of a state event in a room. If the user is
+ * joined to the room then the state is taken from the current
+ * state of the room. If the user has left the room then the state is
+ * taken from the state of the room when they left.
+ */
+class GetRoomStateWithKeyJob : public BaseJob
+{
+public:
+ /*! Get the state identified by the type and key.
+ * \param roomId
+ * The room to look up the state in.
+ * \param eventType
+ * The type of state to look up.
+ * \param stateKey
+ * The key of the state to look up.
+ */
+ explicit GetRoomStateWithKeyJob(const QString& roomId,
+ const QString& eventType,
+ const QString& stateKey);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomStateWithKeyJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+ const QString& eventType,
+ const QString& stateKey);
+};
+
+/// Get the state identified by the type, with the empty state key.
+/*!
+ * Looks up the contents of a state event in a room. If the user is
+ * joined to the room then the state is taken from the current
+ * state of the room. If the user has left the room then the state is
+ * taken from the state of the room when they left.
+ *
+ * This looks up the state event with the empty state key.
+ */
+class GetRoomStateByTypeJob : public BaseJob
+{
+public:
+ /*! Get the state identified by the type, with the empty state key.
+ * \param roomId
+ * The room to look up the state in.
+ * \param eventType
+ * The type of state to look up.
+ */
+ explicit GetRoomStateByTypeJob(const QString& roomId,
const QString& eventType);
- };
- /// Get all state events in the current state of a room.
- ///
- /// Get the state events for the current state of a room.
- class GetRoomStateJob : public BaseJob
- {
- public:
- /*! Get all state events in the current state of a room.
- * \param roomId
- * The room to look up the state for.
- */
- explicit GetRoomStateJob(const QString& roomId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomStateJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
-
- ~GetRoomStateJob() override;
-
- // Result properties
-
- /// If the user is a member of the room this will be the
- /// current state of the room as a list of events. If the user
- /// has left the room then this will be the state of the room
- /// when they left as a list of events.
- StateEvents&& data();
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomStateByTypeJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+ const QString& eventType);
+};
+
+/// Get all state events in the current state of a room.
+/*!
+ * Get the state events for the current state of a room.
+ */
+class GetRoomStateJob : public BaseJob
+{
+public:
+ /*! Get all state events in the current state of a room.
+ * \param roomId
+ * The room to look up the state for.
+ */
+ explicit GetRoomStateJob(const QString& roomId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomStateJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+
+ ~GetRoomStateJob() override;
+
+ // Result properties
+
+ /// If the user is a member of the room this will be the
+ /// current state of the room as a list of events. If the user
+ /// has left the room then this will be the state of the room
+ /// when they left as a list of events.
+ StateEvents&& data();
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Get the m.room.member events for the room.
+/*!
+ * Get the list of members for this room.
+ */
+class GetMembersByRoomJob : public BaseJob
+{
+public:
+ /*! Get the m.room.member events for the room.
+ * \param roomId
+ * The room to get the member events for.
+ * \param at
+ * The token defining the timeline position as-of which to return
+ * the list of members. This token can be obtained from a batch token
+ * returned for each room by the sync API, or from
+ * a ``start``/``end`` token returned by a ``/messages`` request.
+ * \param membership
+ * Only return users with the specified membership
+ * \param notMembership
+ * Only return users with membership state other than specified
+ */
+ explicit GetMembersByRoomJob(const QString& roomId, const QString& at = {},
+ const QString& membership = {},
+ const QString& notMembership = {});
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetMembersByRoomJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
+ const QString& at = {},
+ const QString& membership = {},
+ const QString& notMembership = {});
+
+ ~GetMembersByRoomJob() override;
+
+ // Result properties
- /// Get the m.room.member events for the room.
- ///
/// Get the list of members for this room.
- class GetMembersByRoomJob : public BaseJob
- {
- public:
- /*! Get the m.room.member events for the room.
- * \param roomId
- * The room to get the member events for.
- * \param at
- * The token defining the timeline position as-of which to return
- * the list of members. This token can be obtained from a batch token
- * returned for each room by the sync API, or from
- * a ``start``/``end`` token returned by a ``/messages`` request.
- * \param membership
- * Only return users with the specified membership
- * \param notMembership
- * Only return users with membership state other than specified
- */
- explicit GetMembersByRoomJob(const QString& roomId,
- const QString& at = {},
- const QString& membership = {},
- const QString& notMembership = {});
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetMembersByRoomJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& at = {},
- const QString& membership = {},
- const QString& notMembership = {});
-
- ~GetMembersByRoomJob() override;
-
- // Result properties
-
- /// Get the list of members for this room.
- EventsArray<RoomMemberEvent>&& chunk();
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ EventsArray<RoomMemberEvent>&& chunk();
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Gets the list of currently joined users and their profile data.
+/*!
+ * This API returns a map of MXIDs to member info objects for members of the
+ * room. The current user must be in the room for it to work, unless it is an
+ * Application Service in which case any of the AS's users must be in the room.
+ * This API is primarily for Application Services and should be faster to
+ * respond than ``/members`` as it can be implemented more efficiently on the
+ * server.
+ */
+class GetJoinedMembersByRoomJob : public BaseJob
+{
+public:
+ // Inner data structures
- /// Gets the list of currently joined users and their profile data.
- ///
/// This API returns a map of MXIDs to member info objects for members of
/// the room. The current user must be in the room for it to work, unless it
/// is an Application Service in which case any of the AS's users must be in
/// the room. This API is primarily for Application Services and should be
/// faster to respond than ``/members`` as it can be implemented more
/// efficiently on the server.
- class GetJoinedMembersByRoomJob : public BaseJob
+ struct RoomMember
{
- public:
- // Inner data structures
-
- /// This API returns a map of MXIDs to member info objects for members
- /// of the room. The current user must be in the room for it to work,
- /// unless it is an Application Service in which case any of the AS's
- /// users must be in the room. This API is primarily for Application
- /// Services and should be faster to respond than ``/members`` as it can
- /// be implemented more efficiently on the server.
- struct RoomMember {
- /// 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;
- };
-
- // Construction/destruction
-
- /*! Gets the list of currently joined users and their profile data.
- * \param roomId
- * The room to get the members of.
- */
- explicit GetJoinedMembersByRoomJob(const QString& roomId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetJoinedMembersByRoomJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
-
- ~GetJoinedMembersByRoomJob() override;
-
- // Result properties
-
- /// A map from user ID to a RoomMember object.
- const QHash<QString, RoomMember>& joined() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// 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;
};
+
+ // Construction/destruction
+
+ /*! Gets the list of currently joined users and their profile data.
+ * \param roomId
+ * The room to get the members of.
+ */
+ explicit GetJoinedMembersByRoomJob(const QString& roomId);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetJoinedMembersByRoomJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+
+ ~GetJoinedMembersByRoomJob() override;
+
+ // Result properties
+
+ /// A map from user ID to a RoomMember object.
+ const QHash<QString, RoomMember>& joined() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/search.cpp b/lib/csapi/search.cpp
index 22aaf616..ee1fa70c 100644
--- a/lib/csapi/search.cpp
+++ b/lib/csapi/search.cpp
@@ -12,126 +12,143 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<SearchJob::IncludeEventContext> {
- static void dumpTo(QJsonObject& jo,
- const SearchJob::IncludeEventContext& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("before_limit"),
- pod.beforeLimit);
- addParam<IfNotEmpty>(jo, QStringLiteral("after_limit"),
- pod.afterLimit);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_profile"),
- pod.includeProfile);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::Group> {
- static void dumpTo(QJsonObject& jo, const SearchJob::Group& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::Groupings> {
- static void dumpTo(QJsonObject& jo, const SearchJob::Groupings& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("group_by"), pod.groupBy);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::RoomEventsCriteria> {
- static void dumpTo(QJsonObject& jo,
- const SearchJob::RoomEventsCriteria& pod)
- {
- addParam<>(jo, QStringLiteral("search_term"), pod.searchTerm);
- addParam<IfNotEmpty>(jo, QStringLiteral("keys"), pod.keys);
- addParam<IfNotEmpty>(jo, QStringLiteral("filter"), pod.filter);
- addParam<IfNotEmpty>(jo, QStringLiteral("order_by"), pod.orderBy);
- addParam<IfNotEmpty>(jo, QStringLiteral("event_context"),
- pod.eventContext);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_state"),
- pod.includeState);
- addParam<IfNotEmpty>(jo, QStringLiteral("groupings"),
- pod.groupings);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::Categories> {
- static void dumpTo(QJsonObject& jo, const SearchJob::Categories& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("room_events"),
- pod.roomEvents);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::UserProfile> {
- static void fillFrom(const QJsonObject& jo,
- SearchJob::UserProfile& result)
- {
- fromJson(jo.value("displayname"_ls), result.displayname);
- fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::EventContext> {
- static void fillFrom(const QJsonObject& jo,
- SearchJob::EventContext& result)
- {
- fromJson(jo.value("start"_ls), result.begin);
- fromJson(jo.value("end"_ls), result.end);
- fromJson(jo.value("profile_info"_ls), result.profileInfo);
- fromJson(jo.value("events_before"_ls), result.eventsBefore);
- fromJson(jo.value("events_after"_ls), result.eventsAfter);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::Result> {
- static void fillFrom(const QJsonObject& jo, SearchJob::Result& result)
- {
- fromJson(jo.value("rank"_ls), result.rank);
- fromJson(jo.value("result"_ls), result.result);
- fromJson(jo.value("context"_ls), result.context);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::GroupValue> {
- static void fillFrom(const QJsonObject& jo,
- SearchJob::GroupValue& result)
- {
- fromJson(jo.value("next_batch"_ls), result.nextBatch);
- fromJson(jo.value("order"_ls), result.order);
- fromJson(jo.value("results"_ls), result.results);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::ResultRoomEvents> {
- static void fillFrom(const QJsonObject& jo,
- SearchJob::ResultRoomEvents& result)
- {
- fromJson(jo.value("count"_ls), result.count);
- fromJson(jo.value("highlights"_ls), result.highlights);
- fromJson(jo.value("results"_ls), result.results);
- fromJson(jo.value("state"_ls), result.state);
- fromJson(jo.value("groups"_ls), result.groups);
- fromJson(jo.value("next_batch"_ls), result.nextBatch);
- }
- };
-
- template <> struct JsonObjectConverter<SearchJob::ResultCategories> {
- static void fillFrom(const QJsonObject& jo,
- SearchJob::ResultCategories& result)
- {
- fromJson(jo.value("room_events"_ls), result.roomEvents);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<SearchJob::IncludeEventContext>
+{
+ static void dumpTo(QJsonObject& jo,
+ const SearchJob::IncludeEventContext& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("before_limit"),
+ pod.beforeLimit);
+ addParam<IfNotEmpty>(jo, QStringLiteral("after_limit"), pod.afterLimit);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_profile"),
+ pod.includeProfile);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::Group>
+{
+ static void dumpTo(QJsonObject& jo, const SearchJob::Group& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::Groupings>
+{
+ static void dumpTo(QJsonObject& jo, const SearchJob::Groupings& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("group_by"), pod.groupBy);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::RoomEventsCriteria>
+{
+ static void dumpTo(QJsonObject& jo, const SearchJob::RoomEventsCriteria& pod)
+ {
+ addParam<>(jo, QStringLiteral("search_term"), pod.searchTerm);
+ addParam<IfNotEmpty>(jo, QStringLiteral("keys"), pod.keys);
+ addParam<IfNotEmpty>(jo, QStringLiteral("filter"), pod.filter);
+ addParam<IfNotEmpty>(jo, QStringLiteral("order_by"), pod.orderBy);
+ addParam<IfNotEmpty>(jo, QStringLiteral("event_context"),
+ pod.eventContext);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_state"),
+ pod.includeState);
+ addParam<IfNotEmpty>(jo, QStringLiteral("groupings"), pod.groupings);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::Categories>
+{
+ static void dumpTo(QJsonObject& jo, const SearchJob::Categories& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("room_events"), pod.roomEvents);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::UserProfile>
+{
+ static void fillFrom(const QJsonObject& jo, SearchJob::UserProfile& result)
+ {
+ fromJson(jo.value("displayname"_ls), result.displayname);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::EventContext>
+{
+ static void fillFrom(const QJsonObject& jo, SearchJob::EventContext& result)
+ {
+ fromJson(jo.value("start"_ls), result.begin);
+ fromJson(jo.value("end"_ls), result.end);
+ fromJson(jo.value("profile_info"_ls), result.profileInfo);
+ fromJson(jo.value("events_before"_ls), result.eventsBefore);
+ fromJson(jo.value("events_after"_ls), result.eventsAfter);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::Result>
+{
+ static void fillFrom(const QJsonObject& jo, SearchJob::Result& result)
+ {
+ fromJson(jo.value("rank"_ls), result.rank);
+ fromJson(jo.value("result"_ls), result.result);
+ fromJson(jo.value("context"_ls), result.context);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::GroupValue>
+{
+ static void fillFrom(const QJsonObject& jo, SearchJob::GroupValue& result)
+ {
+ fromJson(jo.value("next_batch"_ls), result.nextBatch);
+ fromJson(jo.value("order"_ls), result.order);
+ fromJson(jo.value("results"_ls), result.results);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::ResultRoomEvents>
+{
+ static void fillFrom(const QJsonObject& jo,
+ SearchJob::ResultRoomEvents& result)
+ {
+ fromJson(jo.value("count"_ls), result.count);
+ fromJson(jo.value("highlights"_ls), result.highlights);
+ fromJson(jo.value("results"_ls), result.results);
+ fromJson(jo.value("state"_ls), result.state);
+ fromJson(jo.value("groups"_ls), result.groups);
+ fromJson(jo.value("next_batch"_ls), result.nextBatch);
+ }
+};
+
+template <>
+struct JsonObjectConverter<SearchJob::ResultCategories>
+{
+ static void fillFrom(const QJsonObject& jo,
+ SearchJob::ResultCategories& result)
+ {
+ fromJson(jo.value("room_events"_ls), result.roomEvents);
+ }
+};
+
} // namespace QMatrixClient
class SearchJob::Private
{
- public:
+public:
ResultCategories searchCategories;
};
@@ -147,8 +164,8 @@ static const auto SearchJobName = QStringLiteral("SearchJob");
SearchJob::SearchJob(const Categories& searchCategories,
const QString& nextBatch)
: BaseJob(HttpVerb::Post, SearchJobName, basePath % "/search",
- queryToSearch(nextBatch)),
- d(new Private)
+ queryToSearch(nextBatch))
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("search_categories"), searchCategories);
@@ -166,8 +183,9 @@ BaseJob::Status SearchJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("search_categories"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'search_categories' not found in the response" };
fromJson(json.value("search_categories"_ls), d->searchCategories);
+
return Success;
}
diff --git a/lib/csapi/search.h b/lib/csapi/search.h
index 41761030..f965a72a 100644
--- a/lib/csapi/search.h
+++ b/lib/csapi/search.h
@@ -4,193 +4,200 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/room_event_filter.h"
+
#include "events/eventloader.h"
+#include "jobs/basejob.h"
+
#include <QtCore/QHash>
#include <QtCore/QVector>
+
#include <unordered_map>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
- /// Perform a server-side search.
- ///
- /// Performs a full text search across different categories.
- class SearchJob : public BaseJob
+// Operations
+
+/// Perform a server-side search.
+/*!
+ * Performs a full text search across different categories.
+ */
+class SearchJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// Configures whether any context for the eventsreturned are included in
+ /// the response.
+ struct IncludeEventContext
{
- public:
- // Inner data structures
-
- /// Configures whether any context for the events
- /// returned are included in the response.
- struct IncludeEventContext {
- /// How many events before the result are
- /// returned. By default, this is ``5``.
- Omittable<int> beforeLimit;
- /// How many events after the result are
- /// returned. By default, this is ``5``.
- Omittable<int> afterLimit;
- /// Requests that the server returns the
- /// historic profile information for the users
- /// that sent the events that were returned.
- /// By default, this is ``false``.
- Omittable<bool> includeProfile;
- };
-
- /// Configuration for group.
- struct Group {
- /// Key that defines the group.
- QString key;
- };
-
- /// Requests that the server partitions the result set
- /// based on the provided list of keys.
- struct Groupings {
- /// List of groups to request.
- QVector<Group> groupBy;
- };
+ /// How many events before the result arereturned. By default, this is
+ /// ``5``.
+ Omittable<int> beforeLimit;
+ /// How many events after the result arereturned. By default, this is
+ /// ``5``.
+ Omittable<int> afterLimit;
+ /// Requests that the server returns thehistoric profile information for
+ /// the usersthat sent the events that were returned.By default, this is
+ /// ``false``.
+ Omittable<bool> includeProfile;
+ };
+ /// Configuration for group.
+ struct Group
+ {
+ /// Key that defines the group.
+ QString key;
+ };
+
+ /// Requests that the server partitions the result setbased on the provided
+ /// list of keys.
+ struct Groupings
+ {
+ /// List of groups to request.
+ QVector<Group> groupBy;
+ };
+
+ /// Mapping of category name to search criteria.
+ struct RoomEventsCriteria
+ {
+ /// The string to search events for
+ QString searchTerm;
+ /// The keys to search. Defaults to all.
+ QStringList keys;
+ /// This takes a `filter`_.
+ Omittable<RoomEventFilter> filter;
+ /// The order in which to search for results.By default, this is
+ /// ``"rank"``.
+ QString orderBy;
+ /// Configures whether any context for the eventsreturned are included
+ /// in the response.
+ Omittable<IncludeEventContext> eventContext;
+ /// Requests the server return the current state foreach room returned.
+ Omittable<bool> includeState;
+ /// Requests that the server partitions the result setbased on the
+ /// provided list of keys.
+ Omittable<Groupings> groupings;
+ };
+
+ /// Describes which categories to search in and their criteria.
+ struct Categories
+ {
/// Mapping of category name to search criteria.
- struct RoomEventsCriteria {
- /// The string to search events for
- QString searchTerm;
- /// The keys to search. Defaults to all.
- QStringList keys;
- /// This takes a `filter`_.
- Omittable<RoomEventFilter> filter;
- /// The order in which to search for results.
- /// By default, this is ``"rank"``.
- QString orderBy;
- /// Configures whether any context for the events
- /// returned are included in the response.
- Omittable<IncludeEventContext> eventContext;
- /// Requests the server return the current state for
- /// each room returned.
- Omittable<bool> includeState;
- /// Requests that the server partitions the result set
- /// based on the provided list of keys.
- Omittable<Groupings> groupings;
- };
-
- /// Describes which categories to search in and their criteria.
- struct Categories {
- /// Mapping of category name to search criteria.
- Omittable<RoomEventsCriteria> roomEvents;
- };
+ Omittable<RoomEventsCriteria> roomEvents;
+ };
+ /// Performs a full text search across different categories.
+ struct UserProfile
+ {
+ /// Performs a full text search across different categories.
+ QString displayname;
/// Performs a full text search across different categories.
- struct UserProfile {
- /// Performs a full text search across different categories.
- QString displayname;
- /// Performs a full text search across different categories.
- QString avatarUrl;
- };
+ QString avatarUrl;
+ };
+
+ /// Context for result, if requested.
+ struct EventContext
+ {
+ /// Pagination token for the start of the chunk
+ QString begin;
+ /// Pagination token for the end of the chunk
+ QString end;
+ /// The historic profile information of theusers that sent the events
+ /// returned.The ``string`` key is the user ID for whichthe profile
+ /// belongs to.
+ QHash<QString, UserProfile> profileInfo;
+ /// Events just before the result.
+ RoomEvents eventsBefore;
+ /// Events just after the result.
+ RoomEvents eventsAfter;
+ };
+ /// The result object.
+ struct Result
+ {
+ /// A number that describes how closely this result matches the search.
+ /// Higher is closer.
+ Omittable<double> rank;
+ /// The event that matched.
+ RoomEventPtr result;
/// Context for result, if requested.
- struct EventContext {
- /// Pagination token for the start of the chunk
- QString begin;
- /// Pagination token for the end of the chunk
- QString end;
- /// The historic profile information of the
- /// users that sent the events returned.
- ///
- /// The ``string`` key is the user ID for which
- /// the profile belongs to.
- QHash<QString, UserProfile> profileInfo;
- /// Events just before the result.
- RoomEvents eventsBefore;
- /// Events just after the result.
- RoomEvents eventsAfter;
- };
-
- /// The result object.
- struct Result {
- /// A number that describes how closely this result matches the
- /// search. Higher is closer.
- Omittable<double> rank;
- /// The event that matched.
- RoomEventPtr result;
- /// Context for result, if requested.
- Omittable<EventContext> context;
- };
-
- /// The results for a particular group value.
- struct GroupValue {
- /// Token that can be used to get the next batch
- /// of results in the group, by passing as the
- /// `next_batch` parameter to the next call. If
- /// this field is absent, there are no more
- /// results in this group.
- QString nextBatch;
- /// Key that can be used to order different
- /// groups.
- Omittable<int> order;
- /// Which results are in this group.
- QStringList results;
- };
+ Omittable<EventContext> context;
+ };
+
+ /// The results for a particular group value.
+ struct GroupValue
+ {
+ /// Token that can be used to get the next batchof results in the group,
+ /// by passing as the`next_batch` parameter to the next call. Ifthis
+ /// field is absent, there are no moreresults in this group.
+ QString nextBatch;
+ /// Key that can be used to order differentgroups.
+ Omittable<int> order;
+ /// Which results are in this group.
+ QStringList results;
+ };
+ /// Mapping of category name to search criteria.
+ struct ResultRoomEvents
+ {
+ /// An approximate count of the total number of results found.
+ Omittable<int> count;
+ /// List of words which should be highlighted, useful for stemming which
+ /// may change the query terms.
+ QStringList highlights;
+ /// List of results in the requested order.
+ std::vector<Result> results;
+ /// The current state for every room in the results.This is included if
+ /// the request had the``include_state`` key set with a value of
+ /// ``true``.The ``string`` key is the room ID for which the
+ /// ``StateEvent`` array belongs to.
+ std::unordered_map<QString, StateEvents> state;
+ /// Any groups that were requested.The outer ``string`` key is the group
+ /// key requested (eg: ``room_id``or ``sender``). The inner ``string``
+ /// key is the grouped value (eg: a room's ID or a user's ID).
+ QHash<QString, QHash<QString, GroupValue>> groups;
+ /// Token that can be used to get the next batch ofresults, by passing
+ /// as the `next_batch` parameter tothe next call. If this field is
+ /// absent, there are nomore results.
+ QString nextBatch;
+ };
+
+ /// Describes which categories to search in and their criteria.
+ struct ResultCategories
+ {
/// Mapping of category name to search criteria.
- struct ResultRoomEvents {
- /// An approximate count of the total number of results found.
- Omittable<int> count;
- /// List of words which should be highlighted, useful for stemming
- /// which may change the query terms.
- QStringList highlights;
- /// List of results in the requested order.
- std::vector<Result> results;
- /// The current state for every room in the results.
- /// This is included if the request had the
- /// ``include_state`` key set with a value of ``true``.
- ///
- /// The ``string`` key is the room ID for which the ``State
- /// Event`` array belongs to.
- std::unordered_map<QString, StateEvents> state;
- /// Any groups that were requested.
- ///
- /// The outer ``string`` key is the group key requested (eg:
- /// ``room_id`` or ``sender``). The inner ``string`` key is the
- /// grouped value (eg: a room's ID or a user's ID).
- QHash<QString, QHash<QString, GroupValue>> groups;
- /// Token that can be used to get the next batch of
- /// results, by passing as the `next_batch` parameter to
- /// the next call. If this field is absent, there are no
- /// more results.
- QString nextBatch;
- };
-
- /// Describes which categories to search in and their criteria.
- struct ResultCategories {
- /// Mapping of category name to search criteria.
- Omittable<ResultRoomEvents> roomEvents;
- };
-
- // Construction/destruction
-
- /*! Perform a server-side search.
- * \param searchCategories
- * Describes which categories to search in and their criteria.
- * \param nextBatch
- * The point to return events from. If given, this should be a
- * ``next_batch`` result from a previous call to this endpoint.
- */
- explicit SearchJob(const Categories& searchCategories,
- const QString& nextBatch = {});
- ~SearchJob() override;
-
- // Result properties
-
- /// Describes which categories to search in and their criteria.
- const ResultCategories& searchCategories() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ Omittable<ResultRoomEvents> roomEvents;
};
+
+ // Construction/destruction
+
+ /*! Perform a server-side search.
+ * \param searchCategories
+ * Describes which categories to search in and their criteria.
+ * \param nextBatch
+ * The point to return events from. If given, this should be a
+ * ``next_batch`` result from a previous call to this endpoint.
+ */
+ explicit SearchJob(const Categories& searchCategories,
+ const QString& nextBatch = {});
+
+ ~SearchJob() override;
+
+ // Result properties
+
+ /// Describes which categories to search in and their criteria.
+ const ResultCategories& searchCategories() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/sso_login_redirect.cpp b/lib/csapi/sso_login_redirect.cpp
index 92084d52..b1dc3674 100644
--- a/lib/csapi/sso_login_redirect.cpp
+++ b/lib/csapi/sso_login_redirect.cpp
@@ -32,5 +32,4 @@ RedirectToSSOJob::RedirectToSSOJob(const QString& redirectUrl)
: BaseJob(HttpVerb::Get, RedirectToSSOJobName,
basePath % "/login/sso/redirect",
queryToRedirectToSSO(redirectUrl), {}, false)
-{
-}
+{}
diff --git a/lib/csapi/sso_login_redirect.h b/lib/csapi/sso_login_redirect.h
index 2b0d3f65..af9e7780 100644
--- a/lib/csapi/sso_login_redirect.h
+++ b/lib/csapi/sso_login_redirect.h
@@ -6,31 +6,35 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
- /// Redirect the user's browser to the SSO interface.
- ///
- /// A web-based Matrix client should instruct the user's browser to
- /// navigate to this endpoint in order to log in via SSO.
- ///
- /// The server MUST respond with an HTTP redirect to the SSO interface.
- class RedirectToSSOJob : public BaseJob
- {
- public:
- /*! Redirect the user's browser to the SSO interface.
- * \param redirectUrl
- * URI to which the user will be redirected after the homeserver has
- * authenticated the user with SSO.
- */
- explicit RedirectToSSOJob(const QString& redirectUrl);
+// Operations
+
+/// Redirect the user's browser to the SSO interface.
+/*!
+ * A web-based Matrix client should instruct the user's browser to
+ * navigate to this endpoint in order to log in via SSO.
+ *
+ * The server MUST respond with an HTTP redirect to the SSO interface.
+ */
+class RedirectToSSOJob : public BaseJob
+{
+public:
+ /*! Redirect the user's browser to the SSO interface.
+ * \param redirectUrl
+ * URI to which the user will be redirected after the homeserver has
+ * authenticated the user with SSO.
+ */
+ explicit RedirectToSSOJob(const QString& redirectUrl);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * RedirectToSSOJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& redirectUrl);
+};
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * RedirectToSSOJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& redirectUrl);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/tags.cpp b/lib/csapi/tags.cpp
index 9f591447..13c933e5 100644
--- a/lib/csapi/tags.cpp
+++ b/lib/csapi/tags.cpp
@@ -12,40 +12,43 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<GetRoomTagsJob::Tag> {
- static void fillFrom(QJsonObject jo, GetRoomTagsJob::Tag& result)
- {
- fromJson(jo.take("order"_ls), result.order);
- fromJson(jo, result.additionalProperties);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<GetRoomTagsJob::Tag>
+{
+ static void fillFrom(QJsonObject jo, GetRoomTagsJob::Tag& result)
+ {
+ fromJson(jo.take("order"_ls), result.order);
+ fromJson(jo, result.additionalProperties);
+ }
+};
+
} // namespace QMatrixClient
class GetRoomTagsJob::Private
{
- public:
+public:
QHash<QString, Tag> tags;
};
QUrl GetRoomTagsJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& roomId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/user/" % userId % "/rooms/"
- % roomId % "/tags");
+ return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/user/"
+ % userId % "/rooms/"
+ % roomId % "/tags");
}
static const auto GetRoomTagsJobName = QStringLiteral("GetRoomTagsJob");
GetRoomTagsJob::GetRoomTagsJob(const QString& userId, const QString& roomId)
: BaseJob(HttpVerb::Get, GetRoomTagsJobName,
- basePath % "/user/" % userId % "/rooms/" % roomId % "/tags"),
- d(new Private)
-{
-}
+ basePath % "/user/" % userId % "/rooms/" % roomId % "/tags")
+ , d(new Private)
+{}
GetRoomTagsJob::~GetRoomTagsJob() = default;
@@ -58,6 +61,7 @@ BaseJob::Status GetRoomTagsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
fromJson(json.value("tags"_ls), d->tags);
+
return Success;
}
@@ -66,8 +70,7 @@ static const auto SetRoomTagJobName = QStringLiteral("SetRoomTagJob");
SetRoomTagJob::SetRoomTagJob(const QString& userId, const QString& roomId,
const QString& tag, Omittable<float> order)
: BaseJob(HttpVerb::Put, SetRoomTagJobName,
- basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/"
- % tag)
+ basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("order"), order);
@@ -79,7 +82,7 @@ QUrl DeleteRoomTagJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
basePath % "/user/" % userId % "/rooms/"
- % roomId % "/tags/" % tag);
+ % roomId % "/tags/" % tag);
}
static const auto DeleteRoomTagJobName = QStringLiteral("DeleteRoomTagJob");
@@ -87,7 +90,5 @@ static const auto DeleteRoomTagJobName = QStringLiteral("DeleteRoomTagJob");
DeleteRoomTagJob::DeleteRoomTagJob(const QString& userId, const QString& roomId,
const QString& tag)
: BaseJob(HttpVerb::Delete, DeleteRoomTagJobName,
- basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/"
- % tag)
-{
-}
+ basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag)
+{}
diff --git a/lib/csapi/tags.h b/lib/csapi/tags.h
index dc683ef7..dc20cd3d 100644
--- a/lib/csapi/tags.h
+++ b/lib/csapi/tags.h
@@ -4,115 +4,123 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QHash>
#include <QtCore/QVariant>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// List the tags for a room.
+/*!
+ * List the tags set by a user on a room.
+ */
+class GetRoomTagsJob : public BaseJob
+{
+public:
+ // Inner data structures
- /// List the tags for a room.
- ///
/// List the tags set by a user on a room.
- class GetRoomTagsJob : public BaseJob
+ struct Tag
{
- public:
- // Inner data structures
+ /// A number in a range ``[0,1]`` describing a relativeposition of the
+ /// room under the given tag.
+ Omittable<float> order;
/// List the tags set by a user on a room.
- struct Tag {
- /// A number in a range ``[0,1]`` describing a relative
- /// position of the room under the given tag.
- Omittable<float> order;
- /// List the tags set by a user on a room.
- QVariantHash additionalProperties;
- };
-
- // Construction/destruction
-
- /*! List the tags for a room.
- * \param userId
- * The id of the user to get tags for. The access token must be
- * authorized to make requests for this user ID.
- * \param roomId
- * The ID of the room to get tags for.
- */
- explicit GetRoomTagsJob(const QString& userId, const QString& roomId);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetRoomTagsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
- const QString& roomId);
-
- ~GetRoomTagsJob() override;
-
- // Result properties
+ QVariantHash additionalProperties;
+ };
- /// List the tags set by a user on a room.
- const QHash<QString, Tag>& tags() const;
+ // Construction/destruction
- protected:
- Status parseJson(const QJsonDocument& data) override;
+ /*! List the tags for a room.
+ * \param userId
+ * The id of the user to get tags for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param roomId
+ * The ID of the room to get tags for.
+ */
+ explicit GetRoomTagsJob(const QString& userId, const QString& roomId);
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetRoomTagsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
+ const QString& roomId);
- /// Add a tag to a room.
- ///
- /// Add a tag to the room.
- class SetRoomTagJob : public BaseJob
- {
- public:
- /*! Add a tag to a room.
- * \param userId
- * The id of the user to add a tag for. The access token must be
- * authorized to make requests for this user ID.
- * \param roomId
- * The ID of the room to add a tag to.
- * \param tag
- * The tag to add.
- * \param order
- * A number in a range ``[0,1]`` describing a relative
- * position of the room under the given tag.
- */
- explicit SetRoomTagJob(const QString& userId, const QString& roomId,
- const QString& tag,
- Omittable<float> order = none);
- };
+ ~GetRoomTagsJob() override;
+
+ // Result properties
+
+ /// List the tags set by a user on a room.
+ const QHash<QString, Tag>& tags() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Add a tag to a room.
+/*!
+ * Add a tag to the room.
+ */
+class SetRoomTagJob : public BaseJob
+{
+public:
+ /*! Add a tag to a room.
+ * \param userId
+ * The id of the user to add a tag for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param roomId
+ * The ID of the room to add a tag to.
+ * \param tag
+ * The tag to add.
+ * \param order
+ * A number in a range ``[0,1]`` describing a relative
+ * position of the room under the given tag.
+ */
+ explicit SetRoomTagJob(const QString& userId, const QString& roomId,
+ const QString& tag, Omittable<float> order = none);
+};
+
+/// Remove a tag from the room.
+/*!
+ * Remove a tag from the room.
+ */
+class DeleteRoomTagJob : public BaseJob
+{
+public:
+ /*! Remove a tag from the room.
+ * \param userId
+ * The id of the user to remove a tag for. The access token must be
+ * authorized to make requests for this user ID.
+ * \param roomId
+ * The ID of the room to remove a tag from.
+ * \param tag
+ * The tag to remove.
+ */
+ explicit DeleteRoomTagJob(const QString& userId, const QString& roomId,
+ const QString& tag);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * DeleteRoomTagJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
+ const QString& roomId, const QString& tag);
+};
- /// Remove a tag from the room.
- ///
- /// Remove a tag from the room.
- class DeleteRoomTagJob : public BaseJob
- {
- public:
- /*! Remove a tag from the room.
- * \param userId
- * The id of the user to remove a tag for. The access token must be
- * authorized to make requests for this user ID.
- * \param roomId
- * The ID of the room to remove a tag from.
- * \param tag
- * The tag to remove.
- */
- explicit DeleteRoomTagJob(const QString& userId, const QString& roomId,
- const QString& tag);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * DeleteRoomTagJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
- const QString& roomId, const QString& tag);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/third_party_lookup.cpp b/lib/csapi/third_party_lookup.cpp
index 339a0d90..986ead01 100644
--- a/lib/csapi/third_party_lookup.cpp
+++ b/lib/csapi/third_party_lookup.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetProtocolsJob::Private
{
- public:
+public:
QHash<QString, ThirdPartyProtocol> data;
};
@@ -28,10 +28,9 @@ static const auto GetProtocolsJobName = QStringLiteral("GetProtocolsJob");
GetProtocolsJob::GetProtocolsJob()
: BaseJob(HttpVerb::Get, GetProtocolsJobName,
- basePath % "/thirdparty/protocols"),
- d(new Private)
-{
-}
+ basePath % "/thirdparty/protocols")
+ , d(new Private)
+{}
GetProtocolsJob::~GetProtocolsJob() = default;
@@ -48,7 +47,7 @@ BaseJob::Status GetProtocolsJob::parseJson(const QJsonDocument& data)
class GetProtocolMetadataJob::Private
{
- public:
+public:
ThirdPartyProtocol data;
};
@@ -56,18 +55,17 @@ QUrl GetProtocolMetadataJob::makeRequestUrl(QUrl baseUrl,
const QString& protocol)
{
return BaseJob::makeRequestUrl(
- std::move(baseUrl), basePath % "/thirdparty/protocol/" % protocol);
+ std::move(baseUrl), basePath % "/thirdparty/protocol/" % protocol);
}
static const auto GetProtocolMetadataJobName =
- QStringLiteral("GetProtocolMetadataJob");
+ QStringLiteral("GetProtocolMetadataJob");
GetProtocolMetadataJob::GetProtocolMetadataJob(const QString& protocol)
: BaseJob(HttpVerb::Get, GetProtocolMetadataJobName,
- basePath % "/thirdparty/protocol/" % protocol),
- d(new Private)
-{
-}
+ basePath % "/thirdparty/protocol/" % protocol)
+ , d(new Private)
+{}
GetProtocolMetadataJob::~GetProtocolMetadataJob() = default;
@@ -84,7 +82,7 @@ BaseJob::Status GetProtocolMetadataJob::parseJson(const QJsonDocument& data)
class QueryLocationByProtocolJob::Private
{
- public:
+public:
QVector<ThirdPartyLocation> data;
};
@@ -99,22 +97,21 @@ QUrl QueryLocationByProtocolJob::makeRequestUrl(QUrl baseUrl,
const QString& protocol,
const QString& searchFields)
{
- return BaseJob::makeRequestUrl(
- std::move(baseUrl), basePath % "/thirdparty/location/" % protocol,
- queryToQueryLocationByProtocol(searchFields));
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ basePath % "/thirdparty/location/" % protocol,
+ queryToQueryLocationByProtocol(searchFields));
}
static const auto QueryLocationByProtocolJobName =
- QStringLiteral("QueryLocationByProtocolJob");
+ QStringLiteral("QueryLocationByProtocolJob");
QueryLocationByProtocolJob::QueryLocationByProtocolJob(
- const QString& protocol, const QString& searchFields)
+ const QString& protocol, const QString& searchFields)
: BaseJob(HttpVerb::Get, QueryLocationByProtocolJobName,
basePath % "/thirdparty/location/" % protocol,
- queryToQueryLocationByProtocol(searchFields)),
- d(new Private)
-{
-}
+ queryToQueryLocationByProtocol(searchFields))
+ , d(new Private)
+{}
QueryLocationByProtocolJob::~QueryLocationByProtocolJob() = default;
@@ -131,7 +128,7 @@ BaseJob::Status QueryLocationByProtocolJob::parseJson(const QJsonDocument& data)
class QueryUserByProtocolJob::Private
{
- public:
+public:
QVector<ThirdPartyUser> data;
};
@@ -152,16 +149,15 @@ QUrl QueryUserByProtocolJob::makeRequestUrl(QUrl baseUrl,
}
static const auto QueryUserByProtocolJobName =
- QStringLiteral("QueryUserByProtocolJob");
+ QStringLiteral("QueryUserByProtocolJob");
QueryUserByProtocolJob::QueryUserByProtocolJob(const QString& protocol,
const QString& fields)
: BaseJob(HttpVerb::Get, QueryUserByProtocolJobName,
basePath % "/thirdparty/user/" % protocol,
- queryToQueryUserByProtocol(fields)),
- d(new Private)
-{
-}
+ queryToQueryUserByProtocol(fields))
+ , d(new Private)
+{}
QueryUserByProtocolJob::~QueryUserByProtocolJob() = default;
@@ -178,7 +174,7 @@ BaseJob::Status QueryUserByProtocolJob::parseJson(const QJsonDocument& data)
class QueryLocationByAliasJob::Private
{
- public:
+public:
QVector<ThirdPartyLocation> data;
};
@@ -197,15 +193,14 @@ QUrl QueryLocationByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& alias)
}
static const auto QueryLocationByAliasJobName =
- QStringLiteral("QueryLocationByAliasJob");
+ QStringLiteral("QueryLocationByAliasJob");
QueryLocationByAliasJob::QueryLocationByAliasJob(const QString& alias)
: BaseJob(HttpVerb::Get, QueryLocationByAliasJobName,
basePath % "/thirdparty/location",
- queryToQueryLocationByAlias(alias)),
- d(new Private)
-{
-}
+ queryToQueryLocationByAlias(alias))
+ , d(new Private)
+{}
QueryLocationByAliasJob::~QueryLocationByAliasJob() = default;
@@ -222,7 +217,7 @@ BaseJob::Status QueryLocationByAliasJob::parseJson(const QJsonDocument& data)
class QueryUserByIDJob::Private
{
- public:
+public:
QVector<ThirdPartyUser> data;
};
@@ -244,10 +239,9 @@ static const auto QueryUserByIDJobName = QStringLiteral("QueryUserByIDJob");
QueryUserByIDJob::QueryUserByIDJob(const QString& userid)
: BaseJob(HttpVerb::Get, QueryUserByIDJobName,
- basePath % "/thirdparty/user", queryToQueryUserByID(userid)),
- d(new Private)
-{
-}
+ basePath % "/thirdparty/user", queryToQueryUserByID(userid))
+ , d(new Private)
+{}
QueryUserByIDJob::~QueryUserByIDJob() = default;
diff --git a/lib/csapi/third_party_lookup.h b/lib/csapi/third_party_lookup.h
index 91bc79e5..d25c1cf3 100644
--- a/lib/csapi/third_party_lookup.h
+++ b/lib/csapi/third_party_lookup.h
@@ -4,244 +4,253 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/../application-service/definitions/location.h"
#include "csapi/../application-service/definitions/protocol.h"
#include "csapi/../application-service/definitions/user.h"
+
+#include "jobs/basejob.h"
+
#include <QtCore/QHash>
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
-
- /// Retrieve metadata about all protocols that a homeserver supports.
- ///
- /// Fetches the overall metadata about protocols supported by the
- /// homeserver. Includes both the available protocols and all fields
- /// required for queries against each protocol.
- class GetProtocolsJob : public BaseJob
- {
- public:
- explicit GetProtocolsJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetProtocolsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetProtocolsJob() override;
-
- // Result properties
-
- /// The protocols supported by the homeserver.
- const QHash<QString, ThirdPartyProtocol>& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Retrieve metadata about a specific protocol that the homeserver
- /// supports.
- ///
- /// Fetches the metadata from the homeserver about a particular third party
- /// protocol.
- class GetProtocolMetadataJob : public BaseJob
- {
- public:
- /*! Retrieve metadata about a specific protocol that the homeserver supports.
- * \param protocol
- * The name of the protocol.
- */
- explicit GetProtocolMetadataJob(const QString& protocol);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetProtocolMetadataJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol);
-
- ~GetProtocolMetadataJob() override;
-
- // Result properties
-
- /// The protocol was found and metadata returned.
- const ThirdPartyProtocol& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Retrieve Matrix-side portals rooms leading to a third party location.
- ///
- /// Requesting this endpoint with a valid protocol name results in a list
- /// of successful mapping results in a JSON array. Each result contains
- /// objects to represent the Matrix room or rooms that represent a portal
- /// to this third party network. Each has the Matrix room alias string,
- /// an identifier for the particular third party network protocol, and an
- /// object containing the network-specific fields that comprise this
- /// identifier. It should attempt to canonicalise the identifier as much
- /// as reasonably possible given the network type.
- class QueryLocationByProtocolJob : public BaseJob
- {
- public:
- /*! Retrieve Matrix-side portals rooms leading to a third party location.
- * \param protocol
- * The protocol used to communicate to the third party network.
- * \param searchFields
- * One or more custom fields to help identify the third party
- * location.
- */
- explicit QueryLocationByProtocolJob(const QString& protocol,
- const QString& searchFields = {});
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * QueryLocationByProtocolJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol,
- const QString& searchFields = {});
-
- ~QueryLocationByProtocolJob() override;
-
- // Result properties
-
- /// At least one portal room was found.
- const QVector<ThirdPartyLocation>& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Retrieve the Matrix User ID of a corresponding third party user.
- ///
- /// Retrieve a Matrix User ID linked to a user on the third party service,
- /// given a set of user parameters.
- class QueryUserByProtocolJob : public BaseJob
- {
- public:
- /*! Retrieve the Matrix User ID of a corresponding third party user.
- * \param protocol
- * The name of the protocol.
- * \param fields
- * One or more custom fields that are passed to the AS to help
- * identify the user.
- */
- explicit QueryUserByProtocolJob(const QString& protocol,
- const QString& fields = {});
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * QueryUserByProtocolJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol,
- const QString& fields = {});
-
- ~QueryUserByProtocolJob() override;
-
- // Result properties
-
- /// The Matrix User IDs found with the given parameters.
- const QVector<ThirdPartyUser>& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Reverse-lookup third party locations given a Matrix room alias.
- ///
- /// Retrieve an array of third party network locations from a Matrix room
- /// alias.
- class QueryLocationByAliasJob : public BaseJob
- {
- public:
- /*! Reverse-lookup third party locations given a Matrix room alias.
- * \param alias
- * The Matrix room alias to look up.
- */
- explicit QueryLocationByAliasJob(const QString& alias);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * QueryLocationByAliasJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& alias);
-
- ~QueryLocationByAliasJob() override;
-
- // Result properties
-
- /// All found third party locations.
- const QVector<ThirdPartyLocation>& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-
- /// Reverse-lookup third party users given a Matrix User ID.
- ///
- /// Retrieve an array of third party users from a Matrix User ID.
- class QueryUserByIDJob : public BaseJob
- {
- public:
- /*! Reverse-lookup third party users given a Matrix User ID.
- * \param userid
- * The Matrix User ID to look up.
- */
- explicit QueryUserByIDJob(const QString& userid);
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * QueryUserByIDJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& userid);
-
- ~QueryUserByIDJob() override;
-
- // Result properties
-
- /// An array of third party users.
- const QVector<ThirdPartyUser>& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Retrieve metadata about all protocols that a homeserver supports.
+/*!
+ * Fetches the overall metadata about protocols supported by the
+ * homeserver. Includes both the available protocols and all fields
+ * required for queries against each protocol.
+ */
+class GetProtocolsJob : public BaseJob
+{
+public:
+ explicit GetProtocolsJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetProtocolsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetProtocolsJob() override;
+
+ // Result properties
+
+ /// The protocols supported by the homeserver.
+ const QHash<QString, ThirdPartyProtocol>& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Retrieve metadata about a specific protocol that the homeserver supports.
+/*!
+ * Fetches the metadata from the homeserver about a particular third party
+ * protocol.
+ */
+class GetProtocolMetadataJob : public BaseJob
+{
+public:
+ /*! Retrieve metadata about a specific protocol that the homeserver
+ * supports. \param protocol The name of the protocol.
+ */
+ explicit GetProtocolMetadataJob(const QString& protocol);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetProtocolMetadataJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol);
+
+ ~GetProtocolMetadataJob() override;
+
+ // Result properties
+
+ /// The protocol was found and metadata returned.
+ const ThirdPartyProtocol& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Retrieve Matrix-side portals rooms leading to a third party location.
+/*!
+ * Requesting this endpoint with a valid protocol name results in a list
+ * of successful mapping results in a JSON array. Each result contains
+ * objects to represent the Matrix room or rooms that represent a portal
+ * to this third party network. Each has the Matrix room alias string,
+ * an identifier for the particular third party network protocol, and an
+ * object containing the network-specific fields that comprise this
+ * identifier. It should attempt to canonicalise the identifier as much
+ * as reasonably possible given the network type.
+ */
+class QueryLocationByProtocolJob : public BaseJob
+{
+public:
+ /*! Retrieve Matrix-side portals rooms leading to a third party location.
+ * \param protocol
+ * The protocol used to communicate to the third party network.
+ * \param searchFields
+ * One or more custom fields to help identify the third party
+ * location.
+ */
+ explicit QueryLocationByProtocolJob(const QString& protocol,
+ const QString& searchFields = {});
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * QueryLocationByProtocolJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol,
+ const QString& searchFields = {});
+
+ ~QueryLocationByProtocolJob() override;
+
+ // Result properties
+
+ /// At least one portal room was found.
+ const QVector<ThirdPartyLocation>& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Retrieve the Matrix User ID of a corresponding third party user.
+/*!
+ * Retrieve a Matrix User ID linked to a user on the third party service, given
+ * a set of user parameters.
+ */
+class QueryUserByProtocolJob : public BaseJob
+{
+public:
+ /*! Retrieve the Matrix User ID of a corresponding third party user.
+ * \param protocol
+ * The name of the protocol.
+ * \param fields
+ * One or more custom fields that are passed to the AS to help identify
+ * the user.
+ */
+ explicit QueryUserByProtocolJob(const QString& protocol,
+ const QString& fields = {});
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * QueryUserByProtocolJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol,
+ const QString& fields = {});
+
+ ~QueryUserByProtocolJob() override;
+
+ // Result properties
+
+ /// The Matrix User IDs found with the given parameters.
+ const QVector<ThirdPartyUser>& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Reverse-lookup third party locations given a Matrix room alias.
+/*!
+ * Retrieve an array of third party network locations from a Matrix room
+ * alias.
+ */
+class QueryLocationByAliasJob : public BaseJob
+{
+public:
+ /*! Reverse-lookup third party locations given a Matrix room alias.
+ * \param alias
+ * The Matrix room alias to look up.
+ */
+ explicit QueryLocationByAliasJob(const QString& alias);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * QueryLocationByAliasJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& alias);
+
+ ~QueryLocationByAliasJob() override;
+
+ // Result properties
+
+ /// All found third party locations.
+ const QVector<ThirdPartyLocation>& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+/// Reverse-lookup third party users given a Matrix User ID.
+/*!
+ * Retrieve an array of third party users from a Matrix User ID.
+ */
+class QueryUserByIDJob : public BaseJob
+{
+public:
+ /*! Reverse-lookup third party users given a Matrix User ID.
+ * \param userid
+ * The Matrix User ID to look up.
+ */
+ explicit QueryUserByIDJob(const QString& userid);
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * QueryUserByIDJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& userid);
+
+ ~QueryUserByIDJob() override;
+
+ // Result properties
+
+ /// An array of third party users.
+ const QVector<ThirdPartyUser>& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/third_party_membership.h b/lib/csapi/third_party_membership.h
index d1261567..36622c94 100644
--- a/lib/csapi/third_party_membership.h
+++ b/lib/csapi/third_party_membership.h
@@ -6,69 +6,72 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Invite a user to participate in a particular room.
+/*!
+ * .. _invite-by-third-party-id-endpoint:
+ *
+ * *Note that there are two forms of this API, which are documented separately.
+ * This version of the API does not require that the inviter know the Matrix
+ * identifier of the invitee, and instead relies on third party identifiers.
+ * The homeserver uses an identity server to perform the mapping from
+ * third party identifier to a Matrix identifier. The other is documented in
+ * the* `joining rooms section`_.
+ *
+ * This API invites a user to participate in a particular room.
+ * They do not start participating in the room until they actually join the
+ * room.
+ *
+ * Only users currently in a particular room can invite other users to
+ * join that room.
+ *
+ * If the identity server did know the Matrix user identifier for the
+ * third party identifier, the homeserver will append a ``m.room.member``
+ * event to the room.
+ *
+ * If the identity server does not know a Matrix user identifier for the
+ * passed third party identifier, the homeserver will issue an invitation
+ * which can be accepted upon providing proof of ownership of the third
+ * party identifier. This is achieved by the identity server generating a
+ * token, which it gives to the inviting homeserver. The homeserver will
+ * add an ``m.room.third_party_invite`` event into the graph for the room,
+ * containing that token.
+ *
+ * When the invitee binds the invited third party identifier to a Matrix
+ * user ID, the identity server will give the user a list of pending
+ * invitations, each containing:
+ *
+ * - The room ID to which they were invited
+ *
+ * - The token given to the homeserver
+ *
+ * - A signature of the token, signed with the identity server's private key
+ *
+ * - The matrix user ID who invited them to the room
+ *
+ * If a token is requested from the identity server, the homeserver will
+ * append a ``m.room.third_party_invite`` event to the room.
+ *
+ * .. _joining rooms section: `invite-by-user-id-endpoint`_
+ */
+class InviteBy3PIDJob : public BaseJob
+{
+public:
+ /*! Invite a user to participate in a particular room.
+ * \param roomId
+ * The room identifier (not alias) to which to invite the user.
+ * \param idServer
+ * The hostname+port of the identity server which should be used for third
+ * party identifier lookups. \param medium The kind of address being passed
+ * in the address field, for example ``email``. \param address The invitee's
+ * third party identifier.
+ */
+ explicit InviteBy3PIDJob(const QString& roomId, const QString& idServer,
+ const QString& medium, const QString& address);
+};
- /// Invite a user to participate in a particular room.
- ///
- /// .. _invite-by-third-party-id-endpoint:
- ///
- /// *Note that there are two forms of this API, which are documented
- /// separately. This version of the API does not require that the inviter
- /// know the Matrix identifier of the invitee, and instead relies on third
- /// party identifiers. The homeserver uses an identity server to perform the
- /// mapping from third party identifier to a Matrix identifier. The other is
- /// documented in the* `joining rooms section`_.
- ///
- /// This API invites a user to participate in a particular room.
- /// They do not start participating in the room until they actually join the
- /// room.
- ///
- /// Only users currently in a particular room can invite other users to
- /// join that room.
- ///
- /// If the identity server did know the Matrix user identifier for the
- /// third party identifier, the homeserver will append a ``m.room.member``
- /// event to the room.
- ///
- /// If the identity server does not know a Matrix user identifier for the
- /// passed third party identifier, the homeserver will issue an invitation
- /// which can be accepted upon providing proof of ownership of the third
- /// party identifier. This is achieved by the identity server generating a
- /// token, which it gives to the inviting homeserver. The homeserver will
- /// add an ``m.room.third_party_invite`` event into the graph for the room,
- /// containing that token.
- ///
- /// When the invitee binds the invited third party identifier to a Matrix
- /// user ID, the identity server will give the user a list of pending
- /// invitations, each containing:
- ///
- /// - The room ID to which they were invited
- ///
- /// - The token given to the homeserver
- ///
- /// - A signature of the token, signed with the identity server's private
- /// key
- ///
- /// - The matrix user ID who invited them to the room
- ///
- /// If a token is requested from the identity server, the homeserver will
- /// append a ``m.room.third_party_invite`` event to the room.
- ///
- /// .. _joining rooms section: `invite-by-user-id-endpoint`_
- class InviteBy3PIDJob : public BaseJob
- {
- public:
- /*! Invite a user to participate in a particular room.
- * \param roomId
- * The room identifier (not alias) to which to invite the user.
- * \param idServer
- * The hostname+port of the identity server which should be used for
- * third party identifier lookups. \param medium The kind of address
- * being passed in the address field, for example ``email``. \param
- * address The invitee's third party identifier.
- */
- explicit InviteBy3PIDJob(const QString& roomId, const QString& idServer,
- const QString& medium, const QString& address);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/to_device.cpp b/lib/csapi/to_device.cpp
index 241869f3..3fb17109 100644
--- a/lib/csapi/to_device.cpp
+++ b/lib/csapi/to_device.cpp
@@ -15,8 +15,8 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
static const auto SendToDeviceJobName = QStringLiteral("SendToDeviceJob");
SendToDeviceJob::SendToDeviceJob(
- const QString& eventType, const QString& txnId,
- const QHash<QString, QHash<QString, QJsonObject>>& messages)
+ const QString& eventType, const QString& txnId,
+ const QHash<QString, QHash<QString, QJsonObject>>& messages)
: BaseJob(HttpVerb::Put, SendToDeviceJobName,
basePath % "/sendToDevice/" % eventType % "/" % txnId)
{
diff --git a/lib/csapi/to_device.h b/lib/csapi/to_device.h
index 83df13b7..e0bbbe28 100644
--- a/lib/csapi/to_device.h
+++ b/lib/csapi/to_device.h
@@ -9,31 +9,34 @@
#include <QtCore/QHash>
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Send an event to a given set of devices.
+/*!
+ * This endpoint is used to send send-to-device events to a set of
+ * client devices.
+ */
+class SendToDeviceJob : public BaseJob
+{
+public:
+ /*! Send an event to a given set of devices.
+ * \param eventType
+ * The type of event to send.
+ * \param txnId
+ * The transaction ID for this event. Clients should generate an
+ * ID unique across requests with the same access token; it will be
+ * used by the server to ensure idempotency of requests.
+ * \param messages
+ * The messages to send. A map from user ID, to a map from
+ * device ID to message body. The device ID may also be `*`,
+ * meaning all known devices for the user.
+ */
+ explicit SendToDeviceJob(
+ const QString& eventType, const QString& txnId,
+ const QHash<QString, QHash<QString, QJsonObject>>& messages = {});
+};
- /// Send an event to a given set of devices.
- ///
- /// This endpoint is used to send send-to-device events to a set of
- /// client devices.
- class SendToDeviceJob : public BaseJob
- {
- public:
- /*! Send an event to a given set of devices.
- * \param eventType
- * The type of event to send.
- * \param txnId
- * The transaction ID for this event. Clients should generate an
- * ID unique across requests with the same access token; it will be
- * used by the server to ensure idempotency of requests.
- * \param messages
- * The messages to send. A map from user ID, to a map from
- * device ID to message body. The device ID may also be `*`,
- * meaning all known devices for the user.
- */
- explicit SendToDeviceJob(
- const QString& eventType, const QString& txnId,
- const QHash<QString, QHash<QString, QJsonObject>>&
- messages = {});
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/typing.h b/lib/csapi/typing.h
index 1f32a8e5..0c3f75a8 100644
--- a/lib/csapi/typing.h
+++ b/lib/csapi/typing.h
@@ -4,34 +4,38 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
+namespace QMatrixClient
+{
-namespace QMatrixClient {
- // Operations
+// Operations
+
+/// Informs the server that the user has started or stopped typing.
+/*!
+ * This tells the server that the user is typing for the next N
+ * milliseconds where N is the value specified in the ``timeout`` key.
+ * Alternatively, if ``typing`` is ``false``, it tells the server that the
+ * user has stopped typing.
+ */
+class SetTypingJob : public BaseJob
+{
+public:
+ /*! Informs the server that the user has started or stopped typing.
+ * \param userId
+ * The user who has started to type.
+ * \param roomId
+ * The room in which the user is typing.
+ * \param typing
+ * Whether the user is typing or not. If ``false``, the ``timeout``
+ * key can be omitted.
+ * \param timeout
+ * The length of time in milliseconds to mark this user as typing.
+ */
+ explicit SetTypingJob(const QString& userId, const QString& roomId,
+ bool typing, Omittable<int> timeout = none);
+};
- /// Informs the server that the user has started or stopped typing.
- ///
- /// This tells the server that the user is typing for the next N
- /// milliseconds where N is the value specified in the ``timeout`` key.
- /// Alternatively, if ``typing`` is ``false``, it tells the server that the
- /// user has stopped typing.
- class SetTypingJob : public BaseJob
- {
- public:
- /*! Informs the server that the user has started or stopped typing.
- * \param userId
- * The user who has started to type.
- * \param roomId
- * The room in which the user is typing.
- * \param typing
- * Whether the user is typing or not. If ``false``, the ``timeout``
- * key can be omitted.
- * \param timeout
- * The length of time in milliseconds to mark this user as typing.
- */
- explicit SetTypingJob(const QString& userId, const QString& roomId,
- bool typing, Omittable<int> timeout = none);
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/users.cpp b/lib/csapi/users.cpp
index 6d005915..39b05a77 100644
--- a/lib/csapi/users.cpp
+++ b/lib/csapi/users.cpp
@@ -12,35 +12,39 @@ using namespace QMatrixClient;
static const auto basePath = QStringLiteral("/_matrix/client/r0");
-namespace QMatrixClient {
- // Converters
-
- template <> struct JsonObjectConverter<SearchUserDirectoryJob::User> {
- static void fillFrom(const QJsonObject& jo,
- SearchUserDirectoryJob::User& result)
- {
- fromJson(jo.value("user_id"_ls), result.userId);
- fromJson(jo.value("display_name"_ls), result.displayName);
- fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
- }
- };
+// Converters
+namespace QMatrixClient
+{
+
+template <>
+struct JsonObjectConverter<SearchUserDirectoryJob::User>
+{
+ static void fillFrom(const QJsonObject& jo,
+ SearchUserDirectoryJob::User& result)
+ {
+ fromJson(jo.value("user_id"_ls), result.userId);
+ fromJson(jo.value("display_name"_ls), result.displayName);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
+ }
+};
+
} // namespace QMatrixClient
class SearchUserDirectoryJob::Private
{
- public:
+public:
QVector<User> results;
bool limited;
};
static const auto SearchUserDirectoryJobName =
- QStringLiteral("SearchUserDirectoryJob");
+ QStringLiteral("SearchUserDirectoryJob");
SearchUserDirectoryJob::SearchUserDirectoryJob(const QString& searchTerm,
Omittable<int> limit)
: BaseJob(HttpVerb::Post, SearchUserDirectoryJobName,
- basePath % "/user_directory/search"),
- d(new Private)
+ basePath % "/user_directory/search")
+ , d(new Private)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("search_term"), searchTerm);
@@ -50,8 +54,7 @@ SearchUserDirectoryJob::SearchUserDirectoryJob(const QString& searchTerm,
SearchUserDirectoryJob::~SearchUserDirectoryJob() = default;
-const QVector<SearchUserDirectoryJob::User>&
-SearchUserDirectoryJob::results() const
+const QVector<SearchUserDirectoryJob::User>& SearchUserDirectoryJob::results() const
{
return d->results;
}
@@ -62,12 +65,13 @@ BaseJob::Status SearchUserDirectoryJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("results"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'results' not found in the response" };
fromJson(json.value("results"_ls), d->results);
if (!json.contains("limited"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'limited' not found in the response" };
fromJson(json.value("limited"_ls), d->limited);
+
return Success;
}
diff --git a/lib/csapi/users.h b/lib/csapi/users.h
index 7754b82a..2e86c009 100644
--- a/lib/csapi/users.h
+++ b/lib/csapi/users.h
@@ -4,74 +4,80 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QVector>
-namespace QMatrixClient {
- // Operations
-
- /// Searches the user directory.
- ///
- /// Performs a search for users on the homeserver. The homeserver may
- /// determine which subset of users are searched, however the homeserver
- /// MUST at a minimum consider the users the requesting user shares a
- /// room with and those who reside in public rooms (known to the
- /// homeserver). The search MUST consider local users to the homeserver, and
- /// SHOULD query remote users as part of the search.
- ///
- /// The search is performed case-insensitively on user IDs and display
- /// names preferably using a collation determined based upon the
- /// ``Accept-Language`` header provided in the request, if present.
- class SearchUserDirectoryJob : public BaseJob
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Searches the user directory.
+/*!
+ * Performs a search for users on the homeserver. The homeserver may
+ * determine which subset of users are searched, however the homeserver
+ * MUST at a minimum consider the users the requesting user shares a
+ * room with and those who reside in public rooms (known to the homeserver).
+ * The search MUST consider local users to the homeserver, and SHOULD
+ * query remote users as part of the search.
+ *
+ * The search is performed case-insensitively on user IDs and display
+ * names preferably using a collation determined based upon the
+ * ``Accept-Language`` header provided in the request, if present.
+ */
+class SearchUserDirectoryJob : public BaseJob
+{
+public:
+ // Inner data structures
+
+ /// Performs a search for users on the homeserver. The homeserver
+ /// maydetermine which subset of users are searched, however the
+ /// homeserverMUST at a minimum consider the users the requesting user
+ /// shares aroom with and those who reside in public rooms (known to the
+ /// homeserver).The search MUST consider local users to the homeserver, and
+ /// SHOULDquery remote users as part of the search.The search is performed
+ /// case-insensitively on user IDs and displaynames preferably using a
+ /// collation determined based upon the ``Accept-Language`` header provided
+ /// in the request, if present.
+ struct User
{
- public:
- // Inner data structures
-
- /// Performs a search for users on the homeserver. The homeserver may
- /// determine which subset of users are searched, however the homeserver
- /// MUST at a minimum consider the users the requesting user shares a
- /// room with and those who reside in public rooms (known to the
- /// homeserver). The search MUST consider local users to the homeserver,
- /// and SHOULD query remote users as part of the search.
- ///
- /// The search is performed case-insensitively on user IDs and display
- /// names preferably using a collation determined based upon the
- /// ``Accept-Language`` header provided in the request, if present.
- struct User {
- /// The user's matrix user ID.
- QString userId;
- /// The display name of the user, if one exists.
- QString displayName;
- /// The avatar url, as an MXC, if one exists.
- QString avatarUrl;
- };
-
- // Construction/destruction
-
- /*! Searches the user directory.
- * \param searchTerm
- * The term to search for
- * \param limit
- * The maximum number of results to return. Defaults to 10.
- */
- explicit SearchUserDirectoryJob(const QString& searchTerm,
- Omittable<int> limit = none);
- ~SearchUserDirectoryJob() override;
-
- // Result properties
-
- /// Ordered by rank and then whether or not profile info is available.
- const QVector<User>& results() const;
- /// Indicates if the result list has been truncated by the limit.
- bool limited() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
+ /// The user's matrix user ID.
+ QString userId;
+ /// The display name of the user, if one exists.
+ QString displayName;
+ /// The avatar url, as an MXC, if one exists.
+ QString avatarUrl;
};
+
+ // Construction/destruction
+
+ /*! Searches the user directory.
+ * \param searchTerm
+ * The term to search for
+ * \param limit
+ * The maximum number of results to return. Defaults to 10.
+ */
+ explicit SearchUserDirectoryJob(const QString& searchTerm,
+ Omittable<int> limit = none);
+
+ ~SearchUserDirectoryJob() override;
+
+ // Result properties
+
+ /// Ordered by rank and then whether or not profile info is available.
+ const QVector<User>& results() const;
+ /// Indicates if the result list has been truncated by the limit.
+ bool limited() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/versions.cpp b/lib/csapi/versions.cpp
index 13e3be15..1d66b94f 100644
--- a/lib/csapi/versions.cpp
+++ b/lib/csapi/versions.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client");
class GetVersionsJob::Private
{
- public:
+public:
QStringList versions;
QHash<QString, bool> unstableFeatures;
};
@@ -27,10 +27,9 @@ QUrl GetVersionsJob::makeRequestUrl(QUrl baseUrl)
static const auto GetVersionsJobName = QStringLiteral("GetVersionsJob");
GetVersionsJob::GetVersionsJob()
- : BaseJob(HttpVerb::Get, GetVersionsJobName, basePath % "/versions", false),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetVersionsJobName, basePath % "/versions", false)
+ , d(new Private)
+{}
GetVersionsJob::~GetVersionsJob() = default;
@@ -45,9 +44,10 @@ BaseJob::Status GetVersionsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("versions"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'versions' not found in the response" };
fromJson(json.value("versions"_ls), d->versions);
fromJson(json.value("unstable_features"_ls), d->unstableFeatures);
+
return Success;
}
diff --git a/lib/csapi/versions.h b/lib/csapi/versions.h
index d017708a..513e7f27 100644
--- a/lib/csapi/versions.h
+++ b/lib/csapi/versions.h
@@ -4,65 +4,70 @@
#pragma once
+#include "converters.h"
+
#include "jobs/basejob.h"
-#include "converters.h"
#include <QtCore/QHash>
-namespace QMatrixClient {
- // Operations
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets the versions of the specification supported by the server.
+/*!
+ * Gets the versions of the specification supported by the server.
+ *
+ * Values will take the form ``rX.Y.Z``.
+ *
+ * Only the latest ``Z`` value will be reported for each supported ``X.Y``
+ * value. i.e. if the server implements ``r0.0.0``, ``r0.0.1``, and ``r1.2.0``,
+ * it will report ``r0.0.1`` and ``r1.2.0``.
+ *
+ * The server may additionally advertise experimental features it supports
+ * through ``unstable_features``. These features should be namespaced and
+ * may optionally include version information within their name if desired.
+ * Features listed here are not for optionally toggling parts of the Matrix
+ * specification and should only be used to advertise support for a feature
+ * which has not yet landed in the spec. For example, a feature currently
+ * undergoing the proposal process may appear here and eventually be taken
+ * off this list once the feature lands in the spec and the server deems it
+ * reasonable to do so. Servers may wish to keep advertising features here
+ * after they've been released into the spec to give clients a chance to
+ * upgrade appropriately. Additionally, clients should avoid using unstable
+ * features in their stable releases.
+ */
+class GetVersionsJob : public BaseJob
+{
+public:
+ explicit GetVersionsJob();
- /// Gets the versions of the specification supported by the server.
- ///
- /// Gets the versions of the specification supported by the server.
- ///
- /// Values will take the form ``rX.Y.Z``.
- ///
- /// Only the latest ``Z`` value will be reported for each supported ``X.Y``
- /// value. i.e. if the server implements ``r0.0.0``, ``r0.0.1``, and
- /// ``r1.2.0``, it will report ``r0.0.1`` and ``r1.2.0``.
- ///
- /// The server may additionally advertise experimental features it supports
- /// through ``unstable_features``. These features should be namespaced and
- /// may optionally include version information within their name if desired.
- /// Features listed here are not for optionally toggling parts of the Matrix
- /// specification and should only be used to advertise support for a feature
- /// which has not yet landed in the spec. For example, a feature currently
- /// undergoing the proposal process may appear here and eventually be taken
- /// off this list once the feature lands in the spec and the server deems it
- /// reasonable to do so. Servers may wish to keep advertising features here
- /// after they've been released into the spec to give clients a chance to
- /// upgrade appropriately. Additionally, clients should avoid using unstable
- /// features in their stable releases.
- class GetVersionsJob : public BaseJob
- {
- public:
- explicit GetVersionsJob();
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetVersionsJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetVersionsJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
+ ~GetVersionsJob() override;
- ~GetVersionsJob() override;
+ // Result properties
- // Result properties
+ /// The supported versions.
+ const QStringList& versions() const;
+ /// Experimental features the server supports. Features not listed here,
+ /// or the lack of this property all together, indicate that a feature is
+ /// not supported.
+ const QHash<QString, bool>& unstableFeatures() const;
- /// The supported versions.
- const QStringList& versions() const;
- /// Experimental features the server supports. Features not listed here,
- /// or the lack of this property all together, indicate that a feature
- /// is not supported.
- const QHash<QString, bool>& unstableFeatures() const;
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- protected:
- Status parseJson(const QJsonDocument& data) override;
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
- private:
- class Private;
- QScopedPointer<Private> d;
- };
} // namespace QMatrixClient
diff --git a/lib/csapi/voip.cpp b/lib/csapi/voip.cpp
index ee511906..0e83c915 100644
--- a/lib/csapi/voip.cpp
+++ b/lib/csapi/voip.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetTurnServerJob::Private
{
- public:
+public:
QJsonObject data;
};
@@ -27,11 +27,9 @@ QUrl GetTurnServerJob::makeRequestUrl(QUrl baseUrl)
static const auto GetTurnServerJobName = QStringLiteral("GetTurnServerJob");
GetTurnServerJob::GetTurnServerJob()
- : BaseJob(HttpVerb::Get, GetTurnServerJobName,
- basePath % "/voip/turnServer"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetTurnServerJobName, basePath % "/voip/turnServer")
+ , d(new Private)
+{}
GetTurnServerJob::~GetTurnServerJob() = default;
diff --git a/lib/csapi/voip.h b/lib/csapi/voip.h
index 3b011651..ab34dcad 100644
--- a/lib/csapi/voip.h
+++ b/lib/csapi/voip.h
@@ -8,38 +8,42 @@
#include <QtCore/QJsonObject>
-namespace QMatrixClient {
- // Operations
-
- /// Obtain TURN server credentials.
- ///
- /// This API provides credentials for the client to use when initiating
- /// calls.
- class GetTurnServerJob : public BaseJob
- {
- public:
- explicit GetTurnServerJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetTurnServerJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetTurnServerJob() override;
-
- // Result properties
-
- /// The TURN server credentials.
- const QJsonObject& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Obtain TURN server credentials.
+/*!
+ * This API provides credentials for the client to use when initiating
+ * calls.
+ */
+class GetTurnServerJob : public BaseJob
+{
+public:
+ explicit GetTurnServerJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetTurnServerJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetTurnServerJob() override;
+
+ // Result properties
+
+ /// The TURN server credentials.
+ const QJsonObject& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/wellknown.cpp b/lib/csapi/wellknown.cpp
index 8543c519..c2bd7822 100644
--- a/lib/csapi/wellknown.cpp
+++ b/lib/csapi/wellknown.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/.well-known");
class GetWellknownJob::Private
{
- public:
+public:
DiscoveryInformation data;
};
@@ -28,10 +28,9 @@ static const auto GetWellknownJobName = QStringLiteral("GetWellknownJob");
GetWellknownJob::GetWellknownJob()
: BaseJob(HttpVerb::Get, GetWellknownJobName, basePath % "/matrix/client",
- false),
- d(new Private)
-{
-}
+ false)
+ , d(new Private)
+{}
GetWellknownJob::~GetWellknownJob() = default;
diff --git a/lib/csapi/wellknown.h b/lib/csapi/wellknown.h
index 1df524ce..66917806 100644
--- a/lib/csapi/wellknown.h
+++ b/lib/csapi/wellknown.h
@@ -4,49 +4,54 @@
#pragma once
-#include "jobs/basejob.h"
-
#include "converters.h"
+
#include "csapi/definitions/wellknown/full.h"
-namespace QMatrixClient {
- // Operations
-
- /// Gets Matrix server discovery information about the domain.
- ///
- /// Gets discovery information about the domain. The file may include
- /// additional keys, which MUST follow the Java package naming convention,
- /// e.g. ``com.example.myapp.property``. This ensures property names are
- /// suitably namespaced for each application and reduces the risk of
- /// clashes.
- ///
- /// Note that this endpoint is not necessarily handled by the homeserver,
- /// but by another webserver, to be used for discovering the homeserver URL.
- class GetWellknownJob : public BaseJob
- {
- public:
- explicit GetWellknownJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetWellknownJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetWellknownJob() override;
-
- // Result properties
-
- /// Server discovery information.
- const DiscoveryInformation& data() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+#include "jobs/basejob.h"
+
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets Matrix server discovery information about the domain.
+/*!
+ * Gets discovery information about the domain. The file may include
+ * additional keys, which MUST follow the Java package naming convention,
+ * e.g. ``com.example.myapp.property``. This ensures property names are
+ * suitably namespaced for each application and reduces the risk of
+ * clashes.
+ *
+ * Note that this endpoint is not necessarily handled by the homeserver,
+ * but by another webserver, to be used for discovering the homeserver URL.
+ */
+class GetWellknownJob : public BaseJob
+{
+public:
+ explicit GetWellknownJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetWellknownJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetWellknownJob() override;
+
+ // Result properties
+
+ /// Server discovery information.
+ const DiscoveryInformation& data() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp
index f0a77aee..2ca9c435 100644
--- a/lib/csapi/whoami.cpp
+++ b/lib/csapi/whoami.cpp
@@ -14,7 +14,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0");
class GetTokenOwnerJob::Private
{
- public:
+public:
QString userId;
};
@@ -27,11 +27,9 @@ QUrl GetTokenOwnerJob::makeRequestUrl(QUrl baseUrl)
static const auto GetTokenOwnerJobName = QStringLiteral("GetTokenOwnerJob");
GetTokenOwnerJob::GetTokenOwnerJob()
- : BaseJob(HttpVerb::Get, GetTokenOwnerJobName,
- basePath % "/account/whoami"),
- d(new Private)
-{
-}
+ : BaseJob(HttpVerb::Get, GetTokenOwnerJobName, basePath % "/account/whoami")
+ , d(new Private)
+{}
GetTokenOwnerJob::~GetTokenOwnerJob() = default;
@@ -41,8 +39,9 @@ BaseJob::Status GetTokenOwnerJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("user_id"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'user_id' not found in the response" };
fromJson(json.value("user_id"_ls), d->userId);
+
return Success;
}
diff --git a/lib/csapi/whoami.h b/lib/csapi/whoami.h
index 8f191351..e62b7dad 100644
--- a/lib/csapi/whoami.h
+++ b/lib/csapi/whoami.h
@@ -6,44 +6,48 @@
#include "jobs/basejob.h"
-namespace QMatrixClient {
- // Operations
-
- /// Gets information about the owner of an access token.
- ///
- /// Gets information about the owner of a given access token.
- ///
- /// Note that, as with the rest of the Client-Server API,
- /// Application Services may masquerade as users within their
- /// namespace by giving a ``user_id`` query parameter. In this
- /// situation, the server should verify that the given ``user_id``
- /// is registered by the appservice, and return it in the response
- /// body.
- class GetTokenOwnerJob : public BaseJob
- {
- public:
- explicit GetTokenOwnerJob();
-
- /*! Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for
- * GetTokenOwnerJob is necessary but the job
- * itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl);
-
- ~GetTokenOwnerJob() override;
-
- // Result properties
-
- /// The user id that owns the access token.
- const QString& userId() const;
-
- protected:
- Status parseJson(const QJsonDocument& data) override;
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
+namespace QMatrixClient
+{
+
+// Operations
+
+/// Gets information about the owner of an access token.
+/*!
+ * Gets information about the owner of a given access token.
+ *
+ * Note that, as with the rest of the Client-Server API,
+ * Application Services may masquerade as users within their
+ * namespace by giving a ``user_id`` query parameter. In this
+ * situation, the server should verify that the given ``user_id``
+ * is registered by the appservice, and return it in the response
+ * body.
+ */
+class GetTokenOwnerJob : public BaseJob
+{
+public:
+ explicit GetTokenOwnerJob();
+
+ /*! Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for
+ * GetTokenOwnerJob is necessary but the job
+ * itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl);
+
+ ~GetTokenOwnerJob() override;
+
+ // Result properties
+
+ /// The user id that owns the access token.
+ const QString& userId() const;
+
+protected:
+ Status parseJson(const QJsonDocument& data) override;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
} // namespace QMatrixClient
diff --git a/lib/csapi/{{base}}.cpp.mustache b/lib/csapi/{{base}}.cpp.mustache
index f9a63412..8ebac6ef 100644
--- a/lib/csapi/{{base}}.cpp.mustache
+++ b/lib/csapi/{{base}}.cpp.mustache
@@ -141,7 +141,7 @@ BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data
}} auto json = data.object();
{{# properties}}{{#required?
}} if (!json.contains("{{baseName}}"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key '{{baseName}}' not found in the response" };
{{/required?
}} fromJson(json.value("{{baseName}}"_ls), d->{{paramName}});
diff --git a/lib/eventitem.cpp b/lib/eventitem.cpp
index f3f18854..de0a5c9f 100644
--- a/lib/eventitem.cpp
+++ b/lib/eventitem.cpp
@@ -35,9 +35,8 @@ void PendingEventItem::setFileUploaded(const QUrl& remoteUrl)
}
if (auto* rae = getAs<RoomAvatarEvent>()) {
Q_ASSERT(rae->content().fileInfo());
- rae->editContent([remoteUrl](EventContent::FileInfo& fi) {
- fi.url = remoteUrl;
- });
+ rae->editContent(
+ [remoteUrl](EventContent::FileInfo& fi) { fi.url = remoteUrl; });
}
setStatus(EventStatus::FileUploaded);
}
diff --git a/lib/eventitem.h b/lib/eventitem.h
index 8b863d67..58f5479c 100644
--- a/lib/eventitem.h
+++ b/lib/eventitem.h
@@ -22,140 +22,144 @@
#include <utility>
-namespace QMatrixClient {
- class StateEventBase;
-
- class EventStatus
+namespace QMatrixClient
+{
+class StateEventBase;
+
+class EventStatus
+{
+ Q_GADGET
+public:
+ /** Special marks an event can assume
+ *
+ * This is used to hint at a special status of some events in UI.
+ * All values except Redacted and Hidden are mutually exclusive.
+ */
+ enum Code
{
- Q_GADGET
- public:
- /** Special marks an event can assume
- *
- * This is used to hint at a special status of some events in UI.
- * All values except Redacted and Hidden are mutually exclusive.
- */
- enum Code {
- Normal = 0x0, //< No special designation
- Submitted = 0x01, //< The event has just been submitted for sending
- FileUploaded = 0x02, //< The file attached to the event has been
- //uploaded to the server
- Departed = 0x03, //< The event has left the client
- ReachedServer = 0x04, //< The server has received the event
- SendingFailed = 0x05, //< The server could not receive the event
- Redacted = 0x08, //< The event has been redacted
- Hidden = 0x10, //< The event should not be shown in the timeline
- };
- Q_DECLARE_FLAGS(Status, Code)
- Q_FLAG(Status)
+ Normal = 0x0, //< No special designation
+ Submitted = 0x01, //< The event has just been submitted for sending
+ FileUploaded = 0x02, //< The file attached to the event has been
+ // uploaded to the server
+ Departed = 0x03, //< The event has left the client
+ ReachedServer = 0x04, //< The server has received the event
+ SendingFailed = 0x05, //< The server could not receive the event
+ Redacted = 0x08, //< The event has been redacted
+ Hidden = 0x10, //< The event should not be shown in the timeline
};
+ Q_DECLARE_FLAGS(Status, Code)
+ Q_FLAG(Status)
+};
+
+class EventItemBase
+{
+public:
+ explicit EventItemBase(RoomEventPtr&& e)
+ : evt(std::move(e))
+ {
+ Q_ASSERT(evt);
+ }
- class EventItemBase
+ const RoomEvent* event() const { return rawPtr(evt); }
+ const RoomEvent* get() const { return event(); }
+ template <typename EventT>
+ const EventT* viewAs() const
{
- public:
- explicit EventItemBase(RoomEventPtr&& e) : evt(std::move(e))
- {
- Q_ASSERT(evt);
- }
-
- const RoomEvent* event() const { return rawPtr(evt); }
- const RoomEvent* get() const { return event(); }
- template <typename EventT> const EventT* viewAs() const
- {
- return eventCast<const EventT>(evt);
- }
- const RoomEventPtr& operator->() const { return evt; }
- const RoomEvent& operator*() const { return *evt; }
-
- // Used for event redaction
- RoomEventPtr replaceEvent(RoomEventPtr&& other)
- {
- return std::exchange(evt, move(other));
- }
-
- protected:
- template <typename EventT> EventT* getAs()
- {
- return eventCast<EventT>(evt);
- }
-
- private:
- RoomEventPtr evt;
- };
+ return eventCast<const EventT>(evt);
+ }
+ const RoomEventPtr& operator->() const { return evt; }
+ const RoomEvent& operator*() const { return *evt; }
- class TimelineItem : public EventItemBase
+ // Used for event redaction
+ RoomEventPtr replaceEvent(RoomEventPtr&& other)
{
- public:
- // For compatibility with Qt containers, even though we use
- // a std:: container now for the room timeline
- using index_t = int;
+ return std::exchange(evt, move(other));
+ }
- TimelineItem(RoomEventPtr&& e, index_t number)
- : EventItemBase(std::move(e)), idx(number)
- {
- }
+protected:
+ template <typename EventT>
+ EventT* getAs()
+ {
+ return eventCast<EventT>(evt);
+ }
- index_t index() const { return idx; }
+private:
+ RoomEventPtr evt;
+};
+
+class TimelineItem : public EventItemBase
+{
+public:
+ // For compatibility with Qt containers, even though we use
+ // a std:: container now for the room timeline
+ using index_t = int;
+
+ TimelineItem(RoomEventPtr&& e, index_t number)
+ : EventItemBase(std::move(e))
+ , idx(number)
+ {}
+
+ index_t index() const { return idx; }
+
+private:
+ index_t idx;
+};
+
+template <>
+inline const StateEventBase* EventItemBase::viewAs<StateEventBase>() const
+{
+ return evt->isStateEvent() ? weakPtrCast<const StateEventBase>(evt)
+ : nullptr;
+}
- private:
- index_t idx;
- };
+template <>
+inline const CallEventBase* EventItemBase::viewAs<CallEventBase>() const
+{
+ return evt->isCallEvent() ? weakPtrCast<const CallEventBase>(evt) : nullptr;
+}
+
+class PendingEventItem : public EventItemBase
+{
+ Q_GADGET
+public:
+ using EventItemBase::EventItemBase;
+
+ EventStatus::Code deliveryStatus() const { return _status; }
+ QDateTime lastUpdated() const { return _lastUpdated; }
+ QString annotation() const { return _annotation; }
- template <>
- inline const StateEventBase* EventItemBase::viewAs<StateEventBase>() const
+ void setDeparted() { setStatus(EventStatus::Departed); }
+ void setFileUploaded(const QUrl& remoteUrl);
+ void setReachedServer(const QString& eventId)
{
- return evt->isStateEvent() ? weakPtrCast<const StateEventBase>(evt)
- : nullptr;
+ setStatus(EventStatus::ReachedServer);
+ (*this)->addId(eventId);
}
-
- template <>
- inline const CallEventBase* EventItemBase::viewAs<CallEventBase>() const
+ void setSendingFailed(QString errorText)
{
- return evt->isCallEvent() ? weakPtrCast<const CallEventBase>(evt)
- : nullptr;
+ setStatus(EventStatus::SendingFailed);
+ _annotation = std::move(errorText);
}
+ void resetStatus() { setStatus(EventStatus::Submitted); }
- class PendingEventItem : public EventItemBase
- {
- Q_GADGET
- public:
- using EventItemBase::EventItemBase;
-
- EventStatus::Code deliveryStatus() const { return _status; }
- QDateTime lastUpdated() const { return _lastUpdated; }
- QString annotation() const { return _annotation; }
-
- void setDeparted() { setStatus(EventStatus::Departed); }
- void setFileUploaded(const QUrl& remoteUrl);
- void setReachedServer(const QString& eventId)
- {
- setStatus(EventStatus::ReachedServer);
- (*this)->addId(eventId);
- }
- void setSendingFailed(QString errorText)
- {
- setStatus(EventStatus::SendingFailed);
- _annotation = std::move(errorText);
- }
- void resetStatus() { setStatus(EventStatus::Submitted); }
-
- private:
- EventStatus::Code _status = EventStatus::Submitted;
- QDateTime _lastUpdated = QDateTime::currentDateTimeUtc();
- QString _annotation;
-
- void setStatus(EventStatus::Code status)
- {
- _status = status;
- _lastUpdated = QDateTime::currentDateTimeUtc();
- _annotation.clear();
- }
- };
+private:
+ EventStatus::Code _status = EventStatus::Submitted;
+ QDateTime _lastUpdated = QDateTime::currentDateTimeUtc();
+ QString _annotation;
- inline QDebug& operator<<(QDebug& d, const TimelineItem& ti)
+ void setStatus(EventStatus::Code status)
{
- QDebugStateSaver dss(d);
- d.nospace() << "(" << ti.index() << "|" << ti->id() << ")";
- return d;
+ _status = status;
+ _lastUpdated = QDateTime::currentDateTimeUtc();
+ _annotation.clear();
}
+};
+
+inline QDebug& operator<<(QDebug& d, const TimelineItem& ti)
+{
+ QDebugStateSaver dss(d);
+ d.nospace() << "(" << ti.index() << "|" << ti->id() << ")";
+ return d;
}
+} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::EventStatus)
diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h
index 0cf2dc60..abab9867 100644
--- a/lib/events/accountdataevents.h
+++ b/lib/events/accountdataevents.h
@@ -24,76 +24,81 @@
#include "event.h"
#include "eventcontent.h"
-namespace QMatrixClient {
- constexpr const char* FavouriteTag = "m.favourite";
- constexpr const char* LowPriorityTag = "m.lowpriority";
+namespace QMatrixClient
+{
+constexpr const char* FavouriteTag = "m.favourite";
+constexpr const char* LowPriorityTag = "m.lowpriority";
- struct TagRecord {
- using order_type = Omittable<float>;
+struct TagRecord
+{
+ using order_type = Omittable<float>;
- order_type order;
+ order_type order;
- TagRecord(order_type order = none) : order(order) {}
+ TagRecord(order_type order = none)
+ : order(order)
+ {}
- bool operator<(const TagRecord& other) const
- {
- // Per The Spec, rooms with no order should be after those with
- // order
- return !order.omitted()
- && (other.order.omitted()
- || order.value() < other.order.value());
- }
- };
+ bool operator<(const TagRecord& other) const
+ {
+ // Per The Spec, rooms with no order should be after those with order
+ return !order.omitted()
+ && (other.order.omitted() || order.value() < other.order.value());
+ }
+};
- template <> struct JsonObjectConverter<TagRecord> {
- static void fillFrom(const QJsonObject& jo, TagRecord& rec)
- {
- // Parse a float both from JSON double and JSON string because
- // libqmatrixclient previously used to use strings to store order.
- const auto orderJv = jo.value("order"_ls);
- if (orderJv.isDouble())
- rec.order = fromJson<float>(orderJv);
- if (orderJv.isString()) {
- bool ok;
- rec.order = orderJv.toString().toFloat(&ok);
- if (!ok)
- rec.order = none;
- }
- }
- static void dumpTo(QJsonObject& jo, const TagRecord& rec)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("order"), rec.order);
+template <>
+struct JsonObjectConverter<TagRecord>
+{
+ static void fillFrom(const QJsonObject& jo, TagRecord& rec)
+ {
+ // Parse a float both from JSON double and JSON string because
+ // libqmatrixclient previously used to use strings to store order.
+ const auto orderJv = jo.value("order"_ls);
+ if (orderJv.isDouble())
+ rec.order = fromJson<float>(orderJv);
+ if (orderJv.isString()) {
+ bool ok;
+ rec.order = orderJv.toString().toFloat(&ok);
+ if (!ok)
+ rec.order = none;
}
- };
+ }
+ static void dumpTo(QJsonObject& jo, const TagRecord& rec)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("order"), rec.order);
+ }
+};
- using TagsMap = QHash<QString, TagRecord>;
+using TagsMap = QHash<QString, TagRecord>;
-#define DEFINE_SIMPLE_EVENT(_Name, _TypeId, _ContentType, _ContentKey) \
- class _Name : public Event \
- { \
- public: \
- using content_type = _ContentType; \
- DEFINE_EVENT_TYPEID(_TypeId, _Name) \
- explicit _Name(QJsonObject obj) : Event(typeId(), std::move(obj)) {} \
- explicit _Name(_ContentType content) \
- : Event(typeId(), matrixTypeId(), \
- QJsonObject { { QStringLiteral(#_ContentKey), \
- toJson(std::move(content)) } }) \
- { \
- } \
- auto _ContentKey() const \
- { \
- return fromJson<content_type>(contentJson()[#_ContentKey##_ls]); \
- } \
- }; \
- REGISTER_EVENT_TYPE(_Name) \
+#define DEFINE_SIMPLE_EVENT(_Name, _TypeId, _ContentType, _ContentKey) \
+ class _Name : public Event \
+ { \
+ public: \
+ using content_type = _ContentType; \
+ DEFINE_EVENT_TYPEID(_TypeId, _Name) \
+ explicit _Name(QJsonObject obj) \
+ : Event(typeId(), std::move(obj)) \
+ {} \
+ explicit _Name(_ContentType content) \
+ : Event(typeId(), matrixTypeId(), \
+ QJsonObject { { QStringLiteral(#_ContentKey), \
+ toJson(std::move(content)) } }) \
+ {} \
+ auto _ContentKey() const \
+ { \
+ return content<content_type>(#_ContentKey##_ls); \
+ } \
+ }; \
+ REGISTER_EVENT_TYPE(_Name) \
// End of macro
- DEFINE_SIMPLE_EVENT(TagEvent, "m.tag", TagsMap, tags)
- DEFINE_SIMPLE_EVENT(ReadMarkerEvent, "m.fully_read", QString, event_id)
- DEFINE_SIMPLE_EVENT(IgnoredUsersEvent, "m.ignored_user_list", QSet<QString>,
- ignored_users)
+DEFINE_SIMPLE_EVENT(TagEvent, "m.tag", TagsMap, tags)
+DEFINE_SIMPLE_EVENT(ReadMarkerEvent, "m.fully_read", QString, event_id)
+DEFINE_SIMPLE_EVENT(IgnoredUsersEvent, "m.ignored_user_list", QSet<QString>,
+ ignored_users)
- DEFINE_EVENTTYPE_ALIAS(Tag, TagEvent)
- DEFINE_EVENTTYPE_ALIAS(ReadMarker, ReadMarkerEvent)
-}
+DEFINE_EVENTTYPE_ALIAS(Tag, TagEvent)
+DEFINE_EVENTTYPE_ALIAS(ReadMarker, ReadMarkerEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/callanswerevent.cpp b/lib/events/callanswerevent.cpp
index 91e164ad..7ab4a6fb 100644
--- a/lib/events/callanswerevent.cpp
+++ b/lib/events/callanswerevent.cpp
@@ -19,7 +19,6 @@
#include "callanswerevent.h"
#include "event.h"
-
#include "logging.h"
#include <QtCore/QJsonDocument>
@@ -55,20 +54,18 @@ CallAnswerEvent::CallAnswerEvent(const QJsonObject& obj)
CallAnswerEvent::CallAnswerEvent(const QString& callId, const int lifetime,
const QString& sdp)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("lifetime"), lifetime },
- { QStringLiteral("answer"),
- QJsonObject { { QStringLiteral("type"),
- QStringLiteral("answer") },
- { QStringLiteral("sdp"), sdp } } } })
-{
-}
+ : CallEventBase(
+ typeId(), matrixTypeId(), callId, 0,
+ { { QStringLiteral("lifetime"), lifetime },
+ { QStringLiteral("answer"),
+ QJsonObject { { QStringLiteral("type"), QStringLiteral("answer") },
+ { QStringLiteral("sdp"), sdp } } } })
+{}
CallAnswerEvent::CallAnswerEvent(const QString& callId, const QString& sdp)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("answer"),
- QJsonObject { { QStringLiteral("type"),
- QStringLiteral("answer") },
- { QStringLiteral("sdp"), sdp } } } })
-{
-}
+ : CallEventBase(
+ typeId(), matrixTypeId(), callId, 0,
+ { { QStringLiteral("answer"),
+ QJsonObject { { QStringLiteral("type"), QStringLiteral("answer") },
+ { QStringLiteral("sdp"), sdp } } } })
+{}
diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h
index f222803b..69662eb9 100644
--- a/lib/events/callanswerevent.h
+++ b/lib/events/callanswerevent.h
@@ -20,31 +20,29 @@
#include "roomevent.h"
-namespace QMatrixClient {
- class CallAnswerEvent : public CallEventBase
- {
- public:
- DEFINE_EVENT_TYPEID("m.call.answer", CallAnswerEvent)
+namespace QMatrixClient
+{
+class CallAnswerEvent : public CallEventBase
+{
+public:
+ DEFINE_EVENT_TYPEID("m.call.answer", CallAnswerEvent)
- explicit CallAnswerEvent(const QJsonObject& obj);
+ explicit CallAnswerEvent(const QJsonObject& obj);
- explicit CallAnswerEvent(const QString& callId, const int lifetime,
- const QString& sdp);
- explicit CallAnswerEvent(const QString& callId, const QString& sdp);
+ explicit CallAnswerEvent(const QString& callId, const int lifetime,
+ const QString& sdp);
+ explicit CallAnswerEvent(const QString& callId, const QString& sdp);
- int lifetime() const
- {
- return content<int>("lifetime"_ls);
- } // FIXME: Omittable<>?
- QString sdp() const
- {
- return contentJson()["answer"_ls]
- .toObject()
- .value("sdp"_ls)
- .toString();
- }
- };
+ int lifetime() const
+ {
+ return content<int>("lifetime"_ls);
+ } // FIXME: Omittable<>?
+ QString sdp() const
+ {
+ return contentJson()["answer"_ls].toObject().value("sdp"_ls).toString();
+ }
+};
- REGISTER_EVENT_TYPE(CallAnswerEvent)
- DEFINE_EVENTTYPE_ALIAS(CallAnswer, CallAnswerEvent)
+REGISTER_EVENT_TYPE(CallAnswerEvent)
+DEFINE_EVENTTYPE_ALIAS(CallAnswer, CallAnswerEvent)
} // namespace QMatrixClient
diff --git a/lib/events/callcandidatesevent.h b/lib/events/callcandidatesevent.h
index e66e0c09..1c12b800 100644
--- a/lib/events/callcandidatesevent.h
+++ b/lib/events/callcandidatesevent.h
@@ -20,30 +20,29 @@
#include "roomevent.h"
-namespace QMatrixClient {
- class CallCandidatesEvent : public CallEventBase
- {
- public:
- DEFINE_EVENT_TYPEID("m.call.candidates", CallCandidatesEvent)
+namespace QMatrixClient
+{
+class CallCandidatesEvent : public CallEventBase
+{
+public:
+ DEFINE_EVENT_TYPEID("m.call.candidates", CallCandidatesEvent)
- explicit CallCandidatesEvent(const QJsonObject& obj)
- : CallEventBase(typeId(), obj)
- {
- }
+ explicit CallCandidatesEvent(const QJsonObject& obj)
+ : CallEventBase(typeId(), obj)
+ {}
- explicit CallCandidatesEvent(const QString& callId,
- const QJsonArray& candidates)
- : CallEventBase(typeId(), matrixTypeId(), callId, 0,
- { { QStringLiteral("candidates"), candidates } })
- {
- }
+ explicit CallCandidatesEvent(const QString& callId,
+ const QJsonArray& candidates)
+ : CallEventBase(typeId(), matrixTypeId(), callId, 0,
+ { { QStringLiteral("candidates"), candidates } })
+ {}
- QJsonArray candidates() const
- {
- return content<QJsonArray>("candidates"_ls);
- }
- };
+ QJsonArray candidates() const
+ {
+ return content<QJsonArray>("candidates"_ls);
+ }
+};
- REGISTER_EVENT_TYPE(CallCandidatesEvent)
- DEFINE_EVENTTYPE_ALIAS(CallCandidates, CallCandidatesEvent)
-}
+REGISTER_EVENT_TYPE(CallCandidatesEvent)
+DEFINE_EVENTTYPE_ALIAS(CallCandidates, CallCandidatesEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/callhangupevent.cpp b/lib/events/callhangupevent.cpp
index 80844f2d..2a4fd3da 100644
--- a/lib/events/callhangupevent.cpp
+++ b/lib/events/callhangupevent.cpp
@@ -19,7 +19,6 @@
#include "callhangupevent.h"
#include "event.h"
-
#include "logging.h"
#include <QtCore/QJsonDocument>
@@ -50,5 +49,4 @@ CallHangupEvent::CallHangupEvent(const QJsonObject& obj)
CallHangupEvent::CallHangupEvent(const QString& callId)
: CallEventBase(typeId(), matrixTypeId(), callId, 0)
-{
-}
+{}
diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h
index 3c3910be..0a5a3283 100644
--- a/lib/events/callhangupevent.h
+++ b/lib/events/callhangupevent.h
@@ -20,16 +20,17 @@
#include "roomevent.h"
-namespace QMatrixClient {
- class CallHangupEvent : public CallEventBase
- {
- public:
- DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent)
+namespace QMatrixClient
+{
+class CallHangupEvent : public CallEventBase
+{
+public:
+ DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent)
- explicit CallHangupEvent(const QJsonObject& obj);
- explicit CallHangupEvent(const QString& callId);
- };
+ explicit CallHangupEvent(const QJsonObject& obj);
+ explicit CallHangupEvent(const QString& callId);
+};
- REGISTER_EVENT_TYPE(CallHangupEvent)
- DEFINE_EVENTTYPE_ALIAS(CallHangup, CallHangupEvent)
-}
+REGISTER_EVENT_TYPE(CallHangupEvent)
+DEFINE_EVENTTYPE_ALIAS(CallHangup, CallHangupEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/callinviteevent.cpp b/lib/events/callinviteevent.cpp
index 2459c093..f565fc3e 100644
--- a/lib/events/callinviteevent.cpp
+++ b/lib/events/callinviteevent.cpp
@@ -19,7 +19,6 @@
#include "callinviteevent.h"
#include "event.h"
-
#include "logging.h"
#include <QtCore/QJsonDocument>
@@ -55,11 +54,10 @@ CallInviteEvent::CallInviteEvent(const QJsonObject& obj)
CallInviteEvent::CallInviteEvent(const QString& callId, const int lifetime,
const QString& sdp)
- : CallEventBase(typeId(), matrixTypeId(), callId, lifetime,
- { { QStringLiteral("lifetime"), lifetime },
- { QStringLiteral("offer"),
- QJsonObject { { QStringLiteral("type"),
- QStringLiteral("offer") },
- { QStringLiteral("sdp"), sdp } } } })
-{
-}
+ : CallEventBase(
+ typeId(), matrixTypeId(), callId, lifetime,
+ { { QStringLiteral("lifetime"), lifetime },
+ { QStringLiteral("offer"),
+ QJsonObject { { QStringLiteral("type"), QStringLiteral("offer") },
+ { QStringLiteral("sdp"), sdp } } } })
+{}
diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h
index 911ccf96..4334ca5b 100644
--- a/lib/events/callinviteevent.h
+++ b/lib/events/callinviteevent.h
@@ -20,30 +20,28 @@
#include "roomevent.h"
-namespace QMatrixClient {
- class CallInviteEvent : public CallEventBase
- {
- public:
- DEFINE_EVENT_TYPEID("m.call.invite", CallInviteEvent)
+namespace QMatrixClient
+{
+class CallInviteEvent : public CallEventBase
+{
+public:
+ DEFINE_EVENT_TYPEID("m.call.invite", CallInviteEvent)
- explicit CallInviteEvent(const QJsonObject& obj);
+ explicit CallInviteEvent(const QJsonObject& obj);
- explicit CallInviteEvent(const QString& callId, const int lifetime,
- const QString& sdp);
+ explicit CallInviteEvent(const QString& callId, const int lifetime,
+ const QString& sdp);
- int lifetime() const
- {
- return content<int>("lifetime"_ls);
- } // FIXME: Omittable<>?
- QString sdp() const
- {
- return contentJson()["offer"_ls]
- .toObject()
- .value("sdp"_ls)
- .toString();
- }
- };
+ int lifetime() const
+ {
+ return content<int>("lifetime"_ls);
+ } // FIXME: Omittable<>?
+ QString sdp() const
+ {
+ return contentJson()["offer"_ls].toObject().value("sdp"_ls).toString();
+ }
+};
- REGISTER_EVENT_TYPE(CallInviteEvent)
- DEFINE_EVENTTYPE_ALIAS(CallInvite, CallInviteEvent)
-}
+REGISTER_EVENT_TYPE(CallInviteEvent)
+DEFINE_EVENTTYPE_ALIAS(CallInvite, CallInviteEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h
index 0d8b8f74..6b4a08ee 100644
--- a/lib/events/directchatevent.h
+++ b/lib/events/directchatevent.h
@@ -20,18 +20,19 @@
#include "event.h"
-namespace QMatrixClient {
- class DirectChatEvent : public Event
- {
- public:
- DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent)
+namespace QMatrixClient
+{
+class DirectChatEvent : public Event
+{
+public:
+ DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent)
- explicit DirectChatEvent(const QJsonObject& obj) : Event(typeId(), obj)
- {
- }
+ explicit DirectChatEvent(const QJsonObject& obj)
+ : Event(typeId(), obj)
+ {}
- QMultiHash<QString, QString> usersToDirectChats() const;
- };
- REGISTER_EVENT_TYPE(DirectChatEvent)
- DEFINE_EVENTTYPE_ALIAS(DirectChat, DirectChatEvent)
-}
+ QMultiHash<QString, QString> usersToDirectChats() const;
+};
+REGISTER_EVENT_TYPE(DirectChatEvent)
+DEFINE_EVENTTYPE_ALIAS(DirectChat, DirectChatEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/event.cpp b/lib/events/event.cpp
index f44b1e5d..718a6602 100644
--- a/lib/events/event.cpp
+++ b/lib/events/event.cpp
@@ -38,10 +38,13 @@ event_type_t EventTypeRegistry::initializeTypeId(event_mtype_t matrixTypeId)
QString EventTypeRegistry::getMatrixType(event_type_t typeId)
{
- return typeId < get().eventTypes.size() ? get().eventTypes[typeId] : "";
+ return typeId < get().eventTypes.size() ? get().eventTypes[typeId]
+ : QString();
}
-Event::Event(Type type, const QJsonObject& json) : _type(type), _json(json)
+Event::Event(Type type, const QJsonObject& json)
+ : _type(type)
+ , _json(json)
{
if (!json.contains(ContentKeyL)
&& !json.value(UnsignedKeyL).toObject().contains(RedactedCauseKeyL)) {
@@ -50,11 +53,9 @@ Event::Event(Type type, const QJsonObject& json) : _type(type), _json(json)
}
}
-Event::Event(Type type, event_mtype_t matrixType,
- const QJsonObject& contentJson)
+Event::Event(Type type, event_mtype_t matrixType, const QJsonObject& contentJson)
: Event(type, basicEventJson(matrixType, contentJson))
-{
-}
+{}
Event::~Event() = default;
diff --git a/lib/events/event.h b/lib/events/event.h
index a0f12b75..9dcec1ae 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -22,375 +22,396 @@
#include "logging.h"
#ifdef ENABLE_EVENTTYPE_ALIAS
-#define USE_EVENTTYPE_ALIAS 1
+# define USE_EVENTTYPE_ALIAS 1
#endif
-namespace QMatrixClient {
- // === event_ptr_tt<> and type casting facilities ===
-
- template <typename EventT> using event_ptr_tt = std::unique_ptr<EventT>;
+namespace QMatrixClient
+{
+// === event_ptr_tt<> and type casting facilities ===
+
+template <typename EventT>
+using event_ptr_tt = std::unique_ptr<EventT>;
+
+/// Unwrap a plain pointer from a smart pointer
+template <typename EventT>
+inline EventT* rawPtr(const event_ptr_tt<EventT>& ptr)
+{
+ return ptr.get();
+}
+
+/// Unwrap a plain pointer and downcast it to the specified type
+template <typename TargetEventT, typename EventT>
+inline TargetEventT* weakPtrCast(const event_ptr_tt<EventT>& ptr)
+{
+ return static_cast<TargetEventT*>(rawPtr(ptr));
+}
+
+/// Re-wrap a smart pointer to base into a smart pointer to derived
+template <typename TargetT, typename SourceT>
+[[deprecated("Consider using eventCast() or visit() "
+ "instead")]] inline event_ptr_tt<TargetT>
+ptrCast(event_ptr_tt<SourceT>&& ptr)
+{
+ return unique_ptr_cast<TargetT>(ptr);
+}
+
+// === Standard Matrix key names and basicEventJson() ===
+
+static const auto TypeKey = QStringLiteral("type");
+static const auto ContentKey = QStringLiteral("content");
+static const auto EventIdKey = QStringLiteral("event_id");
+static const auto UnsignedKey = QStringLiteral("unsigned");
+static const auto TypeKeyL = "type"_ls;
+static const auto ContentKeyL = "content"_ls;
+static const auto EventIdKeyL = "event_id"_ls;
+static const auto UnsignedKeyL = "unsigned"_ls;
+static const auto RedactedCauseKeyL = "redacted_because"_ls;
+static const auto PrevContentKeyL = "prev_content"_ls;
+
+// Minimal correct Matrix event JSON
+template <typename StrT>
+inline QJsonObject basicEventJson(StrT matrixType, const QJsonObject& content)
+{
+ return { { TypeKey, std::forward<StrT>(matrixType) },
+ { ContentKey, content } };
+}
+
+// === Event types and event types registry ===
+
+using event_type_t = size_t;
+using event_mtype_t = const char*;
+
+class EventTypeRegistry
+{
+public:
+ ~EventTypeRegistry() = default;
+
+ static event_type_t initializeTypeId(event_mtype_t matrixTypeId);
template <typename EventT>
- inline EventT* rawPtr(const event_ptr_tt<EventT>& ptr) // unwrap
+ static inline event_type_t initializeTypeId()
{
- return ptr.get();
+ return initializeTypeId(EventT::matrixTypeId());
}
- template <typename TargetEventT, typename EventT>
- inline TargetEventT* weakPtrCast(const event_ptr_tt<EventT>& ptr)
- {
- return static_cast<TargetEventT*>(rawPtr(ptr));
- }
+ static QString getMatrixType(event_type_t typeId);
- template <typename TargetT, typename SourceT>
- inline event_ptr_tt<TargetT> ptrCast(event_ptr_tt<SourceT>&& ptr)
- {
- return unique_ptr_cast<TargetT>(ptr);
- }
+private:
+ EventTypeRegistry() = default;
+ Q_DISABLE_COPY(EventTypeRegistry)
+ DISABLE_MOVE(EventTypeRegistry)
- // === Standard Matrix key names and basicEventJson() ===
-
- static const auto TypeKey = QStringLiteral("type");
- static const auto ContentKey = QStringLiteral("content");
- static const auto EventIdKey = QStringLiteral("event_id");
- static const auto UnsignedKey = QStringLiteral("unsigned");
- static const auto TypeKeyL = "type"_ls;
- static const auto ContentKeyL = "content"_ls;
- static const auto EventIdKeyL = "event_id"_ls;
- static const auto UnsignedKeyL = "unsigned"_ls;
- static const auto RedactedCauseKeyL = "redacted_because"_ls;
- static const auto PrevContentKeyL = "prev_content"_ls;
-
- // Minimal correct Matrix event JSON
- template <typename StrT>
- inline QJsonObject basicEventJson(StrT matrixType,
- const QJsonObject& content)
+ static EventTypeRegistry& get()
{
- return { { TypeKey, std::forward<StrT>(matrixType) },
- { ContentKey, content } };
+ static EventTypeRegistry etr;
+ return etr;
}
- // === Event types and event types registry ===
+ std::vector<event_mtype_t> eventTypes;
+};
- using event_type_t = size_t;
- using event_mtype_t = const char*;
+template <>
+inline event_type_t EventTypeRegistry::initializeTypeId<void>()
+{
+ return initializeTypeId("");
+}
- class EventTypeRegistry
+template <typename EventT>
+struct EventTypeTraits
+{
+ static event_type_t id()
{
- public:
- ~EventTypeRegistry() = default;
-
- static event_type_t initializeTypeId(event_mtype_t matrixTypeId);
-
- template <typename EventT> static inline event_type_t initializeTypeId()
- {
- return initializeTypeId(EventT::matrixTypeId());
- }
-
- static QString getMatrixType(event_type_t typeId);
-
- private:
- EventTypeRegistry() = default;
- Q_DISABLE_COPY(EventTypeRegistry)
- DISABLE_MOVE(EventTypeRegistry)
-
- static EventTypeRegistry& get()
- {
- static EventTypeRegistry etr;
- return etr;
- }
-
- std::vector<event_mtype_t> eventTypes;
- };
-
- template <> inline event_type_t EventTypeRegistry::initializeTypeId<void>()
- {
- return initializeTypeId("");
+ static const auto id = EventTypeRegistry::initializeTypeId<EventT>();
+ return id;
}
-
- template <typename EventT> struct EventTypeTraits {
- static event_type_t id()
- {
- static const auto id =
- EventTypeRegistry::initializeTypeId<EventT>();
- return id;
- }
- };
-
- template <typename EventT> inline event_type_t typeId()
+};
+
+template <typename EventT>
+inline event_type_t typeId()
+{
+ return EventTypeTraits<std::decay_t<EventT>>::id();
+}
+
+inline event_type_t unknownEventTypeId() { return typeId<void>(); }
+
+// === EventFactory ===
+
+/** Create an event of arbitrary type from its arguments */
+template <typename EventT, typename... ArgTs>
+inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args)
+{
+ return std::make_unique<EventT>(std::forward<ArgTs>(args)...);
+}
+
+template <typename BaseEventT>
+class EventFactory
+{
+public:
+ template <typename FnT>
+ static auto addMethod(FnT&& method)
{
- return EventTypeTraits<std::decay_t<EventT>>::id();
+ factories().emplace_back(std::forward<FnT>(method));
+ return 0;
}
- inline event_type_t unknownEventTypeId() { return typeId<void>(); }
-
- // === EventFactory ===
-
- /** Create an event of arbitrary type from its arguments */
- template <typename EventT, typename... ArgTs>
- inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args)
- {
- return std::make_unique<EventT>(std::forward<ArgTs>(args)...);
- }
-
- template <typename BaseEventT> class EventFactory
- {
- public:
- template <typename FnT> static auto addMethod(FnT&& method)
- {
- factories().emplace_back(std::forward<FnT>(method));
- return 0;
- }
-
- /** Chain two type factories
- * Adds the factory class of EventT2 (EventT2::factory_t) to
- * the list in factory class of EventT1 (EventT1::factory_t) so
- * that when EventT1::factory_t::make() is invoked, types of
- * EventT2 factory are looked through as well. This is used
- * to include RoomEvent types into the more general Event factory,
- * and state event types into the RoomEvent factory.
- */
- template <typename EventT> static auto chainFactory()
- {
- return addMethod(&EventT::factory_t::make);
- }
-
- static event_ptr_tt<BaseEventT> make(const QJsonObject& json,
- const QString& matrixType)
- {
- for (const auto& f : factories())
- if (auto e = f(json, matrixType))
- return e;
- return nullptr;
- }
-
- private:
- static auto& factories()
- {
- using inner_factory_tt = std::function<event_ptr_tt<BaseEventT>(
- const QJsonObject&, const QString&)>;
- static std::vector<inner_factory_tt> _factories {};
- return _factories;
- }
- };
-
- /** Add a type to its default factory
- * Adds a standard factory method (via makeEvent<>) for a given
- * type to EventT::factory_t factory class so that it can be
- * created dynamically from loadEvent<>().
- *
- * \tparam EventT the type to enable dynamic creation of
- * \return the registered type id
- * \sa loadEvent, Event::type
+ /** Chain two type factories
+ * Adds the factory class of EventT2 (EventT2::factory_t) to
+ * the list in factory class of EventT1 (EventT1::factory_t) so
+ * that when EventT1::factory_t::make() is invoked, types of
+ * EventT2 factory are looked through as well. This is used
+ * to include RoomEvent types into the more general Event factory,
+ * and state event types into the RoomEvent factory.
*/
- template <typename EventT> inline auto setupFactory()
+ template <typename EventT>
+ static auto chainFactory()
{
- qDebug(EVENTS) << "Adding factory method for" << EventT::matrixTypeId();
- return EventT::factory_t::addMethod(
- [](const QJsonObject& json, const QString& jsonMatrixType) {
- return EventT::matrixTypeId() == jsonMatrixType
- ? makeEvent<EventT>(json)
- : nullptr;
- });
+ return addMethod(&EventT::factory_t::make);
}
- template <typename EventT> inline auto registerEventType()
+ static event_ptr_tt<BaseEventT> make(const QJsonObject& json,
+ const QString& matrixType)
{
- // Initialise exactly once, even if this function is called twice for
- // the same type (for whatever reason - you never know the ways of
- // static initialisation is done).
- static const auto _ = setupFactory<EventT>();
- return _; // Only to facilitate usage in static initialisation
+ for (const auto& f : factories())
+ if (auto e = f(json, matrixType))
+ return e;
+ return nullptr;
}
- // === Event ===
-
- class Event
+private:
+ static auto& factories()
{
- Q_GADGET
- Q_PROPERTY(Type type READ type CONSTANT)
- Q_PROPERTY(QJsonObject contentJson READ contentJson CONSTANT)
- public:
- using Type = event_type_t;
- using factory_t = EventFactory<Event>;
-
- explicit Event(Type type, const QJsonObject& json);
- explicit Event(Type type, event_mtype_t matrixType,
- const QJsonObject& contentJson = {});
- Q_DISABLE_COPY(Event)
- Event(Event&&) = default;
- Event& operator=(Event&&) = delete;
- virtual ~Event();
-
- Type type() const { return _type; }
- QString matrixType() const;
- QByteArray originalJson() const;
- QJsonObject originalJsonObject() const { return fullJson(); }
-
- const QJsonObject& fullJson() const { return _json; }
-
- // According to the CS API spec, every event also has
- // a "content" object; but since its structure is different for
- // different types, we're implementing it per-event type.
-
- const QJsonObject contentJson() const;
- const QJsonObject unsignedJson() const;
-
- template <typename T> T content(const QString& key) const
- {
- return fromJson<T>(contentJson()[key]);
- }
-
- template <typename T> T content(const QLatin1String& key) const
- {
- return fromJson<T>(contentJson()[key]);
- }
-
- friend QDebug operator<<(QDebug dbg, const Event& e)
- {
- QDebugStateSaver _dss { dbg };
- dbg.noquote().nospace()
- << e.matrixType() << '(' << e.type() << "): ";
- e.dumpTo(dbg);
- return dbg;
- }
-
- virtual bool isStateEvent() const { return false; }
- virtual bool isCallEvent() const { return false; }
- virtual void dumpTo(QDebug dbg) const;
-
- protected:
- QJsonObject& editJson() { return _json; }
-
- private:
- Type _type;
- QJsonObject _json;
- };
- using EventPtr = event_ptr_tt<Event>;
-
- template <typename EventT>
- using EventsArray = std::vector<event_ptr_tt<EventT>>;
- using Events = EventsArray<Event>;
-
- // === Macros used with event class definitions ===
-
- // This macro should be used in a public section of an event class to
- // provide matrixTypeId() and typeId().
-#define DEFINE_EVENT_TYPEID(_Id, _Type) \
- static constexpr event_mtype_t matrixTypeId() { return _Id; } \
- static auto typeId() { return QMatrixClient::typeId<_Type>(); } \
- // End of macro
-
- // This macro should be put after an event class definition (in .h or .cpp)
- // to enable its deserialisation from a /sync and other
- // polymorphic event arrays
-#define REGISTER_EVENT_TYPE(_Type) \
- namespace { \
- [[gnu::unused]] static const auto _factoryAdded##_Type = \
- registerEventType<_Type>(); \
- } \
- // End of macro
-
-#ifdef USE_EVENTTYPE_ALIAS
- namespace EventType {
- inline event_type_t logEventType(event_type_t id, const char* idName)
- {
- qDebug(EVENTS) << "Using id" << id << "for" << idName;
- return id;
- }
+ using inner_factory_tt = std::function<event_ptr_tt<BaseEventT>(
+ const QJsonObject&, const QString&)>;
+ static std::vector<inner_factory_tt> _factories {};
+ return _factories;
}
+};
- // This macro provides constants in EventType:: namespace for
- // back-compatibility with libQMatrixClient 0.3 event type system.
-#define DEFINE_EVENTTYPE_ALIAS(_Id, _Type) \
- namespace EventType { \
- [[deprecated( \
- "Use is<>(), eventCast<>() or visit<>()")]] static const auto \
- _Id = logEventType(typeId<_Type>(), #_Id); \
- } \
- // End of macro
-#else
-#define DEFINE_EVENTTYPE_ALIAS(_Id, _Type) // Nothing
-#endif
-
- // === is<>(), eventCast<>() and visit<>() ===
-
- template <typename EventT> inline bool is(const Event& e)
+/** Add a type to its default factory
+ * Adds a standard factory method (via makeEvent<>) for a given
+ * type to EventT::factory_t factory class so that it can be
+ * created dynamically from loadEvent<>().
+ *
+ * \tparam EventT the type to enable dynamic creation of
+ * \return the registered type id
+ * \sa loadEvent, Event::type
+ */
+template <typename EventT>
+inline auto setupFactory()
+{
+ qDebug(EVENTS) << "Adding factory method for" << EventT::matrixTypeId();
+ return EventT::factory_t::addMethod([](const QJsonObject& json,
+ const QString& jsonMatrixType) {
+ return EventT::matrixTypeId() == jsonMatrixType ? makeEvent<EventT>(json)
+ : nullptr;
+ });
+}
+
+template <typename EventT>
+inline auto registerEventType()
+{
+ // Initialise exactly once, even if this function is called twice for
+ // the same type (for whatever reason - you never know the ways of
+ // static initialisation is done).
+ static const auto _ = setupFactory<EventT>();
+ return _; // Only to facilitate usage in static initialisation
+}
+
+// === Event ===
+
+class Event
+{
+ Q_GADGET
+ Q_PROPERTY(Type type READ type CONSTANT)
+ Q_PROPERTY(QJsonObject contentJson READ contentJson CONSTANT)
+public:
+ using Type = event_type_t;
+ using factory_t = EventFactory<Event>;
+
+ explicit Event(Type type, const QJsonObject& json);
+ explicit Event(Type type, event_mtype_t matrixType,
+ const QJsonObject& contentJson = {});
+ Q_DISABLE_COPY(Event)
+ Event(Event&&) = default;
+ Event& operator=(Event&&) = delete;
+ virtual ~Event();
+
+ Type type() const { return _type; }
+ QString matrixType() const;
+ QByteArray originalJson() const;
+ QJsonObject originalJsonObject() const { return fullJson(); }
+
+ const QJsonObject& fullJson() const { return _json; }
+
+ // According to the CS API spec, every event also has
+ // a "content" object; but since its structure is different for
+ // different types, we're implementing it per-event type.
+
+ const QJsonObject contentJson() const;
+ const QJsonObject unsignedJson() const;
+
+ template <typename T>
+ T content(const QString& key) const
{
- return e.type() == typeId<EventT>();
+ return fromJson<T>(contentJson()[key]);
}
- inline bool isUnknown(const Event& e)
+ template <typename T>
+ T content(const QLatin1String& key) const
{
- return e.type() == unknownEventTypeId();
+ return fromJson<T>(contentJson()[key]);
}
- template <typename EventT, typename BasePtrT>
- inline auto eventCast(const BasePtrT& eptr)
- -> decltype(static_cast<EventT*>(&*eptr))
+ friend QDebug operator<<(QDebug dbg, const Event& e)
{
- Q_ASSERT(eptr);
- return is<std::decay_t<EventT>>(*eptr) ? static_cast<EventT*>(&*eptr)
- : nullptr;
+ QDebugStateSaver _dss { dbg };
+ dbg.noquote().nospace() << e.matrixType() << '(' << e.type() << "): ";
+ e.dumpTo(dbg);
+ return dbg;
}
- // A single generic catch-all visitor
- template <typename BaseEventT, typename FnT>
- inline auto visit(const BaseEventT& event, FnT&& visitor)
- -> decltype(visitor(event))
- {
- return visitor(event);
- }
+ virtual bool isStateEvent() const { return false; }
+ virtual bool isCallEvent() const { return false; }
+ virtual void dumpTo(QDebug dbg) const;
- template <typename T> constexpr auto is_event()
- {
- return std::is_base_of<Event, std::decay_t<T>>::value;
- }
+protected:
+ QJsonObject& editJson() { return _json; }
- template <typename T, typename FnT> constexpr auto needs_cast()
- {
- return !std::is_convertible<T, fn_arg_t<FnT>>::value;
- }
+private:
+ Type _type;
+ QJsonObject _json;
+};
+using EventPtr = event_ptr_tt<Event>;
- // A single type-specific void visitor
- template <typename BaseEventT, typename FnT>
- inline std::enable_if_t<is_event<BaseEventT>()
- && needs_cast<BaseEventT, FnT>()
- && std::is_void<fn_return_t<FnT>>::value>
- visit(const BaseEventT& event, FnT&& visitor)
- {
- using event_type = fn_arg_t<FnT>;
- if (is<std::decay_t<event_type>>(event))
- visitor(static_cast<event_type>(event));
- }
+template <typename EventT>
+using EventsArray = std::vector<event_ptr_tt<EventT>>;
+using Events = EventsArray<Event>;
- // A single type-specific non-void visitor with an optional default value
- template <typename BaseEventT, typename FnT>
- inline std::enable_if_t<
- is_event<BaseEventT>() && needs_cast<BaseEventT, FnT>(),
- fn_return_t<FnT>> // non-voidness is guarded by defaultValue type
- visit(const BaseEventT& event, FnT&& visitor,
- fn_return_t<FnT>&& defaultValue = {})
- {
- using event_type = fn_arg_t<FnT>;
- if (is<std::decay_t<event_type>>(event))
- return visitor(static_cast<event_type>(event));
- return std::forward<fn_return_t<FnT>>(defaultValue);
- }
+// === Macros used with event class definitions ===
+
+// This macro should be used in a public section of an event class to
+// provide matrixTypeId() and typeId().
+#define DEFINE_EVENT_TYPEID(_Id, _Type) \
+ static constexpr event_mtype_t matrixTypeId() { return _Id; } \
+ static auto typeId() { return QMatrixClient::typeId<_Type>(); } \
+ // End of macro
+
+// This macro should be put after an event class definition (in .h or .cpp)
+// to enable its deserialisation from a /sync and other
+// polymorphic event arrays
+#define REGISTER_EVENT_TYPE(_Type) \
+ namespace \
+ { \
+ [[gnu::unused]] static const auto _factoryAdded##_Type = \
+ registerEventType<_Type>(); \
+ } \
+ // End of macro
- // A chain of 2 or more visitors
- template <typename BaseEventT, typename FnT1, typename FnT2,
- typename... FnTs>
- inline std::enable_if_t<is_event<BaseEventT>(), fn_return_t<FnT1>>
- visit(const BaseEventT& event, FnT1&& visitor1, FnT2&& visitor2,
- FnTs&&... visitors)
+#ifdef USE_EVENTTYPE_ALIAS
+namespace EventType
+{
+ inline event_type_t logEventType(event_type_t id, const char* idName)
{
- using event_type1 = fn_arg_t<FnT1>;
- if (is<std::decay_t<event_type1>>(event))
- return visitor1(static_cast<event_type1&>(event));
- return visit(event, std::forward<FnT2>(visitor2),
- std::forward<FnTs>(visitors)...);
+ qDebug(EVENTS) << "Using id" << id << "for" << idName;
+ return id;
}
+} // namespace EventType
+
+// This macro provides constants in EventType:: namespace for
+// back-compatibility with libQMatrixClient 0.3 event type system.
+# define DEFINE_EVENTTYPE_ALIAS(_Id, _Type) \
+ namespace EventType \
+ { \
+ [[deprecated("Use is<>(), eventCast<>() or " \
+ "visit<>()")]] static const auto _Id = \
+ logEventType(typeId<_Type>(), #_Id); \
+ } \
+ // End of macro
+#else
+# define DEFINE_EVENTTYPE_ALIAS(_Id, _Type) // Nothing
+#endif
+
+// === is<>(), eventCast<>() and visit<>() ===
+
+template <typename EventT>
+inline bool is(const Event& e)
+{
+ return e.type() == typeId<EventT>();
+}
+
+inline bool isUnknown(const Event& e)
+{
+ return e.type() == unknownEventTypeId();
+}
+
+template <typename EventT, typename BasePtrT>
+inline auto eventCast(const BasePtrT& eptr)
+ -> decltype(static_cast<EventT*>(&*eptr))
+{
+ Q_ASSERT(eptr);
+ return is<std::decay_t<EventT>>(*eptr) ? static_cast<EventT*>(&*eptr)
+ : nullptr;
+}
+
+// A single generic catch-all visitor
+template <typename BaseEventT, typename FnT>
+inline auto visit(const BaseEventT& event, FnT&& visitor)
+ -> decltype(visitor(event))
+{
+ return visitor(event);
+}
+
+template <typename T>
+constexpr auto is_event()
+{
+ return std::is_base_of<Event, std::decay_t<T>>::value;
+}
+
+template <typename T, typename FnT>
+constexpr auto needs_cast()
+{
+ return !std::is_convertible<T, fn_arg_t<FnT>>::value;
+}
+
+// A single type-specific void visitor
+template <typename BaseEventT, typename FnT>
+inline std::enable_if_t<is_event<BaseEventT>() && needs_cast<BaseEventT, FnT>()
+ && std::is_void<fn_return_t<FnT>>::value>
+visit(const BaseEventT& event, FnT&& visitor)
+{
+ using event_type = fn_arg_t<FnT>;
+ if (is<std::decay_t<event_type>>(event))
+ visitor(static_cast<event_type>(event));
+}
+
+// A single type-specific non-void visitor with an optional default value
+template <typename BaseEventT, typename FnT>
+inline std::enable_if_t<is_event<BaseEventT>() && needs_cast<BaseEventT, FnT>(),
+ fn_return_t<FnT>> // non-voidness is guarded by
+ // defaultValue type
+ visit(const BaseEventT& event,
+ FnT&& visitor,
+ fn_return_t<FnT>&&
+ defaultValue = {})
+{
+ using event_type = fn_arg_t<FnT>;
+ if (is<std::decay_t<event_type>>(event))
+ return visitor(static_cast<event_type>(event));
+ return std::forward<fn_return_t<FnT>>(defaultValue);
+}
+
+// A chain of 2 or more visitors
+template <typename BaseEventT, typename FnT1, typename FnT2, typename... FnTs>
+inline std::enable_if_t<is_event<BaseEventT>(), fn_return_t<FnT1>>
+visit(const BaseEventT& event, FnT1&& visitor1, FnT2&& visitor2,
+ FnTs&&... visitors)
+{
+ using event_type1 = fn_arg_t<FnT1>;
+ if (is<std::decay_t<event_type1>>(event))
+ return visitor1(static_cast<event_type1&>(event));
+ return visit(event, std::forward<FnT2>(visitor2),
+ std::forward<FnTs>(visitors)...);
+}
} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::Event*)
Q_DECLARE_METATYPE(const QMatrixClient::Event*)
diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp
index cc31fea5..2b84c2b7 100644
--- a/lib/events/eventcontent.cpp
+++ b/lib/events/eventcontent.cpp
@@ -34,26 +34,31 @@ QJsonObject Base::toJson() const
FileInfo::FileInfo(const QUrl& u, qint64 payloadSize, const QMimeType& mimeType,
const QString& originalFilename)
- : mimeType(mimeType),
- url(u),
- payloadSize(payloadSize),
- originalName(originalFilename)
-{
-}
+ : mimeType(mimeType)
+ , url(u)
+ , payloadSize(payloadSize)
+ , originalName(originalFilename)
+{}
FileInfo::FileInfo(const QUrl& u, const QJsonObject& infoJson,
const QString& originalFilename)
- : originalInfoJson(infoJson),
- mimeType(QMimeDatabase().mimeTypeForName(
- infoJson["mimetype"_ls].toString())),
- url(u),
- payloadSize(fromJson<qint64>(infoJson["size"_ls])),
- originalName(originalFilename)
+ : originalInfoJson(infoJson)
+ , mimeType(
+ QMimeDatabase().mimeTypeForName(infoJson["mimetype"_ls].toString()))
+ , url(u)
+ , payloadSize(fromJson<qint64>(infoJson["size"_ls]))
+ , originalName(originalFilename)
{
if (!mimeType.isValid())
mimeType = QMimeDatabase().mimeTypeForData(QByteArray());
}
+bool FileInfo::isValid() const
+{
+ return url.scheme() == "mxc"
+ && (url.authority() + url.path()).count('/') == 1;
+}
+
void FileInfo::fillInfoJson(QJsonObject* infoJson) const
{
Q_ASSERT(infoJson);
@@ -65,16 +70,15 @@ void FileInfo::fillInfoJson(QJsonObject* infoJson) const
ImageInfo::ImageInfo(const QUrl& u, qint64 fileSize, QMimeType mimeType,
const QSize& imageSize, const QString& originalFilename)
- : FileInfo(u, fileSize, mimeType, originalFilename), imageSize(imageSize)
-{
-}
+ : FileInfo(u, fileSize, mimeType, originalFilename)
+ , imageSize(imageSize)
+{}
ImageInfo::ImageInfo(const QUrl& u, const QJsonObject& infoJson,
const QString& originalFilename)
- : FileInfo(u, infoJson, originalFilename),
- imageSize(infoJson["w"_ls].toInt(), infoJson["h"_ls].toInt())
-{
-}
+ : FileInfo(u, infoJson, originalFilename)
+ , imageSize(infoJson["w"_ls].toInt(), infoJson["h"_ls].toInt())
+{}
void ImageInfo::fillInfoJson(QJsonObject* infoJson) const
{
@@ -88,8 +92,7 @@ void ImageInfo::fillInfoJson(QJsonObject* infoJson) const
Thumbnail::Thumbnail(const QJsonObject& infoJson)
: ImageInfo(infoJson["thumbnail_url"_ls].toString(),
infoJson["thumbnail_info"_ls].toObject())
-{
-}
+{}
void Thumbnail::fillInfoJson(QJsonObject* infoJson) const
{
diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h
index 857e7369..d2b5e477 100644
--- a/lib/events/eventcontent.h
+++ b/lib/events/eventcontent.h
@@ -26,257 +26,265 @@
#include <QtCore/QSize>
#include <QtCore/QUrl>
-namespace QMatrixClient {
- namespace EventContent {
- /**
- * A base class for all content types that can be stored
- * in a RoomMessageEvent
- *
- * Each content type class should have a constructor taking
- * a QJsonObject and override fillJson() with an implementation
- * that will fill the target QJsonObject with stored values. It is
- * assumed but not required that a content object can also be created
- * from plain data.
- */
- class Base
- {
- public:
- explicit Base(QJsonObject o = {}) : originalJson(std::move(o)) {}
- virtual ~Base() = default;
+namespace QMatrixClient
+{
+namespace EventContent
+{
+ /**
+ * A base class for all content types that can be stored
+ * in a RoomMessageEvent
+ *
+ * Each content type class should have a constructor taking
+ * a QJsonObject and override fillJson() with an implementation
+ * that will fill the target QJsonObject with stored values. It is
+ * assumed but not required that a content object can also be created
+ * from plain data.
+ */
+ class Base
+ {
+ public:
+ explicit Base(QJsonObject o = {})
+ : originalJson(std::move(o))
+ {}
+ virtual ~Base() = default;
+
+ // FIXME: make toJson() from converters.* work on base classes
+ QJsonObject toJson() const;
- // FIXME: make toJson() from converters.* work on base classes
- QJsonObject toJson() const;
+ public:
+ QJsonObject originalJson;
- public:
- QJsonObject originalJson;
+ protected:
+ virtual void fillJson(QJsonObject* o) const = 0;
+ };
- protected:
- virtual void fillJson(QJsonObject* o) const = 0;
- };
+ // The below structures fairly follow CS spec 11.2.1.6. The overall
+ // set of attributes for each content types is a superset of the spec
+ // but specific aggregation structure is altered. See doc comments to
+ // each type for the list of available attributes.
- // The below structures fairly follow CS spec 11.2.1.6. The overall
- // set of attributes for each content types is a superset of the spec
- // but specific aggregation structure is altered. See doc comments to
- // each type for the list of available attributes.
+ // A quick classes inheritance structure follows:
+ // FileInfo
+ // FileContent : UrlBasedContent<FileInfo, Thumbnail>
+ // AudioContent : UrlBasedContent<FileInfo, Duration>
+ // ImageInfo : FileInfo + imageSize attribute
+ // ImageContent : UrlBasedContent<ImageInfo, Thumbnail>
+ // VideoContent : UrlBasedContent<ImageInfo, Thumbnail, Duration>
- // A quick classes inheritance structure follows:
- // FileInfo
- // FileContent : UrlBasedContent<FileInfo, Thumbnail>
- // AudioContent : UrlBasedContent<FileInfo, Duration>
- // ImageInfo : FileInfo + imageSize attribute
- // ImageContent : UrlBasedContent<ImageInfo, Thumbnail>
- // VideoContent : UrlBasedContent<ImageInfo, Thumbnail, Duration>
+ /**
+ * A base/mixin class for structures representing an "info" object for
+ * some content types. These include most attachment types currently in
+ * the CS API spec.
+ *
+ * In order to use it in a content class, derive both from TypedBase
+ * (or Base) and from FileInfo (or its derivative, such as \p ImageInfo)
+ * and call fillInfoJson() to fill the "info" subobject. Make sure
+ * to pass an "info" part of JSON to FileInfo constructor, not the whole
+ * JSON content, as well as contents of "url" (or a similar key) and
+ * optionally "filename" node from the main JSON content. Assuming you
+ * don't do unusual things, you should use \p UrlBasedContent<> instead
+ * of doing multiple inheritance and overriding Base::fillJson() by hand.
+ *
+ * This class is not polymorphic.
+ */
+ class FileInfo
+ {
+ public:
+ explicit FileInfo(const QUrl& u, qint64 payloadSize = -1,
+ const QMimeType& mimeType = {},
+ const QString& originalFilename = {});
+ FileInfo(const QUrl& u, const QJsonObject& infoJson,
+ const QString& originalFilename = {});
+
+ bool isValid() const;
+
+ void fillInfoJson(QJsonObject* infoJson) const;
/**
- * A base/mixin class for structures representing an "info" object for
- * some content types. These include most attachment types currently in
- * the CS API spec.
+ * \brief Extract media id from the URL
*
- * In order to use it in a content class, derive both from TypedBase
- * (or Base) and from FileInfo (or its derivative, such as \p ImageInfo)
- * and call fillInfoJson() to fill the "info" subobject. Make sure
- * to pass an "info" part of JSON to FileInfo constructor, not the whole
- * JSON content, as well as contents of "url" (or a similar key) and
- * optionally "filename" node from the main JSON content. Assuming you
- * don't do unusual things, you should use \p UrlBasedContent<> instead
- * of doing multiple inheritance and overriding Base::fillJson() by
- * hand.
- *
- * This class is not polymorphic.
+ * This can be used, e.g., to construct a QML-facing image://
+ * URI as follows:
+ * \code "image://provider/" + info.mediaId() \endcode
*/
- class FileInfo
- {
- public:
- explicit FileInfo(const QUrl& u, qint64 payloadSize = -1,
- const QMimeType& mimeType = {},
- const QString& originalFilename = {});
- FileInfo(const QUrl& u, const QJsonObject& infoJson,
- const QString& originalFilename = {});
+ QString mediaId() const { return url.authority() + url.path(); }
- void fillInfoJson(QJsonObject* infoJson) const;
+ public:
+ QJsonObject originalInfoJson;
+ QMimeType mimeType;
+ QUrl url;
+ qint64 payloadSize;
+ QString originalName;
+ };
- /**
- * \brief Extract media id from the URL
- *
- * This can be used, e.g., to construct a QML-facing image://
- * URI as follows:
- * \code "image://provider/" + info.mediaId() \endcode
- */
- QString mediaId() const { return url.authority() + url.path(); }
+ template <typename InfoT>
+ QJsonObject toInfoJson(const InfoT& info)
+ {
+ QJsonObject infoJson;
+ info.fillInfoJson(&infoJson);
+ return infoJson;
+ }
- public:
- QJsonObject originalInfoJson;
- QMimeType mimeType;
- QUrl url;
- qint64 payloadSize;
- QString originalName;
- };
+ /**
+ * A content info class for image content types: image, thumbnail, video
+ */
+ class ImageInfo : public FileInfo
+ {
+ public:
+ explicit ImageInfo(const QUrl& u, qint64 fileSize = -1,
+ QMimeType mimeType = {}, const QSize& imageSize = {},
+ const QString& originalFilename = {});
+ ImageInfo(const QUrl& u, const QJsonObject& infoJson,
+ const QString& originalFilename = {});
- template <typename InfoT> QJsonObject toInfoJson(const InfoT& info)
- {
- QJsonObject infoJson;
- info.fillInfoJson(&infoJson);
- return infoJson;
- }
+ void fillInfoJson(QJsonObject* infoJson) const;
- /**
- * A content info class for image content types: image, thumbnail, video
- */
- class ImageInfo : public FileInfo
- {
- public:
- explicit ImageInfo(const QUrl& u, qint64 fileSize = -1,
- QMimeType mimeType = {},
- const QSize& imageSize = {},
- const QString& originalFilename = {});
- ImageInfo(const QUrl& u, const QJsonObject& infoJson,
- const QString& originalFilename = {});
+ public:
+ QSize imageSize;
+ };
- void fillInfoJson(QJsonObject* infoJson) const;
-
- public:
- QSize imageSize;
- };
+ /**
+ * An auxiliary class for an info type that carries a thumbnail
+ *
+ * This class saves/loads a thumbnail to/from "info" subobject of
+ * the JSON representation of event content; namely,
+ * "info/thumbnail_url" and "info/thumbnail_info" fields are used.
+ */
+ class Thumbnail : public ImageInfo
+ {
+ public:
+ Thumbnail()
+ : ImageInfo(QUrl())
+ {} // To allow empty thumbnails
+ Thumbnail(const QJsonObject& infoJson);
+ Thumbnail(const ImageInfo& info)
+ : ImageInfo(info)
+ {}
+ using ImageInfo::ImageInfo;
/**
- * An auxiliary class for an info type that carries a thumbnail
- *
- * This class saves/loads a thumbnail to/from "info" subobject of
- * the JSON representation of event content; namely,
- * "info/thumbnail_url" and "info/thumbnail_info" fields are used.
+ * Writes thumbnail information to "thumbnail_info" subobject
+ * and thumbnail URL to "thumbnail_url" node inside "info".
*/
- class Thumbnail : public ImageInfo
- {
- public:
- Thumbnail() : ImageInfo(QUrl()) {} // To allow empty thumbnails
- Thumbnail(const QJsonObject& infoJson);
- Thumbnail(const ImageInfo& info) : ImageInfo(info) {}
- using ImageInfo::ImageInfo;
+ void fillInfoJson(QJsonObject* infoJson) const;
+ };
- /**
- * Writes thumbnail information to "thumbnail_info" subobject
- * and thumbnail URL to "thumbnail_url" node inside "info".
- */
- void fillInfoJson(QJsonObject* infoJson) const;
- };
+ class TypedBase : public Base
+ {
+ public:
+ explicit TypedBase(const QJsonObject& o = {})
+ : Base(o)
+ {}
+ virtual QMimeType type() const = 0;
+ virtual const FileInfo* fileInfo() const { return nullptr; }
+ virtual FileInfo* fileInfo() { return nullptr; }
+ virtual const Thumbnail* thumbnailInfo() const { return nullptr; }
+ };
- class TypedBase : public Base
+ /**
+ * A base class for content types that have a URL and additional info
+ *
+ * Types that derive from this class template take "url" and,
+ * optionally, "filename" values from the top-level JSON object and
+ * the rest of information from the "info" subobject, as defined by
+ * the parameter type.
+ *
+ * \tparam InfoT base info class
+ */
+ template <class InfoT>
+ class UrlBasedContent : public TypedBase, public InfoT
+ {
+ public:
+ using InfoT::InfoT;
+ explicit UrlBasedContent(const QJsonObject& json)
+ : TypedBase(json)
+ , InfoT(json["url"].toString(), json["info"].toObject(),
+ json["filename"].toString())
{
- public:
- explicit TypedBase(const QJsonObject& o = {}) : Base(o) {}
- virtual QMimeType type() const = 0;
- virtual const FileInfo* fileInfo() const { return nullptr; }
- virtual FileInfo* fileInfo() { return nullptr; }
- virtual const Thumbnail* thumbnailInfo() const { return nullptr; }
- };
-
- /**
- * A base class for content types that have a URL and additional info
- *
- * Types that derive from this class template take "url" and,
- * optionally, "filename" values from the top-level JSON object and
- * the rest of information from the "info" subobject, as defined by
- * the parameter type.
- *
- * \tparam InfoT base info class
- */
- template <class InfoT>
- class UrlBasedContent : public TypedBase, public InfoT
- {
- public:
- using InfoT::InfoT;
- explicit UrlBasedContent(const QJsonObject& json)
- : TypedBase(json),
- InfoT(json["url"].toString(), json["info"].toObject(),
- json["filename"].toString())
- {
- // A small hack to facilitate links creation in QML.
- originalJson.insert("mediaId", InfoT::mediaId());
- }
+ // A small hack to facilitate links creation in QML.
+ originalJson.insert("mediaId", InfoT::mediaId());
+ }
- QMimeType type() const override { return InfoT::mimeType; }
- const FileInfo* fileInfo() const override { return this; }
- FileInfo* fileInfo() override { return this; }
+ QMimeType type() const override { return InfoT::mimeType; }
+ const FileInfo* fileInfo() const override { return this; }
+ FileInfo* fileInfo() override { return this; }
- protected:
- void fillJson(QJsonObject* json) const override
- {
- Q_ASSERT(json);
- json->insert("url", InfoT::url.toString());
- if (!InfoT::originalName.isEmpty())
- json->insert("filename", InfoT::originalName);
- json->insert("info", toInfoJson<InfoT>(*this));
- }
- };
+ protected:
+ void fillJson(QJsonObject* json) const override
+ {
+ Q_ASSERT(json);
+ json->insert("url", InfoT::url.toString());
+ if (!InfoT::originalName.isEmpty())
+ json->insert("filename", InfoT::originalName);
+ json->insert("info", toInfoJson<InfoT>(*this));
+ }
+ };
- template <typename InfoT>
- class UrlWithThumbnailContent : public UrlBasedContent<InfoT>
+ template <typename InfoT>
+ class UrlWithThumbnailContent : public UrlBasedContent<InfoT>
+ {
+ public:
+ using UrlBasedContent<InfoT>::UrlBasedContent;
+ explicit UrlWithThumbnailContent(const QJsonObject& json)
+ : UrlBasedContent<InfoT>(json)
+ , thumbnail(InfoT::originalInfoJson)
{
- public:
- using UrlBasedContent<InfoT>::UrlBasedContent;
- explicit UrlWithThumbnailContent(const QJsonObject& json)
- : UrlBasedContent<InfoT>(json),
- thumbnail(InfoT::originalInfoJson)
- {
- // Another small hack, to simplify making a thumbnail link
- UrlBasedContent<InfoT>::originalJson.insert(
- "thumbnailMediaId", thumbnail.mediaId());
- }
+ // Another small hack, to simplify making a thumbnail link
+ UrlBasedContent<InfoT>::originalJson.insert("thumbnailMediaId",
+ thumbnail.mediaId());
+ }
- const Thumbnail* thumbnailInfo() const override
- {
- return &thumbnail;
- }
+ const Thumbnail* thumbnailInfo() const override { return &thumbnail; }
- public:
- Thumbnail thumbnail;
+ public:
+ Thumbnail thumbnail;
- protected:
- void fillJson(QJsonObject* json) const override
- {
- UrlBasedContent<InfoT>::fillJson(json);
- auto infoJson = json->take("info").toObject();
- thumbnail.fillInfoJson(&infoJson);
- json->insert("info", infoJson);
- }
- };
+ protected:
+ void fillJson(QJsonObject* json) const override
+ {
+ UrlBasedContent<InfoT>::fillJson(json);
+ auto infoJson = json->take("info").toObject();
+ thumbnail.fillInfoJson(&infoJson);
+ json->insert("info", infoJson);
+ }
+ };
- /**
- * Content class for m.image
- *
- * Available fields:
- * - corresponding to the top-level JSON:
- * - url
- * - filename (extension to the spec)
- * - corresponding to the "info" subobject:
- * - payloadSize ("size" in JSON)
- * - mimeType ("mimetype" in JSON)
- * - imageSize (QSize for a combination of "h" and "w" in JSON)
- * - thumbnail.url ("thumbnail_url" in JSON)
- * - corresponding to the "info/thumbnail_info" subobject: contents of
- * thumbnail field, in the same vein as for the main image:
- * - payloadSize
- * - mimeType
- * - imageSize
- */
- using ImageContent = UrlWithThumbnailContent<ImageInfo>;
+ /**
+ * Content class for m.image
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - url
+ * - filename (extension to the spec)
+ * - corresponding to the "info" subobject:
+ * - payloadSize ("size" in JSON)
+ * - mimeType ("mimetype" in JSON)
+ * - imageSize (QSize for a combination of "h" and "w" in JSON)
+ * - thumbnail.url ("thumbnail_url" in JSON)
+ * - corresponding to the "info/thumbnail_info" subobject: contents of
+ * thumbnail field, in the same vein as for the main image:
+ * - payloadSize
+ * - mimeType
+ * - imageSize
+ */
+ using ImageContent = UrlWithThumbnailContent<ImageInfo>;
- /**
- * Content class for m.file
- *
- * Available fields:
- * - corresponding to the top-level JSON:
- * - url
- * - filename
- * - corresponding to the "info" subobject:
- * - payloadSize ("size" in JSON)
- * - mimeType ("mimetype" in JSON)
- * - thumbnail.url ("thumbnail_url" in JSON)
- * - corresponding to the "info/thumbnail_info" subobject:
- * - thumbnail.payloadSize
- * - thumbnail.mimeType
- * - thumbnail.imageSize (QSize for "h" and "w" in JSON)
- */
- using FileContent = UrlWithThumbnailContent<FileInfo>;
- } // namespace EventContent
+ /**
+ * Content class for m.file
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - url
+ * - filename
+ * - corresponding to the "info" subobject:
+ * - payloadSize ("size" in JSON)
+ * - mimeType ("mimetype" in JSON)
+ * - thumbnail.url ("thumbnail_url" in JSON)
+ * - corresponding to the "info/thumbnail_info" subobject:
+ * - thumbnail.payloadSize
+ * - thumbnail.mimeType
+ * - thumbnail.imageSize (QSize for "h" and "w" in JSON)
+ */
+ using FileContent = UrlWithThumbnailContent<FileInfo>;
+} // namespace EventContent
} // namespace QMatrixClient
diff --git a/lib/events/eventloader.h b/lib/events/eventloader.h
index a19a83b6..9c797701 100644
--- a/lib/events/eventloader.h
+++ b/lib/events/eventloader.h
@@ -20,51 +20,54 @@
#include "stateevent.h"
-namespace QMatrixClient {
- namespace _impl {
- template <typename BaseEventT>
- static inline auto loadEvent(const QJsonObject& json,
- const QString& matrixType)
- {
- if (auto e = EventFactory<BaseEventT>::make(json, matrixType))
- return e;
- return makeEvent<BaseEventT>(unknownEventTypeId(), json);
- }
- }
-
- /** Create an event with proper type from a JSON object
- * Use this factory template to detect the type from the JSON object
- * contents (the detected event type should derive from the template
- * parameter type) and create an event object of that type.
- */
+namespace QMatrixClient
+{
+namespace _impl
+{
template <typename BaseEventT>
- inline event_ptr_tt<BaseEventT> loadEvent(const QJsonObject& fullJson)
+ static inline auto loadEvent(const QJsonObject& json,
+ const QString& matrixType)
{
- return _impl::loadEvent<BaseEventT>(fullJson,
- fullJson[TypeKeyL].toString());
+ if (auto e = EventFactory<BaseEventT>::make(json, matrixType))
+ return e;
+ return makeEvent<BaseEventT>(unknownEventTypeId(), json);
}
+} // namespace _impl
- /** Create an event from a type string and content JSON
- * Use this factory template to resolve the C++ type from the Matrix
- * type string in \p matrixType and create an event of that type that has
- * its content part set to \p content.
- */
- template <typename BaseEventT>
- inline event_ptr_tt<BaseEventT> loadEvent(const QString& matrixType,
- const QJsonObject& content)
+/** Create an event with proper type from a JSON object
+ * Use this factory template to detect the type from the JSON object
+ * contents (the detected event type should derive from the template
+ * parameter type) and create an event object of that type.
+ */
+template <typename BaseEventT>
+inline event_ptr_tt<BaseEventT> loadEvent(const QJsonObject& fullJson)
+{
+ return _impl::loadEvent<BaseEventT>(fullJson, fullJson[TypeKeyL].toString());
+}
+
+/** Create an event from a type string and content JSON
+ * Use this factory template to resolve the C++ type from the Matrix
+ * type string in \p matrixType and create an event of that type that has
+ * its content part set to \p content.
+ */
+template <typename BaseEventT>
+inline event_ptr_tt<BaseEventT> loadEvent(const QString& matrixType,
+ const QJsonObject& content)
+{
+ return _impl::loadEvent<BaseEventT>(basicEventJson(matrixType, content),
+ matrixType);
+}
+
+template <typename EventT>
+struct JsonConverter<event_ptr_tt<EventT>>
+{
+ static auto load(const QJsonValue& jv)
{
- return _impl::loadEvent<BaseEventT>(basicEventJson(matrixType, content),
- matrixType);
+ return loadEvent<EventT>(jv.toObject());
}
-
- template <typename EventT> struct JsonConverter<event_ptr_tt<EventT>> {
- static auto load(const QJsonValue& jv)
- {
- return loadEvent<EventT>(jv.toObject());
- }
- static auto load(const QJsonDocument& jd)
- {
- return loadEvent<EventT>(jd.object());
- }
- };
+ static auto load(const QJsonDocument& jd)
+ {
+ return loadEvent<EventT>(jd.object());
+ }
+};
} // namespace QMatrixClient
diff --git a/lib/events/receiptevent.cpp b/lib/events/receiptevent.cpp
index 76c7b6e4..fcb8431b 100644
--- a/lib/events/receiptevent.cpp
+++ b/lib/events/receiptevent.cpp
@@ -40,26 +40,26 @@ Example of a Receipt Event:
using namespace QMatrixClient;
-ReceiptEvent::ReceiptEvent(const QJsonObject& obj) : Event(typeId(), obj)
+ReceiptEvent::ReceiptEvent(const QJsonObject& obj)
+ : Event(typeId(), obj)
{
const auto& contents = contentJson();
_eventsWithReceipts.reserve(contents.size());
- for (auto eventIt = contents.begin(); eventIt != contents.end();
- ++eventIt) {
+ for (auto eventIt = contents.begin(); eventIt != contents.end(); ++eventIt) {
if (eventIt.key().isEmpty()) {
qCWarning(EPHEMERAL)
- << "ReceiptEvent has an empty event id, skipping";
+ << "ReceiptEvent has an empty event id, skipping";
qCDebug(EPHEMERAL) << "ReceiptEvent content follows:\n" << contents;
continue;
}
const QJsonObject reads =
- eventIt.value().toObject().value("m.read"_ls).toObject();
+ eventIt.value().toObject().value("m.read"_ls).toObject();
QVector<Receipt> receipts;
receipts.reserve(reads.size());
for (auto userIt = reads.begin(); userIt != reads.end(); ++userIt) {
const QJsonObject user = userIt.value().toObject();
receipts.push_back(
- { userIt.key(), fromJson<QDateTime>(user["ts"_ls]) });
+ { userIt.key(), fromJson<QDateTime>(user["ts"_ls]) });
}
_eventsWithReceipts.push_back({ eventIt.key(), std::move(receipts) });
}
diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h
index fca38bba..e8396670 100644
--- a/lib/events/receiptevent.h
+++ b/lib/events/receiptevent.h
@@ -23,31 +23,34 @@
#include <QtCore/QDateTime>
#include <QtCore/QVector>
-namespace QMatrixClient {
- struct Receipt {
- QString userId;
- QDateTime timestamp;
- };
- struct ReceiptsForEvent {
- QString evtId;
- QVector<Receipt> receipts;
- };
- using EventsWithReceipts = QVector<ReceiptsForEvent>;
+namespace QMatrixClient
+{
+struct Receipt
+{
+ QString userId;
+ QDateTime timestamp;
+};
+struct ReceiptsForEvent
+{
+ QString evtId;
+ QVector<Receipt> receipts;
+};
+using EventsWithReceipts = QVector<ReceiptsForEvent>;
- class ReceiptEvent : public Event
- {
- public:
- DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent)
- explicit ReceiptEvent(const QJsonObject& obj);
+class ReceiptEvent : public Event
+{
+public:
+ DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent)
+ explicit ReceiptEvent(const QJsonObject& obj);
- const EventsWithReceipts& eventsWithReceipts() const
- {
- return _eventsWithReceipts;
- }
+ const EventsWithReceipts& eventsWithReceipts() const
+ {
+ return _eventsWithReceipts;
+ }
- private:
- EventsWithReceipts _eventsWithReceipts;
- };
- REGISTER_EVENT_TYPE(ReceiptEvent)
- DEFINE_EVENTTYPE_ALIAS(Receipt, ReceiptEvent)
+private:
+ EventsWithReceipts _eventsWithReceipts;
+};
+REGISTER_EVENT_TYPE(ReceiptEvent)
+DEFINE_EVENTTYPE_ALIAS(Receipt, ReceiptEvent)
} // namespace QMatrixClient
diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h
index 4187291c..a7dd9705 100644
--- a/lib/events/redactionevent.h
+++ b/lib/events/redactionevent.h
@@ -20,23 +20,23 @@
#include "roomevent.h"
-namespace QMatrixClient {
- class RedactionEvent : public RoomEvent
- {
- public:
- DEFINE_EVENT_TYPEID("m.room.redaction", RedactionEvent)
+namespace QMatrixClient
+{
+class RedactionEvent : public RoomEvent
+{
+public:
+ DEFINE_EVENT_TYPEID("m.room.redaction", RedactionEvent)
- explicit RedactionEvent(const QJsonObject& obj)
- : RoomEvent(typeId(), obj)
- {
- }
+ explicit RedactionEvent(const QJsonObject& obj)
+ : RoomEvent(typeId(), obj)
+ {}
- QString redactedEvent() const
- {
- return fullJson()["redacts"_ls].toString();
- }
- QString reason() const { return contentJson()["reason"_ls].toString(); }
- };
- REGISTER_EVENT_TYPE(RedactionEvent)
- DEFINE_EVENTTYPE_ALIAS(Redaction, RedactionEvent)
+ QString redactedEvent() const
+ {
+ return fullJson()["redacts"_ls].toString();
+ }
+ QString reason() const { return contentJson()["reason"_ls].toString(); }
+};
+REGISTER_EVENT_TYPE(RedactionEvent)
+DEFINE_EVENTTYPE_ALIAS(Redaction, RedactionEvent)
} // namespace QMatrixClient
diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h
index 69cd1f9d..ee460339 100644
--- a/lib/events/roomavatarevent.h
+++ b/lib/events/roomavatarevent.h
@@ -21,21 +21,21 @@
#include "eventcontent.h"
#include "stateevent.h"
-namespace QMatrixClient {
- class RoomAvatarEvent : public StateEvent<EventContent::ImageContent>
- {
- // It's a bit of an overkill to use a full-fledged ImageContent
- // because in reality m.room.avatar usually only has a single URL,
- // without a thumbnail. But The Spec says there be thumbnails, and
- // we follow The Spec.
- public:
- DEFINE_EVENT_TYPEID("m.room.avatar", RoomAvatarEvent)
- explicit RoomAvatarEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- {
- }
- QUrl url() const { return content().url; }
- };
- REGISTER_EVENT_TYPE(RoomAvatarEvent)
- DEFINE_EVENTTYPE_ALIAS(RoomAvatar, RoomAvatarEvent)
+namespace QMatrixClient
+{
+class RoomAvatarEvent : public StateEvent<EventContent::ImageContent>
+{
+ // It's a bit of an overkill to use a full-fledged ImageContent
+ // because in reality m.room.avatar usually only has a single URL,
+ // without a thumbnail. But The Spec says there be thumbnails, and
+ // we follow The Spec.
+public:
+ DEFINE_EVENT_TYPEID("m.room.avatar", RoomAvatarEvent)
+ explicit RoomAvatarEvent(const QJsonObject& obj)
+ : StateEvent(typeId(), obj)
+ {}
+ QUrl url() const { return content().url; }
+};
+REGISTER_EVENT_TYPE(RoomAvatarEvent)
+DEFINE_EVENTTYPE_ALIAS(RoomAvatar, RoomAvatarEvent)
} // namespace QMatrixClient
diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h
index fbfb33ca..17b86388 100644
--- a/lib/events/roomcreateevent.h
+++ b/lib/events/roomcreateevent.h
@@ -20,27 +20,30 @@
#include "stateevent.h"
-namespace QMatrixClient {
- class RoomCreateEvent : public StateEventBase
- {
- public:
- DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent)
-
- explicit RoomCreateEvent() : StateEventBase(typeId(), matrixTypeId()) {}
- explicit RoomCreateEvent(const QJsonObject& obj)
- : StateEventBase(typeId(), obj)
- {
- }
+namespace QMatrixClient
+{
+class RoomCreateEvent : public StateEventBase
+{
+public:
+ DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent)
- struct Predecessor {
- QString roomId;
- QString eventId;
- };
+ explicit RoomCreateEvent()
+ : StateEventBase(typeId(), matrixTypeId())
+ {}
+ explicit RoomCreateEvent(const QJsonObject& obj)
+ : StateEventBase(typeId(), obj)
+ {}
- bool isFederated() const;
- QString version() const;
- Predecessor predecessor() const;
- bool isUpgrade() const;
+ struct Predecessor
+ {
+ QString roomId;
+ QString eventId;
};
- REGISTER_EVENT_TYPE(RoomCreateEvent)
-}
+
+ bool isFederated() const;
+ QString version() const;
+ Predecessor predecessor() const;
+ bool isUpgrade() const;
+};
+REGISTER_EVENT_TYPE(RoomCreateEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp
index 221a3a61..c28de559 100644
--- a/lib/events/roomevent.cpp
+++ b/lib/events/roomevent.cpp
@@ -25,15 +25,15 @@
using namespace QMatrixClient;
[[gnu::unused]] static auto roomEventTypeInitialised =
- Event::factory_t::chainFactory<RoomEvent>();
+ Event::factory_t::chainFactory<RoomEvent>();
RoomEvent::RoomEvent(Type type, event_mtype_t matrixType,
const QJsonObject& contentJson)
: Event(type, matrixType, contentJson)
-{
-}
+{}
-RoomEvent::RoomEvent(Type type, const QJsonObject& json) : Event(type, json)
+RoomEvent::RoomEvent(Type type, const QJsonObject& json)
+ : Event(type, json)
{
const auto unsignedData = json[UnsignedKeyL].toObject();
const auto redaction = unsignedData[RedactedCauseKeyL];
@@ -49,8 +49,7 @@ QString RoomEvent::id() const { return fullJson()[EventIdKeyL].toString(); }
QDateTime RoomEvent::timestamp() const
{
- return QMatrixClient::fromJson<QDateTime>(
- fullJson()["origin_server_ts"_ls]);
+ return QMatrixClient::fromJson<QDateTime>(fullJson()["origin_server_ts"_ls]);
}
QString RoomEvent::roomId() const
@@ -108,8 +107,7 @@ CallEventBase::CallEventBase(Type type, event_mtype_t matrixType,
const QJsonObject& contentJson)
: RoomEvent(type, matrixType,
makeCallContentJson(callId, version, contentJson))
-{
-}
+{}
CallEventBase::CallEventBase(Event::Type type, const QJsonObject& json)
: RoomEvent(type, json)
diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h
index 746e9173..42cd8fe4 100644
--- a/lib/events/roomevent.h
+++ b/lib/events/roomevent.h
@@ -22,85 +22,84 @@
#include <QtCore/QDateTime>
-namespace QMatrixClient {
- class RedactionEvent;
+namespace QMatrixClient
+{
+class RedactionEvent;
- /** This class corresponds to m.room.* events */
- class RoomEvent : public Event
- {
- Q_GADGET
- Q_PROPERTY(QString id READ id)
- Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT)
- Q_PROPERTY(QString roomId READ roomId CONSTANT)
- Q_PROPERTY(QString senderId READ senderId CONSTANT)
- Q_PROPERTY(QString redactionReason READ redactionReason)
- Q_PROPERTY(bool isRedacted READ isRedacted)
- Q_PROPERTY(
- QString transactionId READ transactionId WRITE setTransactionId)
- public:
- using factory_t = EventFactory<RoomEvent>;
+/** This class corresponds to m.room.* events */
+class RoomEvent : public Event
+{
+ Q_GADGET
+ Q_PROPERTY(QString id READ id)
+ Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT)
+ Q_PROPERTY(QString roomId READ roomId CONSTANT)
+ Q_PROPERTY(QString senderId READ senderId CONSTANT)
+ Q_PROPERTY(QString redactionReason READ redactionReason)
+ Q_PROPERTY(bool isRedacted READ isRedacted)
+ Q_PROPERTY(QString transactionId READ transactionId WRITE setTransactionId)
+public:
+ using factory_t = EventFactory<RoomEvent>;
- // RedactionEvent is an incomplete type here so we cannot inline
- // constructors and destructors and we cannot use 'using'.
- RoomEvent(Type type, event_mtype_t matrixType,
- const QJsonObject& contentJson = {});
- RoomEvent(Type type, const QJsonObject& json);
- ~RoomEvent() override;
+ // RedactionEvent is an incomplete type here so we cannot inline
+ // constructors and destructors and we cannot use 'using'.
+ RoomEvent(Type type, event_mtype_t matrixType,
+ const QJsonObject& contentJson = {});
+ RoomEvent(Type type, const QJsonObject& json);
+ ~RoomEvent() override;
- QString id() const;
- QDateTime timestamp() const;
- QString roomId() const;
- QString senderId() const;
- bool isRedacted() const { return bool(_redactedBecause); }
- const event_ptr_tt<RedactionEvent>& redactedBecause() const
- {
- return _redactedBecause;
- }
- QString redactionReason() const;
- QString transactionId() const;
- QString stateKey() const;
+ QString id() const;
+ QDateTime timestamp() const;
+ QString roomId() const;
+ QString senderId() const;
+ bool isRedacted() const { return bool(_redactedBecause); }
+ const event_ptr_tt<RedactionEvent>& redactedBecause() const
+ {
+ return _redactedBecause;
+ }
+ QString redactionReason() const;
+ QString transactionId() const;
+ QString stateKey() const;
- /**
- * Sets the transaction id for locally created events. This should be
- * done before the event is exposed to any code using the respective
- * Q_PROPERTY.
- *
- * \param txnId - transaction id, normally obtained from
- * Connection::generateTxnId()
- */
- void setTransactionId(const QString& txnId);
+ /**
+ * Sets the transaction id for locally created events. This should be
+ * done before the event is exposed to any code using the respective
+ * Q_PROPERTY.
+ *
+ * \param txnId - transaction id, normally obtained from
+ * Connection::generateTxnId()
+ */
+ void setTransactionId(const QString& txnId);
- /**
- * Sets event id for locally created events
- *
- * When a new event is created locally, it has no server id yet.
- * This function allows to add the id once the confirmation from
- * the server is received. There should be no id set previously
- * in the event. It's the responsibility of the code calling addId()
- * to notify clients that use Q_PROPERTY(id) about its change
- */
- void addId(const QString& newId);
+ /**
+ * Sets event id for locally created events
+ *
+ * When a new event is created locally, it has no server id yet.
+ * This function allows to add the id once the confirmation from
+ * the server is received. There should be no id set previously
+ * in the event. It's the responsibility of the code calling addId()
+ * to notify clients that use Q_PROPERTY(id) about its change
+ */
+ void addId(const QString& newId);
- private:
- event_ptr_tt<RedactionEvent> _redactedBecause;
- };
- using RoomEventPtr = event_ptr_tt<RoomEvent>;
- using RoomEvents = EventsArray<RoomEvent>;
- using RoomEventsRange = Range<RoomEvents>;
+private:
+ event_ptr_tt<RedactionEvent> _redactedBecause;
+};
+using RoomEventPtr = event_ptr_tt<RoomEvent>;
+using RoomEvents = EventsArray<RoomEvent>;
+using RoomEventsRange = Range<RoomEvents>;
- class CallEventBase : public RoomEvent
- {
- public:
- CallEventBase(Type type, event_mtype_t matrixType,
- const QString& callId, int version,
- const QJsonObject& contentJson = {});
- CallEventBase(Type type, const QJsonObject& json);
- ~CallEventBase() override = default;
- bool isCallEvent() const override { return true; }
+class CallEventBase : public RoomEvent
+{
+public:
+ CallEventBase(Type type, event_mtype_t matrixType, const QString& callId,
+ int version, const QJsonObject& contentJson = {});
+ CallEventBase(Type type, const QJsonObject& json);
+ ~CallEventBase() override = default;
+ bool isCallEvent() const override { return true; }
- QString callId() const { return content<QString>("call_id"_ls); }
- int version() const { return content<int>("version"_ls); }
- };
+ QString callId() const { return content<QString>("call_id"_ls); }
+ int version() const { return content<int>("version"_ls); }
+};
} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::RoomEvent*)
Q_DECLARE_METATYPE(const QMatrixClient::RoomEvent*)
diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp
index 53203873..e6292b73 100644
--- a/lib/events/roommemberevent.cpp
+++ b/lib/events/roommemberevent.cpp
@@ -28,31 +28,33 @@ static const std::array<QString, 5> membershipStrings = {
QStringLiteral("leave"), QStringLiteral("ban") }
};
-namespace QMatrixClient {
- template <> struct JsonConverter<MembershipType> {
- static MembershipType load(const QJsonValue& jv)
- {
- const auto& membershipString = jv.toString();
- for (auto it = membershipStrings.begin();
- it != membershipStrings.end(); ++it)
- if (membershipString == *it)
- return MembershipType(it - membershipStrings.begin());
+namespace QMatrixClient
+{
+template <>
+struct JsonConverter<MembershipType>
+{
+ static MembershipType load(const QJsonValue& jv)
+ {
+ const auto& membershipString = jv.toString();
+ for (auto it = membershipStrings.begin(); it != membershipStrings.end();
+ ++it)
+ if (membershipString == *it)
+ return MembershipType(it - membershipStrings.begin());
- qCWarning(EVENTS) << "Unknown MembershipType: " << membershipString;
- return MembershipType::Undefined;
- }
- };
-}
+ qCWarning(EVENTS) << "Unknown MembershipType: " << membershipString;
+ return MembershipType::Undefined;
+ }
+};
+} // namespace QMatrixClient
using namespace QMatrixClient;
MemberEventContent::MemberEventContent(const QJsonObject& json)
- : membership(fromJson<MembershipType>(json["membership"_ls])),
- isDirect(json["is_direct"_ls].toBool()),
- displayName(json["displayname"_ls].toString()),
- avatarUrl(json["avatar_url"_ls].toString())
-{
-}
+ : membership(fromJson<MembershipType>(json["membership"_ls]))
+ , isDirect(json["is_direct"_ls].toBool())
+ , displayName(sanitized(json["displayname"_ls].toString()))
+ , avatarUrl(json["avatar_url"_ls].toString())
+{}
void MemberEventContent::fillJson(QJsonObject* o) const
{
@@ -69,20 +71,20 @@ void MemberEventContent::fillJson(QJsonObject* o) const
bool RoomMemberEvent::isInvite() const
{
return membership() == MembershipType::Invite
- && (!prevContent() || prevContent()->membership != membership());
+ && (!prevContent() || prevContent()->membership != membership());
}
bool RoomMemberEvent::isJoin() const
{
return membership() == MembershipType::Join
- && (!prevContent() || prevContent()->membership != membership());
+ && (!prevContent() || prevContent()->membership != membership());
}
bool RoomMemberEvent::isLeave() const
{
return membership() == MembershipType::Leave && prevContent()
- && prevContent()->membership != membership()
- && prevContent()->membership != MembershipType::Ban;
+ && prevContent()->membership != membership()
+ && prevContent()->membership != MembershipType::Ban;
}
bool RoomMemberEvent::isRename() const
diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h
index 55f419d8..a837b026 100644
--- a/lib/events/roommemberevent.h
+++ b/lib/events/roommemberevent.h
@@ -21,92 +21,92 @@
#include "eventcontent.h"
#include "stateevent.h"
-namespace QMatrixClient {
- class MemberEventContent : public EventContent::Base
+namespace QMatrixClient
+{
+class MemberEventContent : public EventContent::Base
+{
+public:
+ enum MembershipType : size_t
{
- public:
- enum MembershipType : size_t {
- Invite = 0,
- Join,
- Knock,
- Leave,
- Ban,
- Undefined
- };
+ Invite = 0,
+ Join,
+ Knock,
+ Leave,
+ Ban,
+ Undefined
+ };
- explicit MemberEventContent(MembershipType mt = Join) : membership(mt)
- {
- }
- explicit MemberEventContent(const QJsonObject& json);
+ explicit MemberEventContent(MembershipType mt = Join)
+ : membership(mt)
+ {}
+ explicit MemberEventContent(const QJsonObject& json);
- MembershipType membership;
- bool isDirect = false;
- QString displayName;
- QUrl avatarUrl;
+ MembershipType membership;
+ bool isDirect = false;
+ QString displayName;
+ QUrl avatarUrl;
- protected:
- void fillJson(QJsonObject* o) const override;
- };
+protected:
+ void fillJson(QJsonObject* o) const override;
+};
- using MembershipType = MemberEventContent::MembershipType;
+using MembershipType = MemberEventContent::MembershipType;
- class RoomMemberEvent : public StateEvent<MemberEventContent>
- {
- Q_GADGET
- public:
- DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent)
+class RoomMemberEvent : public StateEvent<MemberEventContent>
+{
+ Q_GADGET
+public:
+ DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent)
- using MembershipType = MemberEventContent::MembershipType;
+ using MembershipType = MemberEventContent::MembershipType;
- explicit RoomMemberEvent(const QJsonObject& obj)
- : StateEvent(typeId(), obj)
- {
- }
- RoomMemberEvent(MemberEventContent&& c)
- : StateEvent(typeId(), matrixTypeId(), c)
- {
- }
+ explicit RoomMemberEvent(const QJsonObject& obj)
+ : StateEvent(typeId(), obj)
+ {}
+ RoomMemberEvent(MemberEventContent&& c)
+ : StateEvent(typeId(), matrixTypeId(), c)
+ {}
- /// A special constructor to create unknown RoomMemberEvents
- /**
- * This is needed in order to use RoomMemberEvent as a "base event
- * class" in cases like GetMembersByRoomJob when RoomMemberEvents
- * (rather than RoomEvents or StateEvents) are resolved from JSON.
- * For such cases loadEvent<> requires an underlying class to be
- * constructible with unknownTypeId() instead of its genuine id.
- * Don't use it directly.
- * \sa GetMembersByRoomJob, loadEvent, unknownTypeId
- */
- RoomMemberEvent(Type type, const QJsonObject& fullJson)
- : StateEvent(type, fullJson)
- {
- }
+ /// A special constructor to create unknown RoomMemberEvents
+ /**
+ * This is needed in order to use RoomMemberEvent as a "base event
+ * class" in cases like GetMembersByRoomJob when RoomMemberEvents
+ * (rather than RoomEvents or StateEvents) are resolved from JSON.
+ * For such cases loadEvent<> requires an underlying class to be
+ * constructible with unknownTypeId() instead of its genuine id.
+ * Don't use it directly.
+ * \sa GetMembersByRoomJob, loadEvent, unknownTypeId
+ */
+ RoomMemberEvent(Type type, const QJsonObject& fullJson)
+ : StateEvent(type, fullJson)
+ {}
- MembershipType membership() const { return content().membership; }
- QString userId() const { return fullJson()["state_key"_ls].toString(); }
- bool isDirect() const { return content().isDirect; }
- QString displayName() const { return content().displayName; }
- QUrl avatarUrl() const { return content().avatarUrl; }
- bool isInvite() const;
- bool isJoin() const;
- bool isLeave() const;
- bool isRename() const;
- bool isAvatarUpdate() const;
+ MembershipType membership() const { return content().membership; }
+ QString userId() const { return fullJson()["state_key"_ls].toString(); }
+ bool isDirect() const { return content().isDirect; }
+ QString displayName() const { return content().displayName; }
+ QUrl avatarUrl() const { return content().avatarUrl; }
+ bool isInvite() const;
+ bool isJoin() const;
+ bool isLeave() const;
+ bool isRename() const;
+ bool isAvatarUpdate() const;
- private:
- REGISTER_ENUM(MembershipType)
- };
+private:
+ REGISTER_ENUM(MembershipType)
+};
- template <> class EventFactory<RoomMemberEvent>
+template <>
+class EventFactory<RoomMemberEvent>
+{
+public:
+ static event_ptr_tt<RoomMemberEvent> make(const QJsonObject& json,
+ const QString&)
{
- public:
- static event_ptr_tt<RoomMemberEvent> make(const QJsonObject& json,
- const QString&)
- {
- return makeEvent<RoomMemberEvent>(json);
- }
- };
+ return makeEvent<RoomMemberEvent>(json);
+ }
+};
- REGISTER_EVENT_TYPE(RoomMemberEvent)
- DEFINE_EVENTTYPE_ALIAS(RoomMember, RoomMemberEvent)
+REGISTER_EVENT_TYPE(RoomMemberEvent)
+DEFINE_EVENTTYPE_ALIAS(RoomMember, RoomMemberEvent)
} // namespace QMatrixClient
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 0af02eb0..c7f17303 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -40,19 +40,22 @@ static const auto NoticeTypeKey = "m.notice";
static const auto HtmlContentTypeId = QStringLiteral("org.matrix.custom.html");
-template <typename ContentT> TypedBase* make(const QJsonObject& json)
+template <typename ContentT>
+TypedBase* make(const QJsonObject& json)
{
return new ContentT(json);
}
-template <> TypedBase* make<TextContent>(const QJsonObject& json)
+template <>
+TypedBase* make<TextContent>(const QJsonObject& json)
{
return json.contains(FormattedBodyKey) || json.contains(RelatesToKey)
- ? new TextContent(json)
- : nullptr;
+ ? new TextContent(json)
+ : nullptr;
}
-struct MsgTypeDesc {
+struct MsgTypeDesc
+{
QString matrixType;
MsgType enumType;
TypedBase* (*maker)(const QJsonObject&);
@@ -71,9 +74,10 @@ const std::vector<MsgTypeDesc> msgTypes = {
QString msgTypeToJson(MsgType enumType)
{
- auto it = std::find_if(
- msgTypes.begin(), msgTypes.end(),
- [=](const MsgTypeDesc& mtd) { return mtd.enumType == enumType; });
+ auto it = std::find_if(msgTypes.begin(), msgTypes.end(),
+ [=](const MsgTypeDesc& mtd) {
+ return mtd.enumType == enumType;
+ });
if (it != msgTypes.end())
return it->matrixType;
@@ -112,16 +116,14 @@ RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
const QString& jsonMsgType,
TypedBase* content)
: RoomEvent(typeId(), matrixTypeId(),
- assembleContentJson(plainBody, jsonMsgType, content)),
- _content(content)
-{
-}
+ assembleContentJson(plainBody, jsonMsgType, content))
+ , _content(content)
+{}
RoomMessageEvent::RoomMessageEvent(const QString& plainBody, MsgType msgType,
TypedBase* content)
: RoomMessageEvent(plainBody, msgTypeToJson(msgType), content)
-{
-}
+{}
TypedBase* contentFromFile(const QFileInfo& file, bool asGenericFile)
{
@@ -155,11 +157,11 @@ RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
asGenericFile ? QStringLiteral("m.file")
: rawMsgTypeForFile(file),
contentFromFile(file, asGenericFile))
-{
-}
+{}
RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
- : RoomEvent(typeId(), obj), _content(nullptr)
+ : RoomEvent(typeId(), obj)
+ , _content(nullptr)
{
if (isRedacted())
return;
@@ -202,15 +204,15 @@ QString RoomMessageEvent::plainBody() const
QMimeType RoomMessageEvent::mimeType() const
{
static const auto PlainTextMimeType =
- QMimeDatabase().mimeTypeForName("text/plain");
+ QMimeDatabase().mimeTypeForName("text/plain");
return _content ? _content->type() : PlainTextMimeType;
}
bool RoomMessageEvent::hasTextContent() const
{
return !content()
- || (msgtype() == MsgType::Text || msgtype() == MsgType::Emote
- || msgtype() == MsgType::Notice);
+ || (msgtype() == MsgType::Text || msgtype() == MsgType::Emote
+ || msgtype() == MsgType::Notice);
}
bool RoomMessageEvent::hasFileContent() const
@@ -226,11 +228,12 @@ bool RoomMessageEvent::hasThumbnail() const
QString rawMsgTypeForMimeType(const QMimeType& mimeType)
{
auto name = mimeType.name();
- return name.startsWith("image/") ? QStringLiteral("m.image")
- : name.startsWith("video/")
- ? QStringLiteral("m.video")
- : name.startsWith("audio/") ? QStringLiteral("m.audio")
- : QStringLiteral("m.file");
+ return name.startsWith("image/")
+ ? QStringLiteral("m.image")
+ : name.startsWith("video/")
+ ? QStringLiteral("m.video")
+ : name.startsWith("audio/") ? QStringLiteral("m.audio")
+ : QStringLiteral("m.file");
}
QString RoomMessageEvent::rawMsgTypeForUrl(const QUrl& url)
@@ -245,9 +248,9 @@ QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi)
TextContent::TextContent(const QString& text, const QString& contentType,
Omittable<RelatesTo> relatesTo)
- : mimeType(QMimeDatabase().mimeTypeForName(contentType)),
- body(text),
- relatesTo(std::move(relatesTo))
+ : mimeType(QMimeDatabase().mimeTypeForName(contentType))
+ , body(text)
+ , relatesTo(std::move(relatesTo))
{
if (contentType == HtmlContentTypeId)
mimeType = QMimeDatabase().mimeTypeForName("text/html");
@@ -270,10 +273,8 @@ TextContent::TextContent(const QJsonObject& json)
mimeType = PlainTextMimeType;
body = json[BodyKey].toString();
}
- const auto replyJson = json[RelatesToKey]
- .toObject()
- .value(RelatesTo::ReplyTypeId())
- .toObject();
+ const auto replyJson =
+ json[RelatesToKey].toObject().value(RelatesTo::ReplyTypeId()).toObject();
if (!replyJson.isEmpty())
relatesTo = replyTo(fromJson<QString>(replyJson[EventIdKeyL]));
}
@@ -292,16 +293,15 @@ void TextContent::fillJson(QJsonObject* json) const
LocationContent::LocationContent(const QString& geoUri,
const Thumbnail& thumbnail)
- : geoUri(geoUri), thumbnail(thumbnail)
-{
-}
+ : geoUri(geoUri)
+ , thumbnail(thumbnail)
+{}
LocationContent::LocationContent(const QJsonObject& json)
- : TypedBase(json),
- geoUri(json["geo_uri"_ls].toString()),
- thumbnail(json["info"_ls].toObject())
-{
-}
+ : TypedBase(json)
+ , geoUri(json["geo_uri"_ls].toString())
+ , thumbnail(json["info"_ls].toObject())
+{}
QMimeType LocationContent::type() const
{
diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h
index bd1b7c83..eabb21e3 100644
--- a/lib/events/roommessageevent.h
+++ b/lib/events/roommessageevent.h
@@ -23,205 +23,203 @@
class QFileInfo;
-namespace QMatrixClient {
- namespace MessageEventContent = EventContent; // Back-compatibility
+namespace QMatrixClient
+{
+namespace MessageEventContent = EventContent; // Back-compatibility
+
+/**
+ * The event class corresponding to m.room.message events
+ */
+class RoomMessageEvent : public RoomEvent
+{
+ Q_GADGET
+ Q_PROPERTY(QString msgType READ rawMsgtype CONSTANT)
+ Q_PROPERTY(QString plainBody READ plainBody CONSTANT)
+ Q_PROPERTY(QMimeType mimeType READ mimeType STORED false CONSTANT)
+ Q_PROPERTY(EventContent::TypedBase* content READ content CONSTANT)
+public:
+ DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent)
+
+ enum class MsgType
+ {
+ Text,
+ Emote,
+ Notice,
+ Image,
+ File,
+ Location,
+ Video,
+ Audio,
+ Unknown
+ };
+
+ RoomMessageEvent(const QString& plainBody, const QString& jsonMsgType,
+ EventContent::TypedBase* content = nullptr);
+ explicit RoomMessageEvent(const QString& plainBody,
+ MsgType msgType = MsgType::Text,
+ EventContent::TypedBase* content = nullptr);
+ explicit RoomMessageEvent(const QString& plainBody, const QFileInfo& file,
+ bool asGenericFile = false);
+ explicit RoomMessageEvent(const QJsonObject& obj);
+
+ MsgType msgtype() const;
+ QString rawMsgtype() const;
+ QString plainBody() const;
+ EventContent::TypedBase* content() const { return _content.data(); }
+ template <typename VisitorT>
+ void editContent(VisitorT visitor)
+ {
+ visitor(*_content);
+ editJson()[ContentKeyL] = assembleContentJson(plainBody(), rawMsgtype(),
+ content());
+ }
+ QMimeType mimeType() const;
+ bool hasTextContent() const;
+ bool hasFileContent() const;
+ bool hasThumbnail() const;
+
+ static QString rawMsgTypeForUrl(const QUrl& url);
+ static QString rawMsgTypeForFile(const QFileInfo& fi);
+
+private:
+ QScopedPointer<EventContent::TypedBase> _content;
+
+ static QJsonObject assembleContentJson(const QString& plainBody,
+ const QString& jsonMsgType,
+ EventContent::TypedBase* content);
+
+ REGISTER_ENUM(MsgType)
+};
+REGISTER_EVENT_TYPE(RoomMessageEvent)
+DEFINE_EVENTTYPE_ALIAS(RoomMessage, RoomMessageEvent)
+using MessageEventType = RoomMessageEvent::MsgType;
+
+namespace EventContent
+{
+ // Additional event content types
+
+ struct RelatesTo
+ {
+ static constexpr const char* ReplyTypeId() { return "m.in_reply_to"; }
+ QString type; // The only supported relation so far
+ QString eventId;
+ };
+ inline RelatesTo replyTo(QString eventId)
+ {
+ return { RelatesTo::ReplyTypeId(), std::move(eventId) };
+ }
/**
- * The event class corresponding to m.room.message events
+ * Rich text content for m.text, m.emote, m.notice
+ *
+ * Available fields: mimeType, body. The body can be either rich text
+ * or plain text, depending on what mimeType specifies.
*/
- class RoomMessageEvent : public RoomEvent
+ class TextContent : public TypedBase
{
- Q_GADGET
- Q_PROPERTY(QString msgType READ rawMsgtype CONSTANT)
- Q_PROPERTY(QString plainBody READ plainBody CONSTANT)
- Q_PROPERTY(QMimeType mimeType READ mimeType STORED false CONSTANT)
- Q_PROPERTY(EventContent::TypedBase* content READ content CONSTANT)
- public:
- DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent)
-
- enum class MsgType {
- Text,
- Emote,
- Notice,
- Image,
- File,
- Location,
- Video,
- Audio,
- Unknown
- };
-
- RoomMessageEvent(const QString& plainBody, const QString& jsonMsgType,
- EventContent::TypedBase* content = nullptr);
- explicit RoomMessageEvent(const QString& plainBody,
- MsgType msgType = MsgType::Text,
- EventContent::TypedBase* content = nullptr);
- explicit RoomMessageEvent(const QString& plainBody,
- const QFileInfo& file,
- bool asGenericFile = false);
- explicit RoomMessageEvent(const QJsonObject& obj);
-
- MsgType msgtype() const;
- QString rawMsgtype() const;
- QString plainBody() const;
- EventContent::TypedBase* content() const { return _content.data(); }
- template <typename VisitorT> void editContent(VisitorT visitor)
- {
- visitor(*_content);
- editJson()[ContentKeyL] =
- assembleContentJson(plainBody(), rawMsgtype(), content());
- }
- QMimeType mimeType() const;
- bool hasTextContent() const;
- bool hasFileContent() const;
- bool hasThumbnail() const;
-
- static QString rawMsgTypeForUrl(const QUrl& url);
- static QString rawMsgTypeForFile(const QFileInfo& fi);
+ public:
+ TextContent(const QString& text, const QString& contentType,
+ Omittable<RelatesTo> relatesTo = none);
+ explicit TextContent(const QJsonObject& json);
- private:
- QScopedPointer<EventContent::TypedBase> _content;
+ QMimeType type() const override { return mimeType; }
- static QJsonObject
- assembleContentJson(const QString& plainBody,
- const QString& jsonMsgType,
- EventContent::TypedBase* content);
+ QMimeType mimeType;
+ QString body;
+ Omittable<RelatesTo> relatesTo;
- REGISTER_ENUM(MsgType)
+ protected:
+ void fillJson(QJsonObject* json) const override;
};
- REGISTER_EVENT_TYPE(RoomMessageEvent)
- DEFINE_EVENTTYPE_ALIAS(RoomMessage, RoomMessageEvent)
- using MessageEventType = RoomMessageEvent::MsgType;
-
- namespace EventContent {
- // Additional event content types
-
- struct RelatesTo {
- static constexpr const char* ReplyTypeId()
- {
- return "m.in_reply_to";
- }
- QString type; // The only supported relation so far
- QString eventId;
- };
- inline RelatesTo replyTo(QString eventId)
- {
- return { RelatesTo::ReplyTypeId(), std::move(eventId) };
- }
- /**
- * Rich text content for m.text, m.emote, m.notice
- *
- * Available fields: mimeType, body. The body can be either rich text
- * or plain text, depending on what mimeType specifies.
- */
- class TextContent : public TypedBase
- {
- public:
- TextContent(const QString& text, const QString& contentType,
- Omittable<RelatesTo> relatesTo = none);
- explicit TextContent(const QJsonObject& json);
-
- QMimeType type() const override { return mimeType; }
-
- QMimeType mimeType;
- QString body;
- Omittable<RelatesTo> relatesTo;
-
- protected:
- void fillJson(QJsonObject* json) const override;
- };
-
- /**
- * Content class for m.location
- *
- * Available fields:
- * - corresponding to the top-level JSON:
- * - geoUri ("geo_uri" in JSON)
- * - corresponding to the "info" subobject:
- * - thumbnail.url ("thumbnail_url" in JSON)
- * - corresponding to the "info/thumbnail_info" subobject:
- * - thumbnail.payloadSize
- * - thumbnail.mimeType
- * - thumbnail.imageSize
- */
- class LocationContent : public TypedBase
- {
- public:
- LocationContent(const QString& geoUri,
- const Thumbnail& thumbnail = {});
- explicit LocationContent(const QJsonObject& json);
+ /**
+ * Content class for m.location
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - geoUri ("geo_uri" in JSON)
+ * - corresponding to the "info" subobject:
+ * - thumbnail.url ("thumbnail_url" in JSON)
+ * - corresponding to the "info/thumbnail_info" subobject:
+ * - thumbnail.payloadSize
+ * - thumbnail.mimeType
+ * - thumbnail.imageSize
+ */
+ class LocationContent : public TypedBase
+ {
+ public:
+ LocationContent(const QString& geoUri, const Thumbnail& thumbnail = {});
+ explicit LocationContent(const QJsonObject& json);
- QMimeType type() const override;
+ QMimeType type() const override;
- public:
- QString geoUri;
- Thumbnail thumbnail;
+ public:
+ QString geoUri;
+ Thumbnail thumbnail;
- protected:
- void fillJson(QJsonObject* o) const override;
- };
+ protected:
+ void fillJson(QJsonObject* o) const override;
+ };
- /**
- * A base class for info types that include duration: audio and video
- */
- template <typename ContentT> class PlayableContent : public ContentT
+ /**
+ * A base class for info types that include duration: audio and video
+ */
+ template <typename ContentT>
+ class PlayableContent : public ContentT
+ {
+ public:
+ using ContentT::ContentT;
+ PlayableContent(const QJsonObject& json)
+ : ContentT(json)
+ , duration(ContentT::originalInfoJson["duration"_ls].toInt())
+ {}
+
+ protected:
+ void fillJson(QJsonObject* json) const override
{
- public:
- using ContentT::ContentT;
- PlayableContent(const QJsonObject& json)
- : ContentT(json),
- duration(ContentT::originalInfoJson["duration"_ls].toInt())
- {
- }
-
- protected:
- void fillJson(QJsonObject* json) const override
- {
- ContentT::fillJson(json);
- auto infoJson = json->take("info"_ls).toObject();
- infoJson.insert(QStringLiteral("duration"), duration);
- json->insert(QStringLiteral("info"), infoJson);
- }
-
- public:
- int duration;
- };
-
- /**
- * Content class for m.video
- *
- * Available fields:
- * - corresponding to the top-level JSON:
- * - url
- * - filename (extension to the CS API spec)
- * - corresponding to the "info" subobject:
- * - payloadSize ("size" in JSON)
- * - mimeType ("mimetype" in JSON)
- * - duration
- * - imageSize (QSize for a combination of "h" and "w" in JSON)
- * - thumbnail.url ("thumbnail_url" in JSON)
- * - corresponding to the "info/thumbnail_info" subobject: contents of
- * thumbnail field, in the same vein as for "info":
- * - payloadSize
- * - mimeType
- * - imageSize
- */
- using VideoContent =
- PlayableContent<UrlWithThumbnailContent<ImageInfo>>;
-
- /**
- * Content class for m.audio
- *
- * Available fields:
- * - corresponding to the top-level JSON:
- * - url
- * - filename (extension to the CS API spec)
- * - corresponding to the "info" subobject:
- * - payloadSize ("size" in JSON)
- * - mimeType ("mimetype" in JSON)
- * - duration
- */
- using AudioContent = PlayableContent<UrlBasedContent<FileInfo>>;
- } // namespace EventContent
+ ContentT::fillJson(json);
+ auto infoJson = json->take("info"_ls).toObject();
+ infoJson.insert(QStringLiteral("duration"), duration);
+ json->insert(QStringLiteral("info"), infoJson);
+ }
+
+ public:
+ int duration;
+ };
+
+ /**
+ * Content class for m.video
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - url
+ * - filename (extension to the CS API spec)
+ * - corresponding to the "info" subobject:
+ * - payloadSize ("size" in JSON)
+ * - mimeType ("mimetype" in JSON)
+ * - duration
+ * - imageSize (QSize for a combination of "h" and "w" in JSON)
+ * - thumbnail.url ("thumbnail_url" in JSON)
+ * - corresponding to the "info/thumbnail_info" subobject: contents of
+ * thumbnail field, in the same vein as for "info":
+ * - payloadSize
+ * - mimeType
+ * - imageSize
+ */
+ using VideoContent = PlayableContent<UrlWithThumbnailContent<ImageInfo>>;
+
+ /**
+ * Content class for m.audio
+ *
+ * Available fields:
+ * - corresponding to the top-level JSON:
+ * - url
+ * - filename (extension to the CS API spec)
+ * - corresponding to the "info" subobject:
+ * - payloadSize ("size" in JSON)
+ * - mimeType ("mimetype" in JSON)
+ * - duration
+ */
+ using AudioContent = PlayableContent<UrlBasedContent<FileInfo>>;
+} // namespace EventContent
} // namespace QMatrixClient
diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h
index 5b7ade76..aa9cb766 100644
--- a/lib/events/roomtombstoneevent.h
+++ b/lib/events/roomtombstoneevent.h
@@ -20,22 +20,22 @@
#include "stateevent.h"
-namespace QMatrixClient {
- class RoomTombstoneEvent : public StateEventBase
- {
- public:
- DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent)
+namespace QMatrixClient
+{
+class RoomTombstoneEvent : public StateEventBase
+{
+public:
+ DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent)
- explicit RoomTombstoneEvent() : StateEventBase(typeId(), matrixTypeId())
- {
- }
- explicit RoomTombstoneEvent(const QJsonObject& obj)
- : StateEventBase(typeId(), obj)
- {
- }
+ explicit RoomTombstoneEvent()
+ : StateEventBase(typeId(), matrixTypeId())
+ {}
+ explicit RoomTombstoneEvent(const QJsonObject& obj)
+ : StateEventBase(typeId(), obj)
+ {}
- QString serverMessage() const;
- QString successorRoomId() const;
- };
- REGISTER_EVENT_TYPE(RoomTombstoneEvent)
-}
+ QString serverMessage() const;
+ QString successorRoomId() const;
+};
+REGISTER_EVENT_TYPE(RoomTombstoneEvent)
+} // namespace QMatrixClient
diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h
index 430eacb0..7ad2efa6 100644
--- a/lib/events/simplestateevents.h
+++ b/lib/events/simplestateevents.h
@@ -18,74 +18,76 @@
#pragma once
+#include "converters.h"
#include "stateevent.h"
-#include "converters.h"
+namespace QMatrixClient
+{
+namespace EventContent
+{
+ template <typename T>
+ class SimpleContent
+ {
+ public:
+ using value_type = T;
-namespace QMatrixClient {
- namespace EventContent {
- template <typename T> class SimpleContent
+ // The constructor is templated to enable perfect forwarding
+ template <typename TT>
+ SimpleContent(QString keyName, TT&& value)
+ : value(std::forward<TT>(value))
+ , key(std::move(keyName))
+ {}
+ SimpleContent(const QJsonObject& json, QString keyName)
+ : value(fromJson<T>(json[keyName]))
+ , key(std::move(keyName))
+ {}
+ QJsonObject toJson() const
{
- public:
- using value_type = T;
-
- // The constructor is templated to enable perfect forwarding
- template <typename TT>
- SimpleContent(QString keyName, TT&& value)
- : value(std::forward<TT>(value)), key(std::move(keyName))
- {
- }
- SimpleContent(const QJsonObject& json, QString keyName)
- : value(fromJson<T>(json[keyName])), key(std::move(keyName))
- {
- }
- QJsonObject toJson() const
- {
- return { { key, QMatrixClient::toJson(value) } };
- }
+ return { { key, QMatrixClient::toJson(value) } };
+ }
- public:
- T value;
+ public:
+ T value;
- protected:
- QString key;
- };
- } // namespace EventContent
+ protected:
+ QString key;
+ };
+} // namespace EventContent
#define DEFINE_SIMPLE_STATE_EVENT(_Name, _TypeId, _ValueType, _ContentKey) \
class _Name : public StateEvent<EventContent::SimpleContent<_ValueType>> \
{ \
- public: \
+ public: \
using value_type = content_type::value_type; \
DEFINE_EVENT_TYPEID(_TypeId, _Name) \
- explicit _Name() : _Name(value_type()) {} \
+ explicit _Name() \
+ : _Name(value_type()) \
+ {} \
template <typename T> \
explicit _Name(T&& value) \
: StateEvent(typeId(), matrixTypeId(), \
QStringLiteral(#_ContentKey), std::forward<T>(value)) \
- { \
- } \
+ {} \
explicit _Name(QJsonObject obj) \
: StateEvent(typeId(), std::move(obj), \
QStringLiteral(#_ContentKey)) \
- { \
- } \
+ {} \
auto _ContentKey() const { return content().value; } \
}; \
REGISTER_EVENT_TYPE(_Name) \
// End of macro
- DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", QString, name)
- DEFINE_EVENTTYPE_ALIAS(RoomName, RoomNameEvent)
- DEFINE_SIMPLE_STATE_EVENT(RoomAliasesEvent, "m.room.aliases", QStringList,
- aliases)
- DEFINE_EVENTTYPE_ALIAS(RoomAliases, RoomAliasesEvent)
- DEFINE_SIMPLE_STATE_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias",
- QString, alias)
- DEFINE_EVENTTYPE_ALIAS(RoomCanonicalAlias, RoomCanonicalAliasEvent)
- DEFINE_SIMPLE_STATE_EVENT(RoomTopicEvent, "m.room.topic", QString, topic)
- DEFINE_EVENTTYPE_ALIAS(RoomTopic, RoomTopicEvent)
- DEFINE_SIMPLE_STATE_EVENT(EncryptionEvent, "m.room.encryption", QString,
- algorithm)
- DEFINE_EVENTTYPE_ALIAS(RoomEncryption, EncryptionEvent)
+DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", QString, name)
+DEFINE_EVENTTYPE_ALIAS(RoomName, RoomNameEvent)
+DEFINE_SIMPLE_STATE_EVENT(RoomAliasesEvent, "m.room.aliases", QStringList,
+ aliases)
+DEFINE_EVENTTYPE_ALIAS(RoomAliases, RoomAliasesEvent)
+DEFINE_SIMPLE_STATE_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias",
+ QString, alias)
+DEFINE_EVENTTYPE_ALIAS(RoomCanonicalAlias, RoomCanonicalAliasEvent)
+DEFINE_SIMPLE_STATE_EVENT(RoomTopicEvent, "m.room.topic", QString, topic)
+DEFINE_EVENTTYPE_ALIAS(RoomTopic, RoomTopicEvent)
+DEFINE_SIMPLE_STATE_EVENT(EncryptionEvent, "m.room.encryption", QString,
+ algorithm)
+DEFINE_EVENTTYPE_ALIAS(RoomEncryption, EncryptionEvent)
} // namespace QMatrixClient
diff --git a/lib/events/stateevent.cpp b/lib/events/stateevent.cpp
index f172edb6..7fea59a1 100644
--- a/lib/events/stateevent.cpp
+++ b/lib/events/stateevent.cpp
@@ -24,10 +24,9 @@ using namespace QMatrixClient;
// StateEventBase itself can be instantiated if there's a state_key JSON key
// but the event type is unknown.
[[gnu::unused]] static auto stateEventTypeInitialised =
- RoomEvent::factory_t::addMethod([](const QJsonObject& json,
- const QString& matrixType)
- -> StateEventPtr {
- if (!json.contains("state_key"))
+ RoomEvent::factory_t::addMethod(
+ [](const QJsonObject& json, const QString& matrixType) -> StateEventPtr {
+ if (!json.contains("state_key"_ls))
return nullptr;
if (auto e = StateEventBase::factory_t::make(json, matrixType))
@@ -53,7 +52,7 @@ void StateEventBase::dumpTo(QDebug dbg) const
dbg << '<' << stateKey() << "> ";
if (unsignedJson().contains(PrevContentKeyL))
dbg << QJsonDocument(unsignedJson()[PrevContentKeyL].toObject())
- .toJson(QJsonDocument::Compact)
+ .toJson(QJsonDocument::Compact)
<< " -> ";
RoomEvent::dumpTo(dbg);
}
diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h
index 1a02646b..8a89c86c 100644
--- a/lib/events/stateevent.h
+++ b/lib/events/stateevent.h
@@ -20,110 +20,111 @@
#include "roomevent.h"
-namespace QMatrixClient {
- class StateEventBase : public RoomEvent
- {
- public:
- using factory_t = EventFactory<StateEventBase>;
+namespace QMatrixClient
+{
+class StateEventBase : public RoomEvent
+{
+public:
+ using factory_t = EventFactory<StateEventBase>;
- using RoomEvent::RoomEvent;
- ~StateEventBase() override = default;
+ using RoomEvent::RoomEvent;
+ ~StateEventBase() override = default;
- bool isStateEvent() const override { return true; }
- QString replacedState() const;
- void dumpTo(QDebug dbg) const override;
+ bool isStateEvent() const override { return true; }
+ QString replacedState() const;
+ void dumpTo(QDebug dbg) const override;
- virtual bool repeatsState() const;
- };
- using StateEventPtr = event_ptr_tt<StateEventBase>;
- using StateEvents = EventsArray<StateEventBase>;
+ virtual bool repeatsState() const;
+};
+using StateEventPtr = event_ptr_tt<StateEventBase>;
+using StateEvents = EventsArray<StateEventBase>;
- template <> inline bool is<StateEventBase>(const Event& e)
- {
- return e.isStateEvent();
- }
+template <>
+inline bool is<StateEventBase>(const Event& e)
+{
+ return e.isStateEvent();
+}
+
+/**
+ * A combination of event type and state key uniquely identifies a piece
+ * of state in Matrix.
+ * \sa
+ * https://matrix.org/docs/spec/client_server/unstable.html#types-of-room-events
+ */
+using StateEventKey = QPair<QString, QString>;
- /**
- * A combination of event type and state key uniquely identifies a piece
- * of state in Matrix.
- * \sa
- * https://matrix.org/docs/spec/client_server/unstable.html#types-of-room-events
- */
- using StateEventKey = QPair<QString, QString>;
+template <typename ContentT>
+struct Prev
+{
+ template <typename... ContentParamTs>
+ explicit Prev(const QJsonObject& unsignedJson,
+ ContentParamTs&&... contentParams)
+ : senderId(unsignedJson.value("prev_sender"_ls).toString())
+ , content(unsignedJson.value(PrevContentKeyL).toObject(),
+ std::forward<ContentParamTs>(contentParams)...)
+ {}
- template <typename ContentT> struct Prev {
- template <typename... ContentParamTs>
- explicit Prev(const QJsonObject& unsignedJson,
- ContentParamTs&&... contentParams)
- : senderId(unsignedJson.value("prev_sender"_ls).toString()),
- content(unsignedJson.value(PrevContentKeyL).toObject(),
- std::forward<ContentParamTs>(contentParams)...)
- {
- }
+ QString senderId;
+ ContentT content;
+};
- QString senderId;
- ContentT content;
- };
+template <typename ContentT>
+class StateEvent : public StateEventBase
+{
+public:
+ using content_type = ContentT;
- template <typename ContentT> class StateEvent : public StateEventBase
+ template <typename... ContentParamTs>
+ explicit StateEvent(Type type, const QJsonObject& fullJson,
+ ContentParamTs&&... contentParams)
+ : StateEventBase(type, fullJson)
+ , _content(contentJson(), std::forward<ContentParamTs>(contentParams)...)
{
- public:
- using content_type = ContentT;
-
- template <typename... ContentParamTs>
- explicit StateEvent(Type type, const QJsonObject& fullJson,
- ContentParamTs&&... contentParams)
- : StateEventBase(type, fullJson),
- _content(contentJson(),
- std::forward<ContentParamTs>(contentParams)...)
- {
- const auto& unsignedData = unsignedJson();
- if (unsignedData.contains(PrevContentKeyL))
- _prev = std::make_unique<Prev<ContentT>>(
- unsignedData,
- std::forward<ContentParamTs>(contentParams)...);
- }
- template <typename... ContentParamTs>
- explicit StateEvent(Type type, event_mtype_t matrixType,
- ContentParamTs&&... contentParams)
- : StateEventBase(type, matrixType),
- _content(std::forward<ContentParamTs>(contentParams)...)
- {
- editJson().insert(ContentKey, _content.toJson());
- }
+ const auto& unsignedData = unsignedJson();
+ if (unsignedData.contains(PrevContentKeyL))
+ _prev = std::make_unique<Prev<ContentT>>(
+ unsignedData, std::forward<ContentParamTs>(contentParams)...);
+ }
+ template <typename... ContentParamTs>
+ explicit StateEvent(Type type, event_mtype_t matrixType,
+ ContentParamTs&&... contentParams)
+ : StateEventBase(type, matrixType)
+ , _content(std::forward<ContentParamTs>(contentParams)...)
+ {
+ editJson().insert(ContentKey, _content.toJson());
+ }
- const ContentT& content() const { return _content; }
- template <typename VisitorT> void editContent(VisitorT&& visitor)
- {
- 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;
- }
- QString prevSenderId() const
- {
- return _prev ? _prev->senderId : QString();
- }
+ const ContentT& content() const { return _content; }
+ template <typename VisitorT>
+ void editContent(VisitorT&& visitor)
+ {
+ 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;
+ }
+ QString prevSenderId() const { return _prev ? _prev->senderId : QString(); }
- private:
- ContentT _content;
- std::unique_ptr<Prev<ContentT>> _prev;
- };
+private:
+ ContentT _content;
+ std::unique_ptr<Prev<ContentT>> _prev;
+};
} // namespace QMatrixClient
-namespace std {
- template <> struct hash<QMatrixClient::StateEventKey> {
- size_t
- operator()(const QMatrixClient::StateEventKey& k) const Q_DECL_NOEXCEPT
- {
- return qHash(k);
- }
- };
-}
+namespace std
+{
+template <>
+struct hash<QMatrixClient::StateEventKey>
+{
+ size_t operator()(const QMatrixClient::StateEventKey& k) const Q_DECL_NOEXCEPT
+ {
+ return qHash(k);
+ }
+};
+} // namespace std
diff --git a/lib/events/typingevent.cpp b/lib/events/typingevent.cpp
index ee3d6b67..128a206a 100644
--- a/lib/events/typingevent.cpp
+++ b/lib/events/typingevent.cpp
@@ -22,7 +22,8 @@
using namespace QMatrixClient;
-TypingEvent::TypingEvent(const QJsonObject& obj) : Event(typeId(), obj)
+TypingEvent::TypingEvent(const QJsonObject& obj)
+ : Event(typeId(), obj)
{
const auto& array = contentJson()["user_ids"_ls].toArray();
for (const auto& user : array)
diff --git a/lib/events/typingevent.h b/lib/events/typingevent.h
index f66a1fbc..241359b4 100644
--- a/lib/events/typingevent.h
+++ b/lib/events/typingevent.h
@@ -20,19 +20,20 @@
#include "event.h"
-namespace QMatrixClient {
- class TypingEvent : public Event
- {
- public:
- DEFINE_EVENT_TYPEID("m.typing", TypingEvent)
+namespace QMatrixClient
+{
+class TypingEvent : public Event
+{
+public:
+ DEFINE_EVENT_TYPEID("m.typing", TypingEvent)
- TypingEvent(const QJsonObject& obj);
+ TypingEvent(const QJsonObject& obj);
- const QStringList& users() const { return _users; }
+ const QStringList& users() const { return _users; }
- private:
- QStringList _users;
- };
- REGISTER_EVENT_TYPE(TypingEvent)
- DEFINE_EVENTTYPE_ALIAS(Typing, TypingEvent)
+private:
+ QStringList _users;
+};
+REGISTER_EVENT_TYPE(TypingEvent)
+DEFINE_EVENTTYPE_ALIAS(Typing, TypingEvent)
} // namespace QMatrixClient
diff --git a/lib/identity/definitions/request_email_validation.cpp b/lib/identity/definitions/request_email_validation.cpp
index a2d0a707..131b9488 100644
--- a/lib/identity/definitions/request_email_validation.cpp
+++ b/lib/identity/definitions/request_email_validation.cpp
@@ -7,7 +7,7 @@
using namespace QMatrixClient;
void JsonObjectConverter<RequestEmailValidation>::dumpTo(
- QJsonObject& jo, const RequestEmailValidation& pod)
+ QJsonObject& jo, const RequestEmailValidation& pod)
{
addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
addParam<>(jo, QStringLiteral("email"), pod.email);
@@ -16,7 +16,7 @@ void JsonObjectConverter<RequestEmailValidation>::dumpTo(
}
void JsonObjectConverter<RequestEmailValidation>::fillFrom(
- const QJsonObject& jo, RequestEmailValidation& result)
+ const QJsonObject& jo, RequestEmailValidation& result)
{
fromJson(jo.value("client_secret"_ls), result.clientSecret);
fromJson(jo.value("email"_ls), result.email);
diff --git a/lib/identity/definitions/request_email_validation.h b/lib/identity/definitions/request_email_validation.h
index 51369039..2496d7f5 100644
--- a/lib/identity/definitions/request_email_validation.h
+++ b/lib/identity/definitions/request_email_validation.h
@@ -6,35 +6,37 @@
#include "converters.h"
-#include "converters.h"
+namespace QMatrixClient
+{
+
+// Data structures
-namespace QMatrixClient {
- // Data structures
+struct RequestEmailValidation
+{
+ /// A unique string generated by the client, and used to identify
+ /// thevalidation attempt. It must be a string consisting of the
+ /// characters``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters
+ /// and itmust not be empty.
+ QString clientSecret;
+ /// The email address to validate.
+ QString email;
+ /// The server will only send an email if the ``send_attempt``is a number
+ /// greater than the most recent one which it has seen,scoped to that
+ /// ``email`` + ``client_secret`` pair. This is toavoid repeatedly sending
+ /// the same email in the case of requestretries between the POSTing user
+ /// and the identity server.The client should increment this value if they
+ /// desire a newemail (e.g. a reminder) to be sent.
+ int sendAttempt;
+ /// Optional. When the validation is completed, the identityserver will
+ /// redirect the user to this URL.
+ QString nextLink;
+};
- struct RequestEmailValidation {
- /// A unique string generated by the client, and used to identify the
- /// validation attempt. It must be a string consisting of the characters
- /// ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- /// it must not be empty.
- QString clientSecret;
- /// The email address to validate.
- QString email;
- /// The server will only send an email if the ``send_attempt``
- /// is a number greater than the most recent one which it has seen,
- /// scoped to that ``email`` + ``client_secret`` pair. This is to
- /// avoid repeatedly sending the same email in the case of request
- /// retries between the POSTing user and the identity server.
- /// The client should increment this value if they desire a new
- /// email (e.g. a reminder) to be sent.
- int sendAttempt;
- /// Optional. When the validation is completed, the identity
- /// server will redirect the user to this URL.
- QString nextLink;
- };
- template <> struct JsonObjectConverter<RequestEmailValidation> {
- static void dumpTo(QJsonObject& jo, const RequestEmailValidation& pod);
- static void fillFrom(const QJsonObject& jo,
- RequestEmailValidation& pod);
- };
+template <>
+struct JsonObjectConverter<RequestEmailValidation>
+{
+ static void dumpTo(QJsonObject& jo, const RequestEmailValidation& pod);
+ static void fillFrom(const QJsonObject& jo, RequestEmailValidation& pod);
+};
} // namespace QMatrixClient
diff --git a/lib/identity/definitions/request_msisdn_validation.cpp b/lib/identity/definitions/request_msisdn_validation.cpp
index 9facbf7e..0087d202 100644
--- a/lib/identity/definitions/request_msisdn_validation.cpp
+++ b/lib/identity/definitions/request_msisdn_validation.cpp
@@ -7,7 +7,7 @@
using namespace QMatrixClient;
void JsonObjectConverter<RequestMsisdnValidation>::dumpTo(
- QJsonObject& jo, const RequestMsisdnValidation& pod)
+ QJsonObject& jo, const RequestMsisdnValidation& pod)
{
addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
addParam<>(jo, QStringLiteral("country"), pod.country);
@@ -17,7 +17,7 @@ void JsonObjectConverter<RequestMsisdnValidation>::dumpTo(
}
void JsonObjectConverter<RequestMsisdnValidation>::fillFrom(
- const QJsonObject& jo, RequestMsisdnValidation& result)
+ const QJsonObject& jo, RequestMsisdnValidation& result)
{
fromJson(jo.value("client_secret"_ls), result.clientSecret);
fromJson(jo.value("country"_ls), result.country);
diff --git a/lib/identity/definitions/request_msisdn_validation.h b/lib/identity/definitions/request_msisdn_validation.h
index c4fe479e..f8060cfc 100644
--- a/lib/identity/definitions/request_msisdn_validation.h
+++ b/lib/identity/definitions/request_msisdn_validation.h
@@ -6,38 +6,41 @@
#include "converters.h"
-#include "converters.h"
+namespace QMatrixClient
+{
+
+// Data structures
-namespace QMatrixClient {
- // Data structures
+struct RequestMsisdnValidation
+{
+ /// A unique string generated by the client, and used to identify
+ /// thevalidation attempt. It must be a string consisting of the
+ /// characters``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters
+ /// and itmust not be empty.
+ QString clientSecret;
+ /// The two-letter uppercase ISO country code that the number
+ /// in``phone_number`` should be parsed as if it were dialled from.
+ QString country;
+ /// The phone number to validate.
+ QString phoneNumber;
+ /// The server will only send an SMS if the ``send_attempt`` is anumber
+ /// greater than the most recent one which it has seen,scoped to that
+ /// ``country`` + ``phone_number`` + ``client_secret``triple. This is to
+ /// avoid repeatedly sending the same SMS inthe case of request retries
+ /// between the POSTing user and theidentity server. The client should
+ /// increment this value ifthey desire a new SMS (e.g. a reminder) to be
+ /// sent.
+ int sendAttempt;
+ /// Optional. When the validation is completed, the identityserver will
+ /// redirect the user to this URL.
+ QString nextLink;
+};
- struct RequestMsisdnValidation {
- /// A unique string generated by the client, and used to identify the
- /// validation attempt. It must be a string consisting of the characters
- /// ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and
- /// it must not be empty.
- QString clientSecret;
- /// The two-letter uppercase ISO country code that the number in
- /// ``phone_number`` should be parsed as if it were dialled from.
- QString country;
- /// The phone number to validate.
- QString phoneNumber;
- /// The server will only send an SMS if the ``send_attempt`` is a
- /// number greater than the most recent one which it has seen,
- /// scoped to that ``country`` + ``phone_number`` + ``client_secret``
- /// triple. This is to avoid repeatedly sending the same SMS in
- /// the case of request retries between the POSTing user and the
- /// identity server. The client should increment this value if
- /// they desire a new SMS (e.g. a reminder) to be sent.
- int sendAttempt;
- /// Optional. When the validation is completed, the identity
- /// server will redirect the user to this URL.
- QString nextLink;
- };
- template <> struct JsonObjectConverter<RequestMsisdnValidation> {
- static void dumpTo(QJsonObject& jo, const RequestMsisdnValidation& pod);
- static void fillFrom(const QJsonObject& jo,
- RequestMsisdnValidation& pod);
- };
+template <>
+struct JsonObjectConverter<RequestMsisdnValidation>
+{
+ static void dumpTo(QJsonObject& jo, const RequestMsisdnValidation& pod);
+ static void fillFrom(const QJsonObject& jo, RequestMsisdnValidation& pod);
+};
} // namespace QMatrixClient
diff --git a/lib/identity/definitions/sid.h b/lib/identity/definitions/sid.h
index 85462b46..752d62bb 100644
--- a/lib/identity/definitions/sid.h
+++ b/lib/identity/definitions/sid.h
@@ -6,19 +6,25 @@
#include "converters.h"
-namespace QMatrixClient {
- // Data structures
+namespace QMatrixClient
+{
- struct Sid {
- /// The session ID. Session IDs are opaque strings generated by the
- /// identity server. They must consist entirely of the characters
- /// ``[0-9a-zA-Z.=_-]``. Their length must not exceed 255 characters and
- /// they must not be empty.
- QString sid;
- };
- template <> struct JsonObjectConverter<Sid> {
- static void dumpTo(QJsonObject& jo, const Sid& pod);
- static void fillFrom(const QJsonObject& jo, Sid& pod);
- };
+// Data structures
+
+struct Sid
+{
+ /// The session ID. Session IDs are opaque strings generated by the
+ /// identityserver. They must consist entirely of the
+ /// characters``[0-9a-zA-Z.=_-]``. Their length must not exceed 255
+ /// characters and theymust not be empty.
+ QString sid;
+};
+
+template <>
+struct JsonObjectConverter<Sid>
+{
+ static void dumpTo(QJsonObject& jo, const Sid& pod);
+ static void fillFrom(const QJsonObject& jo, Sid& pod);
+};
} // namespace QMatrixClient
diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp
index a023d4f7..a0a3dc29 100644
--- a/lib/jobs/basejob.cpp
+++ b/lib/jobs/basejob.cpp
@@ -32,7 +32,8 @@
using namespace QMatrixClient;
-struct NetworkReplyDeleter : public QScopedPointerDeleteLater {
+struct NetworkReplyDeleter : public QScopedPointerDeleteLater
+{
static inline void cleanup(QNetworkReply* reply)
{
if (reply && reply->isRunning())
@@ -43,18 +44,17 @@ struct NetworkReplyDeleter : public QScopedPointerDeleteLater {
class BaseJob::Private
{
- public:
+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)
- : verb(v),
- apiEndpoint(std::move(endpoint)),
- requestQuery(q),
- requestData(std::move(data)),
- needsToken(nt)
- {
- }
+ : verb(v)
+ , apiEndpoint(std::move(endpoint))
+ , requestQuery(q)
+ , requestData(std::move(data))
+ , needsToken(nt)
+ {}
void sendRequest(bool inBackground);
const JobTimeoutConfig& getCurrentTimeoutConfig() const;
@@ -94,8 +94,7 @@ class BaseJob::Private
BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
bool needsToken)
: BaseJob(verb, name, endpoint, Query {}, Data {}, needsToken)
-{
-}
+{}
BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
const Query& query, Data&& data, bool needsToken)
@@ -121,9 +120,9 @@ QUrl BaseJob::requestUrl() const
bool BaseJob::isBackground() const
{
return d->reply
- && d->reply->request()
- .attribute(QNetworkRequest::BackgroundRequestAttribute)
- .toBool();
+ && d->reply->request()
+ .attribute(QNetworkRequest::BackgroundRequestAttribute)
+ .toBool();
}
const QString& BaseJob::apiEndpoint() const { return d->apiEndpoint; }
@@ -182,7 +181,7 @@ QUrl BaseJob::makeRequestUrl(QUrl baseUrl, const QString& path,
if (!pathBase.endsWith('/') && !path.startsWith('/'))
pathBase.push_back('/');
- baseUrl.setPath(pathBase + path);
+ baseUrl.setPath(pathBase + path, QUrl::TolerantMode);
baseUrl.setQuery(query);
return baseUrl;
}
@@ -253,8 +252,7 @@ void BaseJob::sendRequest(bool inBackground)
if (!d->requestQuery.isEmpty())
qCDebug(d->logCat) << " query:" << d->requestQuery.toString();
d->sendRequest(inBackground);
- connect(d->reply.data(), &QNetworkReply::finished, this,
- &BaseJob::gotReply);
+ connect(d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply);
if (d->reply->isRunning()) {
connect(d->reply.data(), &QNetworkReply::metaDataChanged, this,
&BaseJob::checkReply);
@@ -279,10 +277,10 @@ void BaseJob::gotReply()
else {
// FIXME: Factor out to smth like BaseJob::handleError()
d->rawResponse = d->reply->readAll();
- const auto jsonBody =
- d->reply->rawHeader("Content-Type") == "application/json";
- qCDebug(d->logCat).noquote() << "Error body (truncated if long):"
- << d->rawResponse.left(500);
+ const auto jsonBody = d->reply->rawHeader("Content-Type")
+ == "application/json";
+ qCDebug(d->logCat).noquote()
+ << "Error body (truncated if long):" << d->rawResponse.left(500);
if (jsonBody) {
auto json = QJsonDocument::fromJson(d->rawResponse).object();
const auto errCode = json.value("errcode"_ls).toString();
@@ -291,8 +289,8 @@ void BaseJob::gotReply()
QString msg = tr("Too many requests");
auto retryInterval = json.value("retry_after_ms"_ls).toInt(-1);
if (retryInterval != -1)
- msg += tr(", next retry advised after %1 ms")
- .arg(retryInterval);
+ msg +=
+ tr(", next retry advised after %1 ms").arg(retryInterval);
else // We still have to figure some reasonable interval
retryInterval = getNextRetryInterval();
@@ -301,7 +299,7 @@ void BaseJob::gotReply()
// Shortcut to retry instead of executing finishJob()
stop();
qCWarning(d->logCat)
- << this << "will retry in" << retryInterval << "ms";
+ << this << "will retry in" << retryInterval << "ms";
d->retryTimer.start(retryInterval);
emit retryScheduled(d->retriesTaken, retryInterval);
return;
@@ -314,11 +312,10 @@ void BaseJob::gotReply()
d->status.code = UnsupportedRoomVersionError;
if (json.contains("room_version"))
d->status.message =
- tr("Requested room version: %1")
- .arg(json.value("room_version").toString());
+ tr("Requested room version: %1")
+ .arg(json.value("room_version").toString());
} else if (!json.isEmpty()) // Not localisable on the client side
- setStatus(IncorrectRequestError,
- json.value("error"_ls).toString());
+ setStatus(d->status.code, json.value("error"_ls).toString());
}
}
@@ -341,7 +338,7 @@ bool checkContentType(const QByteArray& type, const QByteArrayList& patterns)
Q_ASSERT_X(patternParts.size() <= 2, __FUNCTION__,
"BaseJob: Expected content type should have up to two"
" /-separated parts; violating pattern: "
- + pattern);
+ + pattern);
if (ctype.split('/').front() == patternParts.front()
&& patternParts.back() == "*")
@@ -358,25 +355,23 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const
// so check genuine HTTP codes. The below processing is based on
// https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
const auto httpCodeHeader =
- reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+ reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (!httpCodeHeader.isValid()) {
qCWarning(d->logCat) << this << "didn't get valid HTTP headers";
return { NetworkError, reply->errorString() };
}
const QString replyState = reply->isRunning()
- ? QStringLiteral("(tentative)")
- : QStringLiteral("(final)");
+ ? QStringLiteral("(tentative)")
+ : QStringLiteral("(final)");
const auto urlString = '|' + d->reply->url().toDisplayString();
const auto httpCode = httpCodeHeader.toInt();
const auto reason =
- reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute)
- .toString();
+ reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
if (httpCode / 100 == 2) // 2xx
{
qCDebug(d->logCat).noquote().nospace() << this << urlString;
- qCDebug(d->logCat).noquote()
- << " " << httpCode << reason << replyState;
+ qCDebug(d->logCat).noquote() << " " << httpCode << reason << replyState;
if (!checkContentType(reply->rawHeader("Content-Type"),
d->expectedContentTypes))
return { UnexpectedResponseTypeWarning,
@@ -423,7 +418,7 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const
BaseJob::Status BaseJob::parseReply(QNetworkReply* reply)
{
d->rawResponse = reply->readAll();
- QJsonParseError error;
+ QJsonParseError error { 0, QJsonParseError::MissingObject };
const auto& json = QJsonDocument::fromJson(d->rawResponse, &error);
if (error.error == QJsonParseError::NoError)
return parseJson(json);
@@ -440,7 +435,7 @@ void BaseJob::stop()
d->reply->disconnect(this); // Ignore whatever comes from the reply
if (d->reply->isRunning()) {
qCWarning(d->logCat)
- << this << "stopped without ready network reply";
+ << this << "stopped without ready network reply";
d->reply->abort();
}
} else
@@ -455,12 +450,12 @@ void BaseJob::finishJob()
// TODO: The whole retrying thing should be put to ConnectionManager
// otherwise independently retrying jobs make a bit of notification
// storm towards the UI.
- const auto retryInterval =
- error() == TimeoutError ? 0 : getNextRetryInterval();
+ const auto retryInterval = error() == TimeoutError
+ ? 0
+ : getNextRetryInterval();
++d->retriesTaken;
- qCWarning(d->logCat).nospace()
- << this << ": retry #" << d->retriesTaken << " in "
- << retryInterval / 1000 << " s";
+ qCWarning(d->logCat).nospace() << this << ": retry #" << d->retriesTaken
+ << " in " << retryInterval / 1000 << " s";
d->retryTimer.start(retryInterval);
emit retryScheduled(d->retriesTaken, retryInterval);
return;
@@ -510,19 +505,20 @@ BaseJob::Status BaseJob::status() const { return d->status; }
QByteArray BaseJob::rawData(int bytesAtMost) const
{
return bytesAtMost > 0 && d->rawResponse.size() > bytesAtMost
- ? d->rawResponse.left(bytesAtMost)
- : d->rawResponse;
+ ? d->rawResponse.left(bytesAtMost)
+ : d->rawResponse;
}
QString BaseJob::rawDataSample(int bytesAtMost) const
{
auto data = rawData(bytesAtMost);
Q_ASSERT(data.size() <= d->rawResponse.size());
- return data.size() == d->rawResponse.size() ? data
- : data
- + tr("...(truncated, %Ln bytes in total)",
- "Comes after trimmed raw network response",
- d->rawResponse.size());
+ return data.size() == d->rawResponse.size()
+ ? data
+ : data
+ + tr("...(truncated, %Ln bytes in total)",
+ "Comes after trimmed raw network response",
+ d->rawResponse.size());
}
QString BaseJob::statusCaption() const
@@ -538,8 +534,6 @@ QString BaseJob::statusCaption() const
return tr("Request was abandoned");
case NetworkError:
return tr("Network problems");
- case JsonParseError:
- return tr("Response could not be parsed");
case TimeoutError:
return tr("Request timed out");
case ContentAccessError:
@@ -573,10 +567,25 @@ QUrl BaseJob::errorUrl() const { return d->errorUrl; }
void BaseJob::setStatus(Status s)
{
+ // The crash that led to this code has been reported in
+ // https://github.com/QMatrixClient/Quaternion/issues/566 - basically,
+ // when cleaning up childrent of a deleted Connection, there's a chance
+ // of pending jobs being abandoned, calling setStatus(Abandoned).
+ // There's nothing wrong with this; however, the safety check for
+ // cleartext access tokens below uses d->connection - which is a dangling
+ // pointer.
+ // To alleviate that, a stricter condition is applied, that for Abandoned
+ // and to-be-Abandoned jobs the status message will be disregarded entirely.
+ // For 0.6 we might rectify the situation by making d->connection
+ // a QPointer<> (and derive ConnectionData from QObject, respectively).
+ if (d->status.code == Abandoned || s.code == Abandoned)
+ s.message.clear();
+
if (d->status == s)
return;
- if (d->connection && !d->connection->accessToken().isEmpty())
+ if (!s.message.isEmpty() && d->connection
+ && !d->connection->accessToken().isEmpty())
s.message.replace(d->connection->accessToken(), "(REDACTED)");
if (!s.good())
qCWarning(d->logCat) << this << "status" << s;
diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h
index 8ff25d42..04d79c66 100644
--- a/lib/jobs/basejob.h
+++ b/lib/jobs/basejob.h
@@ -28,329 +28,350 @@
class QNetworkReply;
class QSslError;
-namespace QMatrixClient {
- class ConnectionData;
-
- enum class HttpVerb { Get, Put, Post, Delete };
+namespace QMatrixClient
+{
+class ConnectionData;
+
+enum class HttpVerb
+{
+ Get,
+ Put,
+ Post,
+ Delete
+};
+
+struct JobTimeoutConfig
+{
+ int jobTimeout;
+ int nextRetryInterval;
+};
+
+class BaseJob : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT)
+ Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries)
+public:
+ enum StatusCode
+ {
+ NoError = 0 // To be compatible with Qt conventions
+ ,
+ Success = 0,
+ Pending = 1,
+ WarningLevel = 20,
+ UnexpectedResponseType = 21,
+ UnexpectedResponseTypeWarning = UnexpectedResponseType,
+ Abandoned = 50 //< A very brief period between abandoning and object
+ //deletion
+ ,
+ ErrorLevel = 100 //< Errors have codes starting from this
+ ,
+ NetworkError = 100,
+ Timeout,
+ TimeoutError = Timeout,
+ ContentAccessError,
+ NotFoundError,
+ IncorrectRequest,
+ IncorrectRequestError = IncorrectRequest,
+ IncorrectResponse,
+ IncorrectResponseError = IncorrectResponse,
+ JsonParseError //< deprecated; Use IncorrectResponse instead
+ = IncorrectResponse,
+ TooManyRequests,
+ TooManyRequestsError = TooManyRequests,
+ RequestNotImplemented,
+ RequestNotImplementedError = RequestNotImplemented,
+ UnsupportedRoomVersion,
+ UnsupportedRoomVersionError = UnsupportedRoomVersion,
+ NetworkAuthRequired,
+ NetworkAuthRequiredError = NetworkAuthRequired,
+ UserConsentRequired,
+ UserConsentRequiredError = UserConsentRequired,
+ UserDefinedError = 256
+ };
- struct JobTimeoutConfig {
- int jobTimeout;
- int nextRetryInterval;
+ /**
+ * A simple wrapper around QUrlQuery that allows its creation from
+ * a list of string pairs
+ */
+ class Query : public QUrlQuery
+ {
+ public:
+ using QUrlQuery::QUrlQuery;
+ Query() = default;
+ Query(const std::initializer_list<QPair<QString, QString>>& l)
+ {
+ setQueryItems(l);
+ }
};
- class BaseJob : public QObject
+ using Data = RequestData;
+
+ /**
+ * This structure stores the status of a server call job. The status
+ * consists of a code, that is described (but not delimited) by the
+ * respective enum, and a freeform message.
+ *
+ * To extend the list of error codes, define an (anonymous) enum
+ * along the lines of StatusCode, with additional values
+ * starting at UserDefinedError
+ */
+ class Status
{
- Q_OBJECT
- Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT)
- Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries)
- public:
- /* Just in case, the values are compatible with KJob
- * (which BaseJob used to inherit from). */
- enum StatusCode {
- NoError = 0 // To be compatible with Qt conventions
- ,
- Success = 0,
- Pending = 1,
- WarningLevel = 20,
- UnexpectedResponseTypeWarning = 21,
- Abandoned = 50 //< A very brief period between abandoning and object
- //deletion
- ,
- ErrorLevel = 100 //< Errors have codes starting from this
- ,
- NetworkError = 100,
- JsonParseError // TODO: Merge into IncorrectResponseError
- ,
- TimeoutError,
- ContentAccessError,
- NotFoundError,
- IncorrectRequestError,
- IncorrectResponseError,
- TooManyRequestsError,
- RequestNotImplementedError,
- UnsupportedRoomVersionError,
- NetworkAuthRequiredError,
- UserConsentRequiredError,
- UserDefinedError = 200
- };
-
- /**
- * A simple wrapper around QUrlQuery that allows its creation from
- * a list of string pairs
- */
- class Query : public QUrlQuery
+ public:
+ Status(StatusCode c)
+ : code(c)
+ {}
+ Status(int c, QString m)
+ : code(c)
+ , message(std::move(m))
+ {}
+
+ bool good() const { return code < ErrorLevel; }
+ friend QDebug operator<<(QDebug dbg, const Status& s)
{
- public:
- using QUrlQuery::QUrlQuery;
- Query() = default;
- Query(const std::initializer_list<QPair<QString, QString>>& l)
- {
- setQueryItems(l);
- }
- };
-
- using Data = RequestData;
-
- /**
- * This structure stores the status of a server call job. The status
- * consists of a code, that is described (but not delimited) by the
- * respective enum, and a freeform message.
- *
- * To extend the list of error codes, define an (anonymous) enum
- * along the lines of StatusCode, with additional values
- * starting at UserDefinedError
- */
- class Status
+ QDebugStateSaver _s(dbg);
+ return dbg.noquote().nospace() << s.code << ": " << s.message;
+ }
+
+ bool operator==(const Status& other) const
{
- public:
- Status(StatusCode c) : code(c) {}
- Status(int c, QString m) : code(c), message(std::move(m)) {}
-
- bool good() const { return code < ErrorLevel; }
- friend QDebug operator<<(QDebug dbg, const Status& s)
- {
- QDebugStateSaver _s(dbg);
- return dbg.noquote().nospace() << s.code << ": " << s.message;
- }
-
- bool operator==(const Status& other) const
- {
- return code == other.code && message == other.message;
- }
- bool operator!=(const Status& other) const
- {
- return !operator==(other);
- }
-
- int code;
- QString message;
- };
-
- using duration_t = int; // milliseconds
-
- public:
- BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
- bool needsToken = true);
- BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
- const Query& query, Data&& data = {}, bool needsToken = true);
-
- QUrl requestUrl() const;
- bool isBackground() const;
-
- /** Current status of the job */
- Status status() const;
- /** Short human-friendly message on the job status */
- QString statusCaption() const;
- /** Get raw response body as received from the server
- * \param bytesAtMost return this number of leftmost bytes, or -1
- * to return the entire response
- */
- QByteArray rawData(int bytesAtMost = -1) const;
- /** Get UI-friendly sample of raw data
- *
- * This is almost the same as rawData but appends the "truncated"
- * suffix if not all data fit in bytesAtMost. This call is
- * recommended to present a sample of raw data as "details" next to
- * error messages. Note that the default \p bytesAtMost value is
- * also tailored to UI cases.
- */
- QString rawDataSample(int bytesAtMost = 65535) const;
-
- /** Error (more generally, status) code
- * Equivalent to status().code
- * \sa status
- */
- int error() const;
- /** Error-specific message, as returned by the server */
- virtual QString errorString() const;
- /** A URL to help/clarify the error, if provided by the server */
- QUrl errorUrl() const;
-
- int maxRetries() const;
- void setMaxRetries(int newMaxRetries);
-
- Q_INVOKABLE duration_t getCurrentTimeout() const;
- Q_INVOKABLE duration_t getNextRetryInterval() const;
- Q_INVOKABLE duration_t millisToRetry() const;
-
- friend QDebug operator<<(QDebug dbg, const BaseJob* j)
+ return code == other.code && message == other.message;
+ }
+ bool operator!=(const Status& other) const
{
- return dbg << j->objectName();
+ return !operator==(other);
}
- public slots:
- void start(const ConnectionData* connData, bool inBackground = false);
-
- /**
- * Abandons the result of this job, arrived or unarrived.
- *
- * This aborts waiting for a reply from the server (if there was
- * any pending) and deletes the job object. No result signals
- * (result, success, failure) are emitted.
- */
- void abandon();
-
- signals:
- /** The job is about to send a network request */
- void aboutToStart();
-
- /** The job has sent a network request */
- void started();
-
- /** The job has changed its status */
- void statusChanged(Status newStatus);
-
- /**
- * The previous network request has failed; the next attempt will
- * be done in the specified time
- * @param nextAttempt the 1-based number of attempt (will always be more
- * than 1)
- * @param inMilliseconds the interval after which the next attempt will
- * be taken
- */
- void retryScheduled(int nextAttempt, int inMilliseconds);
-
- /**
- * Emitted when the job is finished, in any case. It is used to notify
- * observers that the job is terminated and that progress can be hidden.
- *
- * This should not be emitted directly by subclasses;
- * use finishJob() instead.
- *
- * In general, to be notified of a job's completion, client code
- * should connect to result(), success(), or failure()
- * rather than finished(). However if you need to track the job's
- * lifecycle you should connect to this instead of result();
- * in particular, only this signal will be emitted on abandoning.
- *
- * @param job the job that emitted this signal
- *
- * @see result, success, failure
- */
- void finished(BaseJob* job);
-
- /**
- * Emitted when the job is finished (except when abandoned).
- *
- * Use error() to know if the job was finished with error.
- *
- * @param job the job that emitted this signal
- *
- * @see success, failure
- */
- void result(BaseJob* job);
-
- /**
- * Emitted together with result() in case there's no error.
- *
- * @see result, failure
- */
- void success(BaseJob*);
-
- /**
- * Emitted together with result() if there's an error.
- * Similar to result(), this won't be emitted in case of abandon().
- *
- * @see result, success
- */
- void failure(BaseJob*);
-
- void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
- void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
-
- protected:
- using headers_t = QHash<QByteArray, QByteArray>;
-
- const QString& apiEndpoint() const;
- 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;
- void setRequestQuery(const QUrlQuery& query);
- const Data& requestData() const;
- void setRequestData(Data&& data);
- const QByteArrayList& expectedContentTypes() const;
- void addExpectedContentType(const QByteArray& contentType);
- void setExpectedContentTypes(const QByteArrayList& contentTypes);
-
- /** Construct a URL out of baseUrl, path and query
- * The function automatically adds '/' between baseUrl's path and
- * \p path if necessary. The query component of \p baseUrl
- * is ignored.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& path,
- const QUrlQuery& query = {});
-
- virtual void beforeStart(const ConnectionData* connData);
- virtual void afterStart(const ConnectionData* connData,
- QNetworkReply* reply);
- virtual void beforeAbandon(QNetworkReply*);
-
- /**
- * Used by gotReply() to check the received reply for general
- * issues such as network errors or access denial.
- * Returning anything except NoError/Success prevents
- * further parseReply()/parseJson() invocation.
- *
- * @param reply the reply received from the server
- * @return the result of checking the reply
- *
- * @see gotReply
- */
- virtual Status doCheckReply(QNetworkReply* reply) const;
-
- /**
- * Processes the reply. By default, parses the reply into
- * a QJsonDocument and calls parseJson() if it's a valid JSON.
- *
- * @param reply raw contents of a HTTP reply from the server (without
- * headers)
- *
- * @see gotReply, parseJson
- */
- virtual Status parseReply(QNetworkReply* reply);
-
- /**
- * Processes the JSON document received from the Matrix server.
- * By default returns succesful status without analysing the JSON.
- *
- * @param json valid JSON document received from the server
- *
- * @see parseReply
- */
- virtual Status parseJson(const QJsonDocument&);
-
- void setStatus(Status s);
- void setStatus(int code, QString message);
-
- // Q_DECLARE_LOGGING_CATEGORY return different function types
- // in different versions
- using LoggingCategory = decltype(JOBS)*;
- void setLoggingCategory(LoggingCategory lcf);
-
- // Job objects should only be deleted via QObject::deleteLater
- ~BaseJob() override;
-
- protected slots:
- void timeout();
-
- private slots:
- void sendRequest(bool inBackground);
- void checkReply();
- void gotReply();
-
- private:
- void stop();
- void finishJob();
-
- class Private;
- QScopedPointer<Private> d;
+ int code;
+ QString message;
};
- inline bool isJobRunning(BaseJob* job)
+ using duration_t = int; // milliseconds
+
+public:
+ BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
+ bool needsToken = true);
+ BaseJob(HttpVerb verb, const QString& name, const QString& endpoint,
+ const Query& query, Data&& data = {}, bool needsToken = true);
+
+ QUrl requestUrl() const;
+ bool isBackground() const;
+
+ /** Current status of the job */
+ Status status() const;
+ /** Short human-friendly message on the job status */
+ QString statusCaption() const;
+ /** Get raw response body as received from the server
+ * \param bytesAtMost return this number of leftmost bytes, or -1
+ * to return the entire response
+ */
+ QByteArray rawData(int bytesAtMost = -1) const;
+ /** Get UI-friendly sample of raw data
+ *
+ * This is almost the same as rawData but appends the "truncated"
+ * suffix if not all data fit in bytesAtMost. This call is
+ * recommended to present a sample of raw data as "details" next to
+ * error messages. Note that the default \p bytesAtMost value is
+ * also tailored to UI cases.
+ */
+ QString rawDataSample(int bytesAtMost = 65535) const;
+
+ /** Error (more generally, status) code
+ * Equivalent to status().code
+ * \sa status
+ */
+ int error() const;
+ /** Error-specific message, as returned by the server */
+ virtual QString errorString() const;
+ /** A URL to help/clarify the error, if provided by the server */
+ QUrl errorUrl() const;
+
+ int maxRetries() const;
+ void setMaxRetries(int newMaxRetries);
+
+ Q_INVOKABLE duration_t getCurrentTimeout() const;
+ Q_INVOKABLE duration_t getNextRetryInterval() const;
+ Q_INVOKABLE duration_t millisToRetry() const;
+
+ friend QDebug operator<<(QDebug dbg, const BaseJob* j)
{
- return job && job->error() == BaseJob::Pending;
+ return dbg << j->objectName();
}
+
+public slots:
+ void start(const ConnectionData* connData, bool inBackground = false);
+
+ /**
+ * Abandons the result of this job, arrived or unarrived.
+ *
+ * This aborts waiting for a reply from the server (if there was
+ * any pending) and deletes the job object. No result signals
+ * (result, success, failure) are emitted.
+ */
+ void abandon();
+
+signals:
+ /** The job is about to send a network request */
+ void aboutToStart();
+
+ /** The job has sent a network request */
+ void started();
+
+ /** The job has changed its status */
+ void statusChanged(Status newStatus);
+
+ /**
+ * The previous network request has failed; the next attempt will
+ * be done in the specified time
+ * @param nextAttempt the 1-based number of attempt (will always be more
+ * than 1)
+ * @param inMilliseconds the interval after which the next attempt will be
+ * taken
+ */
+ void retryScheduled(int nextAttempt, int inMilliseconds);
+
+ /**
+ * Emitted when the job is finished, in any case. It is used to notify
+ * observers that the job is terminated and that progress can be hidden.
+ *
+ * This should not be emitted directly by subclasses;
+ * use finishJob() instead.
+ *
+ * In general, to be notified of a job's completion, client code
+ * should connect to result(), success(), or failure()
+ * rather than finished(). However if you need to track the job's
+ * lifecycle you should connect to this instead of result();
+ * in particular, only this signal will be emitted on abandoning.
+ *
+ * @param job the job that emitted this signal
+ *
+ * @see result, success, failure
+ */
+ void finished(BaseJob* job);
+
+ /**
+ * Emitted when the job is finished (except when abandoned).
+ *
+ * Use error() to know if the job was finished with error.
+ *
+ * @param job the job that emitted this signal
+ *
+ * @see success, failure
+ */
+ void result(BaseJob* job);
+
+ /**
+ * Emitted together with result() in case there's no error.
+ *
+ * @see result, failure
+ */
+ void success(BaseJob*);
+
+ /**
+ * Emitted together with result() if there's an error.
+ * Similar to result(), this won't be emitted in case of abandon().
+ *
+ * @see result, success
+ */
+ void failure(BaseJob*);
+
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
+
+protected:
+ using headers_t = QHash<QByteArray, QByteArray>;
+
+ const QString& apiEndpoint() const;
+ 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;
+ void setRequestQuery(const QUrlQuery& query);
+ const Data& requestData() const;
+ void setRequestData(Data&& data);
+ const QByteArrayList& expectedContentTypes() const;
+ void addExpectedContentType(const QByteArray& contentType);
+ void setExpectedContentTypes(const QByteArrayList& contentTypes);
+
+ /** Construct a URL out of baseUrl, path and query
+ * The function automatically adds '/' between baseUrl's path and
+ * \p path if necessary. The query component of \p baseUrl
+ * is ignored.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& path,
+ const QUrlQuery& query = {});
+
+ virtual void beforeStart(const ConnectionData* connData);
+ virtual void afterStart(const ConnectionData* connData,
+ QNetworkReply* reply);
+ virtual void beforeAbandon(QNetworkReply*);
+
+ /**
+ * Used by gotReply() to check the received reply for general
+ * issues such as network errors or access denial.
+ * Returning anything except NoError/Success prevents
+ * further parseReply()/parseJson() invocation.
+ *
+ * @param reply the reply received from the server
+ * @return the result of checking the reply
+ *
+ * @see gotReply
+ */
+ virtual Status doCheckReply(QNetworkReply* reply) const;
+
+ /**
+ * Processes the reply. By default, parses the reply into
+ * a QJsonDocument and calls parseJson() if it's a valid JSON.
+ *
+ * @param reply raw contents of a HTTP reply from the server (without
+ * headers)
+ *
+ * @see gotReply, parseJson
+ */
+ virtual Status parseReply(QNetworkReply* reply);
+
+ /**
+ * Processes the JSON document received from the Matrix server.
+ * By default returns succesful status without analysing the JSON.
+ *
+ * @param json valid JSON document received from the server
+ *
+ * @see parseReply
+ */
+ virtual Status parseJson(const QJsonDocument&);
+
+ void setStatus(Status s);
+ void setStatus(int code, QString message);
+
+ // Q_DECLARE_LOGGING_CATEGORY return different function types
+ // in different versions
+ using LoggingCategory = decltype(JOBS)*;
+ void setLoggingCategory(LoggingCategory lcf);
+
+ // Job objects should only be deleted via QObject::deleteLater
+ ~BaseJob() override;
+
+protected slots:
+ void timeout();
+
+private slots:
+ void sendRequest(bool inBackground);
+ void checkReply();
+ void gotReply();
+
+private:
+ void stop();
+ void finishJob();
+
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+inline bool isJobRunning(BaseJob* job)
+{
+ return job && job->error() == BaseJob::Pending;
+}
} // namespace QMatrixClient
diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp
index 12aacb8b..3dff5a68 100644
--- a/lib/jobs/downloadfilejob.cpp
+++ b/lib/jobs/downloadfilejob.cpp
@@ -8,14 +8,15 @@ using namespace QMatrixClient;
class DownloadFileJob::Private
{
- public:
- Private() : tempFile(new QTemporaryFile()) {}
+public:
+ Private()
+ : tempFile(new QTemporaryFile())
+ {}
explicit Private(const QString& localFilename)
- : targetFile(new QFile(localFilename)),
- tempFile(new QFile(targetFile->fileName() + ".qmcdownload"))
- {
- }
+ : targetFile(new QFile(localFilename))
+ , tempFile(new QFile(targetFile->fileName() + ".qmcdownload"))
+ {}
QScopedPointer<QFile> targetFile;
QScopedPointer<QFile> tempFile;
@@ -23,16 +24,17 @@ class DownloadFileJob::Private
QUrl DownloadFileJob::makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri)
{
- return makeRequestUrl(baseUrl, mxcUri.authority(), mxcUri.path().mid(1));
+ return makeRequestUrl(std::move(baseUrl), mxcUri.authority(),
+ mxcUri.path().mid(1));
}
DownloadFileJob::DownloadFileJob(const QString& serverName,
const QString& mediaId,
const QString& localFilename)
- : GetContentJob(serverName, mediaId),
- d(localFilename.isEmpty() ? new Private : new Private(localFilename))
+ : GetContentJob(serverName, mediaId)
+ , d(localFilename.isEmpty() ? new Private : new Private(localFilename))
{
- setObjectName("DownloadFileJob");
+ setObjectName(QStringLiteral("DownloadFileJob"));
}
QString DownloadFileJob::targetFileName() const
@@ -49,8 +51,7 @@ void DownloadFileJob::beforeStart(const ConnectionData*)
setStatus(FileError, "Could not open the target file for writing");
return;
}
- if (!d->tempFile->isReadable()
- && !d->tempFile->open(QIODevice::WriteOnly)) {
+ if (!d->tempFile->isReadable() && !d->tempFile->open(QIODevice::WriteOnly)) {
qCWarning(JOBS) << "Couldn't open the temporary file"
<< d->tempFile->fileName() << "for writing";
setStatus(FileError, "Could not open the temporary download file");
diff --git a/lib/jobs/downloadfilejob.h b/lib/jobs/downloadfilejob.h
index fd34ba5a..58858448 100644
--- a/lib/jobs/downloadfilejob.h
+++ b/lib/jobs/downloadfilejob.h
@@ -2,27 +2,31 @@
#include "csapi/content-repo.h"
-namespace QMatrixClient {
- class DownloadFileJob : public GetContentJob
+namespace QMatrixClient
+{
+class DownloadFileJob : public GetContentJob
+{
+public:
+ enum
{
- public:
- enum { FileError = BaseJob::UserDefinedError + 1 };
+ FileError = BaseJob::UserDefinedError + 1
+ };
- using GetContentJob::makeRequestUrl;
- static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri);
+ using GetContentJob::makeRequestUrl;
+ static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri);
- DownloadFileJob(const QString& serverName, const QString& mediaId,
- const QString& localFilename = {});
+ DownloadFileJob(const QString& serverName, const QString& mediaId,
+ const QString& localFilename = {});
- QString targetFileName() const;
+ QString targetFileName() const;
- private:
- class Private;
- QScopedPointer<Private> d;
+private:
+ class Private;
+ QScopedPointer<Private> d;
- void beforeStart(const ConnectionData*) override;
- void afterStart(const ConnectionData*, QNetworkReply* reply) override;
- void beforeAbandon(QNetworkReply*) override;
- Status parseReply(QNetworkReply*) override;
- };
-}
+ void beforeStart(const ConnectionData*) override;
+ void afterStart(const ConnectionData*, QNetworkReply* reply) override;
+ void beforeAbandon(QNetworkReply*) override;
+ Status parseReply(QNetworkReply*) override;
+};
+} // namespace QMatrixClient
diff --git a/lib/jobs/mediathumbnailjob.cpp b/lib/jobs/mediathumbnailjob.cpp
index d3370f1f..db2bbc13 100644
--- a/lib/jobs/mediathumbnailjob.cpp
+++ b/lib/jobs/mediathumbnailjob.cpp
@@ -29,19 +29,16 @@ QUrl MediaThumbnailJob::makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri,
}
MediaThumbnailJob::MediaThumbnailJob(const QString& serverName,
- const QString& mediaId,
- QSize requestedSize)
+ const QString& mediaId, QSize requestedSize)
: GetContentThumbnailJob(serverName, mediaId, requestedSize.width(),
requestedSize.height())
-{
-}
+{}
MediaThumbnailJob::MediaThumbnailJob(const QUrl& mxcUri, QSize requestedSize)
: MediaThumbnailJob(mxcUri.authority(),
mxcUri.path().mid(1), // sans leading '/'
requestedSize)
-{
-}
+{}
QImage MediaThumbnailJob::thumbnail() const { return _thumbnail; }
@@ -60,5 +57,6 @@ BaseJob::Status MediaThumbnailJob::parseReply(QNetworkReply* reply)
if (_thumbnail.loadFromData(data()->readAll()))
return Success;
- return { IncorrectResponseError, "Could not read image data" };
+ return { IncorrectResponseError,
+ QStringLiteral("Could not read image data") };
}
diff --git a/lib/jobs/mediathumbnailjob.h b/lib/jobs/mediathumbnailjob.h
index 1dcf8ccb..eeabe7a9 100644
--- a/lib/jobs/mediathumbnailjob.h
+++ b/lib/jobs/mediathumbnailjob.h
@@ -22,25 +22,26 @@
#include <QtGui/QPixmap>
-namespace QMatrixClient {
- class MediaThumbnailJob : public GetContentThumbnailJob
- {
- public:
- using GetContentThumbnailJob::makeRequestUrl;
- static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri,
- QSize requestedSize);
-
- MediaThumbnailJob(const QString& serverName, const QString& mediaId,
- QSize requestedSize);
- MediaThumbnailJob(const QUrl& mxcUri, QSize requestedSize);
-
- QImage thumbnail() const;
- QImage scaledThumbnail(QSize toSize) const;
-
- protected:
- Status parseReply(QNetworkReply* reply) override;
-
- private:
- QImage _thumbnail;
- };
+namespace QMatrixClient
+{
+class MediaThumbnailJob : public GetContentThumbnailJob
+{
+public:
+ using GetContentThumbnailJob::makeRequestUrl;
+ static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri,
+ QSize requestedSize);
+
+ MediaThumbnailJob(const QString& serverName, const QString& mediaId,
+ QSize requestedSize);
+ MediaThumbnailJob(const QUrl& mxcUri, QSize requestedSize);
+
+ QImage thumbnail() const;
+ QImage scaledThumbnail(QSize toSize) const;
+
+protected:
+ Status parseReply(QNetworkReply* reply) override;
+
+private:
+ QImage _thumbnail;
+};
} // namespace QMatrixClient
diff --git a/lib/jobs/postreadmarkersjob.h b/lib/jobs/postreadmarkersjob.h
index 3c5cac89..d53ae66c 100644
--- a/lib/jobs/postreadmarkersjob.h
+++ b/lib/jobs/postreadmarkersjob.h
@@ -26,14 +26,14 @@ using namespace QMatrixClient;
class PostReadMarkersJob : public BaseJob
{
- public:
+public:
explicit PostReadMarkersJob(const QString& roomId,
const QString& readUpToEventId)
- : BaseJob(HttpVerb::Post, "PostReadMarkersJob",
- QStringLiteral("_matrix/client/r0/rooms/%1/read_markers")
- .arg(roomId))
+ : BaseJob(
+ HttpVerb::Post, "PostReadMarkersJob",
+ QStringLiteral("_matrix/client/r0/rooms/%1/read_markers").arg(roomId))
{
- setRequestData(QJsonObject {
- { QStringLiteral("m.fully_read"), readUpToEventId } });
+ setRequestData(
+ QJsonObject { { QStringLiteral("m.fully_read"), readUpToEventId } });
}
};
diff --git a/lib/jobs/requestdata.cpp b/lib/jobs/requestdata.cpp
index 477f49e7..8248d6b1 100644
--- a/lib/jobs/requestdata.cpp
+++ b/lib/jobs/requestdata.cpp
@@ -17,15 +17,22 @@ auto fromData(const QByteArray& data)
return source;
}
-template <typename JsonDataT> inline auto fromJson(const JsonDataT& jdata)
+template <typename JsonDataT>
+inline auto fromJson(const JsonDataT& jdata)
{
return fromData(QJsonDocument(jdata).toJson(QJsonDocument::Compact));
}
-RequestData::RequestData(const QByteArray& a) : _source(fromData(a)) {}
+RequestData::RequestData(const QByteArray& a)
+ : _source(fromData(a))
+{}
-RequestData::RequestData(const QJsonObject& jo) : _source(fromJson(jo)) {}
+RequestData::RequestData(const QJsonObject& jo)
+ : _source(fromJson(jo))
+{}
-RequestData::RequestData(const QJsonArray& ja) : _source(fromJson(ja)) {}
+RequestData::RequestData(const QJsonArray& ja)
+ : _source(fromJson(ja))
+{}
RequestData::~RequestData() = default;
diff --git a/lib/jobs/requestdata.h b/lib/jobs/requestdata.h
index 207ff731..974a9ddf 100644
--- a/lib/jobs/requestdata.h
+++ b/lib/jobs/requestdata.h
@@ -26,33 +26,33 @@ class QJsonArray;
class QJsonDocument;
class QIODevice;
-namespace QMatrixClient {
- /**
- * A simple wrapper that represents the request body.
- * Provides a unified interface to dump an unstructured byte stream
- * as well as JSON (and possibly other structures in the future) to
- * a QByteArray consumed by QNetworkAccessManager request methods.
- */
- class RequestData
- {
- public:
- RequestData() = default;
- RequestData(const QByteArray& a);
- RequestData(const QJsonObject& jo);
- RequestData(const QJsonArray& ja);
- RequestData(QIODevice* source)
- : _source(std::unique_ptr<QIODevice>(source))
- {
- }
- RequestData(const RequestData&) = delete;
- RequestData& operator=(const RequestData&) = delete;
- RequestData(RequestData&&) = default;
- RequestData& operator=(RequestData&&) = default;
- ~RequestData();
+namespace QMatrixClient
+{
+/**
+ * A simple wrapper that represents the request body.
+ * Provides a unified interface to dump an unstructured byte stream
+ * as well as JSON (and possibly other structures in the future) to
+ * a QByteArray consumed by QNetworkAccessManager request methods.
+ */
+class RequestData
+{
+public:
+ RequestData() = default;
+ RequestData(const QByteArray& a);
+ RequestData(const QJsonObject& jo);
+ RequestData(const QJsonArray& ja);
+ RequestData(QIODevice* source)
+ : _source(std::unique_ptr<QIODevice>(source))
+ {}
+ RequestData(const RequestData&) = delete;
+ RequestData& operator=(const RequestData&) = delete;
+ RequestData(RequestData&&) = default;
+ RequestData& operator=(RequestData&&) = default;
+ ~RequestData();
- QIODevice* source() const { return _source.get(); }
+ QIODevice* source() const { return _source.get(); }
- private:
- std::unique_ptr<QIODevice> _source;
- };
+private:
+ std::unique_ptr<QIODevice> _source;
+};
} // namespace QMatrixClient
diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp
index db11005a..f660e1b6 100644
--- a/lib/jobs/syncjob.cpp
+++ b/lib/jobs/syncjob.cpp
@@ -47,8 +47,7 @@ SyncJob::SyncJob(const QString& since, const Filter& filter, int timeout,
: SyncJob(since,
QJsonDocument(toJson(filter)).toJson(QJsonDocument::Compact),
timeout, presence)
-{
-}
+{}
BaseJob::Status SyncJob::parseJson(const QJsonDocument& data)
{
diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h
index 2afaf0f7..e2cec8f7 100644
--- a/lib/jobs/syncjob.h
+++ b/lib/jobs/syncjob.h
@@ -18,26 +18,26 @@
#pragma once
-#include "basejob.h"
-
#include "../csapi/definitions/sync_filter.h"
#include "../syncdata.h"
+#include "basejob.h"
-namespace QMatrixClient {
- class SyncJob : public BaseJob
- {
- public:
- explicit SyncJob(const QString& since = {}, const QString& filter = {},
- int timeout = -1, const QString& presence = {});
- explicit SyncJob(const QString& since, const Filter& filter,
- int timeout = -1, const QString& presence = {});
+namespace QMatrixClient
+{
+class SyncJob : public BaseJob
+{
+public:
+ explicit SyncJob(const QString& since = {}, const QString& filter = {},
+ int timeout = -1, const QString& presence = {});
+ explicit SyncJob(const QString& since, const Filter& filter,
+ int timeout = -1, const QString& presence = {});
- SyncData&& takeData() { return std::move(d); }
+ SyncData&& takeData() { return std::move(d); }
- protected:
- Status parseJson(const QJsonDocument& data) override;
+protected:
+ Status parseJson(const QJsonDocument& data) override;
- private:
- SyncData d;
- };
+private:
+ SyncData d;
+};
} // namespace QMatrixClient
diff --git a/lib/joinstate.h b/lib/joinstate.h
index ddaba9a5..f7c0cb2b 100644
--- a/lib/joinstate.h
+++ b/lib/joinstate.h
@@ -22,27 +22,28 @@
#include <array>
-namespace QMatrixClient {
- enum class JoinState : unsigned int {
- Join = 0x1,
- Invite = 0x2,
- Leave = 0x4,
- };
+namespace QMatrixClient
+{
+enum class JoinState : unsigned int
+{
+ Join = 0x1,
+ Invite = 0x2,
+ Leave = 0x4,
+};
- Q_DECLARE_FLAGS(JoinStates, JoinState)
+Q_DECLARE_FLAGS(JoinStates, JoinState)
- // We cannot use REGISTER_ENUM outside of a Q_OBJECT and besides, we want
- // to use strings that match respective JSON keys.
- static const std::array<const char*, 3> JoinStateStrings {
- { "join", "invite", "leave" }
- };
+// We cannot use REGISTER_ENUM outside of a Q_OBJECT and besides, we want
+// to use strings that match respective JSON keys.
+static const std::array<const char*, 3> JoinStateStrings { { "join", "invite",
+ "leave" } };
- inline const char* toCString(JoinState js)
- {
- size_t state = size_t(js), index = 0;
- while (state >>= 1)
- ++index;
- return JoinStateStrings[index];
- }
+inline const char* toCString(JoinState js)
+{
+ size_t state = size_t(js), index = 0;
+ while (state >>= 1)
+ ++index;
+ return JoinStateStrings[index];
+}
} // namespace QMatrixClient
Q_DECLARE_OPERATORS_FOR_FLAGS(QMatrixClient::JoinStates)
diff --git a/lib/logging.cpp b/lib/logging.cpp
index 5d70ba36..73cc59a1 100644
--- a/lib/logging.cpp
+++ b/lib/logging.cpp
@@ -19,9 +19,10 @@
#include "logging.h"
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
-#define LOGGING_CATEGORY(Name, Id) Q_LOGGING_CATEGORY((Name), (Id), QtInfoMsg)
+# define LOGGING_CATEGORY(Name, Id) \
+ Q_LOGGING_CATEGORY((Name), (Id), QtInfoMsg)
#else
-#define LOGGING_CATEGORY(Name, Id) Q_LOGGING_CATEGORY((Name), (Id))
+# define LOGGING_CATEGORY(Name, Id) Q_LOGGING_CATEGORY((Name), (Id))
#endif
// Use LOGGING_CATEGORY instead of Q_LOGGING_CATEGORY in the rest of the code
diff --git a/lib/logging.h b/lib/logging.h
index 06603322..a50c1795 100644
--- a/lib/logging.h
+++ b/lib/logging.h
@@ -28,54 +28,55 @@ Q_DECLARE_LOGGING_CATEGORY(EPHEMERAL)
Q_DECLARE_LOGGING_CATEGORY(JOBS)
Q_DECLARE_LOGGING_CATEGORY(SYNCJOB)
-namespace QMatrixClient {
- // QDebug manipulators
+namespace QMatrixClient
+{
+// QDebug manipulators
- using QDebugManip = QDebug (*)(QDebug);
+using QDebugManip = QDebug (*)(QDebug);
- /**
- * @brief QDebug manipulator to setup the stream for JSON output
- *
- * Originally made to encapsulate the change in QDebug behavior in Qt 5.4
- * and the respective addition of QDebug::noquote().
- * Together with the operator<<() helper, the proposed usage is
- * (similar to std:: I/O manipulators):
- *
- * @example qCDebug() << formatJson << json_object; // (QJsonObject, etc.)
- */
- inline QDebug formatJson(QDebug debug_object)
- {
+/**
+ * @brief QDebug manipulator to setup the stream for JSON output
+ *
+ * Originally made to encapsulate the change in QDebug behavior in Qt 5.4
+ * and the respective addition of QDebug::noquote().
+ * Together with the operator<<() helper, the proposed usage is
+ * (similar to std:: I/O manipulators):
+ *
+ * @example qCDebug() << formatJson << json_object; // (QJsonObject, etc.)
+ */
+inline QDebug formatJson(QDebug debug_object)
+{
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
- return debug_object;
+ return debug_object;
#else
- return debug_object.noquote();
+ return debug_object.noquote();
#endif
- }
+}
- /**
- * @brief A helper operator to facilitate usage of formatJson (and possibly
- * other manipulators)
- *
- * @param debug_object to output the json to
- * @param qdm a QDebug manipulator
- * @return a copy of debug_object that has its mode altered by qdm
- */
- inline QDebug operator<<(QDebug debug_object, QDebugManip qdm)
- {
- return qdm(debug_object);
- }
+/**
+ * @brief A helper operator to facilitate usage of formatJson (and possibly
+ * other manipulators)
+ *
+ * @param debug_object to output the json to
+ * @param qdm a QDebug manipulator
+ * @return a copy of debug_object that has its mode altered by qdm
+ */
+inline QDebug operator<<(QDebug debug_object, QDebugManip qdm)
+{
+ return qdm(debug_object);
+}
- inline qint64 profilerMinNsecs()
- {
- return
+inline qint64 profilerMinNsecs()
+{
+ return
#ifdef PROFILER_LOG_USECS
- PROFILER_LOG_USECS
+ PROFILER_LOG_USECS
#else
- 200
+ 200
#endif
- * 1000;
- }
+ * 1000;
}
+} // namespace QMatrixClient
inline QDebug operator<<(QDebug debug_object, const QElapsedTimer& et)
{
diff --git a/lib/networkaccessmanager.cpp b/lib/networkaccessmanager.cpp
index 174ac16e..9ac589b8 100644
--- a/lib/networkaccessmanager.cpp
+++ b/lib/networkaccessmanager.cpp
@@ -25,14 +25,14 @@ using namespace QMatrixClient;
class NetworkAccessManager::Private
{
- public:
+public:
QList<QSslError> ignoredSslErrors;
};
NetworkAccessManager::NetworkAccessManager(QObject* parent)
- : d(std::make_unique<Private>())
-{
-}
+ : QNetworkAccessManager(parent)
+ , d(std::make_unique<Private>())
+{}
QList<QSslError> NetworkAccessManager::ignoredSslErrors() const
{
@@ -69,10 +69,9 @@ NetworkAccessManager* NetworkAccessManager::instance()
NetworkAccessManager::~NetworkAccessManager() = default;
QNetworkReply* NetworkAccessManager::createRequest(
- Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
+ Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
- auto reply =
- QNetworkAccessManager::createRequest(op, request, outgoingData);
+ auto reply = QNetworkAccessManager::createRequest(op, request, outgoingData);
reply->ignoreSslErrors(d->ignoredSslErrors);
return reply;
}
diff --git a/lib/networkaccessmanager.h b/lib/networkaccessmanager.h
index ebaaa5b2..bf8f0cbc 100644
--- a/lib/networkaccessmanager.h
+++ b/lib/networkaccessmanager.h
@@ -22,27 +22,27 @@
#include <memory>
-namespace QMatrixClient {
- class NetworkAccessManager : public QNetworkAccessManager
- {
- Q_OBJECT
- public:
- NetworkAccessManager(QObject* parent = nullptr);
- ~NetworkAccessManager() override;
-
- QList<QSslError> ignoredSslErrors() const;
- void addIgnoredSslError(const QSslError& error);
- void clearIgnoredSslErrors();
-
- /** Get a pointer to the singleton */
- static NetworkAccessManager* instance();
-
- private:
- QNetworkReply*
- createRequest(Operation op, const QNetworkRequest& request,
- QIODevice* outgoingData = Q_NULLPTR) override;
-
- class Private;
- std::unique_ptr<Private> d;
- };
+namespace QMatrixClient
+{
+class NetworkAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+public:
+ NetworkAccessManager(QObject* parent = nullptr);
+ ~NetworkAccessManager() override;
+
+ QList<QSslError> ignoredSslErrors() const;
+ void addIgnoredSslError(const QSslError& error);
+ void clearIgnoredSslErrors();
+
+ /** Get a pointer to the singleton */
+ static NetworkAccessManager* instance();
+
+private:
+ QNetworkReply* createRequest(Operation op, const QNetworkRequest& request,
+ QIODevice* outgoingData = Q_NULLPTR) override;
+
+ class Private;
+ std::unique_ptr<Private> d;
+};
} // namespace QMatrixClient
diff --git a/lib/networksettings.cpp b/lib/networksettings.cpp
index de333884..f5655975 100644
--- a/lib/networksettings.cpp
+++ b/lib/networksettings.cpp
@@ -23,12 +23,12 @@ using namespace QMatrixClient;
void NetworkSettings::setupApplicationProxy() const
{
QNetworkProxy::setApplicationProxy(
- { proxyType(), proxyHostName(), proxyPort() });
+ { proxyType(), proxyHostName(), proxyPort() });
}
QMC_DEFINE_SETTING(NetworkSettings, QNetworkProxy::ProxyType, proxyType,
"proxy_type", QNetworkProxy::DefaultProxy, setProxyType)
QMC_DEFINE_SETTING(NetworkSettings, QString, proxyHostName, "proxy_hostname",
- "", setProxyHostName)
+ {}, setProxyHostName)
QMC_DEFINE_SETTING(NetworkSettings, quint16, proxyPort, "proxy_port", -1,
setProxyPort)
diff --git a/lib/networksettings.h b/lib/networksettings.h
index ca9c7dfc..0c21a9fe 100644
--- a/lib/networksettings.h
+++ b/lib/networksettings.h
@@ -24,22 +24,22 @@
Q_DECLARE_METATYPE(QNetworkProxy::ProxyType)
-namespace QMatrixClient {
- class NetworkSettings : public SettingsGroup
- {
- Q_OBJECT
- QMC_DECLARE_SETTING(QNetworkProxy::ProxyType, proxyType, setProxyType)
- QMC_DECLARE_SETTING(QString, proxyHostName, setProxyHostName)
- QMC_DECLARE_SETTING(quint16, proxyPort, setProxyPort)
- Q_PROPERTY(QString proxyHost READ proxyHostName WRITE setProxyHostName)
- public:
- template <typename... ArgTs>
- explicit NetworkSettings(ArgTs... qsettingsArgs)
- : SettingsGroup(QStringLiteral("Network"), qsettingsArgs...)
- {
- }
- ~NetworkSettings() override = default;
+namespace QMatrixClient
+{
+class NetworkSettings : public SettingsGroup
+{
+ Q_OBJECT
+ QMC_DECLARE_SETTING(QNetworkProxy::ProxyType, proxyType, setProxyType)
+ QMC_DECLARE_SETTING(QString, proxyHostName, setProxyHostName)
+ QMC_DECLARE_SETTING(quint16, proxyPort, setProxyPort)
+ Q_PROPERTY(QString proxyHost READ proxyHostName WRITE setProxyHostName)
+public:
+ template <typename... ArgTs>
+ explicit NetworkSettings(ArgTs... qsettingsArgs)
+ : SettingsGroup(QStringLiteral("Network"), qsettingsArgs...)
+ {}
+ ~NetworkSettings() override = default;
- Q_INVOKABLE void setupApplicationProxy() const;
- };
-}
+ Q_INVOKABLE void setupApplicationProxy() const;
+};
+} // namespace QMatrixClient
diff --git a/lib/qt_connection_util.h b/lib/qt_connection_util.h
index 0f36424f..1b3229d4 100644
--- a/lib/qt_connection_util.h
+++ b/lib/qt_connection_util.h
@@ -22,91 +22,88 @@
#include <QtCore/QPointer>
-namespace QMatrixClient {
- namespace _impl {
- template <typename SenderT, typename SignalT, typename ContextT,
- typename... ArgTs>
- inline QMetaObject::Connection
- connectUntil(SenderT* sender, SignalT signal, ContextT* context,
- std::function<bool(ArgTs...)> slot,
- Qt::ConnectionType connType)
- {
- // See https://bugreports.qt.io/browse/QTBUG-60339
+namespace QMatrixClient
+{
+namespace _impl
+{
+ template <typename SenderT, typename SignalT, typename ContextT, typename... ArgTs>
+ inline QMetaObject::Connection
+ connectUntil(SenderT* sender, SignalT signal, ContextT* context,
+ std::function<bool(ArgTs...)> slot, 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>();
+ auto pc = std::make_shared<QMetaObject::Connection>();
#else
- auto pc = std::make_unique<QMetaObject::Connection>();
+ auto pc = std::make_unique<QMetaObject::Connection>();
#endif
- auto& c = *pc; // Resolve a reference before pc is moved to lambda
- c = QObject::connect(
- sender, signal, context,
- [pc = std::move(pc), slot](ArgTs... args) {
- Q_ASSERT(
- *pc); // If it's been triggered, it should exist
- if (slot(std::forward<ArgTs>(args)...))
- QObject::disconnect(*pc);
- },
- connType);
- return c;
- }
+ auto& c = *pc; // Resolve a reference before pc is moved to lambda
+ c = QObject::connect(
+ sender, signal, context,
+ [pc = std::move(pc), slot](ArgTs... args) {
+ Q_ASSERT(*pc); // If it's been triggered, it should exist
+ if (slot(std::forward<ArgTs>(args)...))
+ QObject::disconnect(*pc);
+ },
+ connType);
+ return c;
}
+} // namespace _impl
- template <typename SenderT, typename SignalT, typename ContextT,
- typename FunctorT>
- inline auto connectUntil(SenderT* sender, SignalT signal, ContextT* context,
- const FunctorT& slot,
- Qt::ConnectionType connType = Qt::AutoConnection)
- {
- return _impl::connectUntil(
- sender, signal, context,
- typename function_traits<FunctorT>::function_type(slot),
- connType);
- }
+template <typename SenderT, typename SignalT, typename ContextT, typename FunctorT>
+inline auto connectUntil(SenderT* sender, SignalT signal, ContextT* context,
+ const FunctorT& slot,
+ Qt::ConnectionType connType = Qt::AutoConnection)
+{
+ return _impl::connectUntil(
+ sender, signal, context,
+ typename function_traits<FunctorT>::function_type(slot), connType);
+}
- /** Create a single-shot connection that triggers on the signal and
- * then self-disconnects
- *
- * Only supports DirectConnection type.
- */
- template <typename SenderT, typename SignalT, typename ReceiverT,
- typename SlotT>
- inline auto connectSingleShot(SenderT* sender, SignalT signal,
- ReceiverT* receiver, SlotT slot)
- {
- QMetaObject::Connection connection;
- connection = QObject::connect(sender, signal, receiver, slot,
- Qt::DirectConnection);
- Q_ASSERT(connection);
- QObject::connect(sender, signal, receiver,
- [connection] { QObject::disconnect(connection); },
- Qt::DirectConnection);
- return connection;
- }
+/** Create a single-shot connection that triggers on the signal and
+ * then self-disconnects
+ *
+ * Only supports DirectConnection type.
+ */
+template <typename SenderT, typename SignalT, typename ReceiverT, typename SlotT>
+inline auto connectSingleShot(SenderT* sender, SignalT signal,
+ ReceiverT* receiver, SlotT slot)
+{
+ QMetaObject::Connection connection;
+ connection = QObject::connect(sender, signal, receiver, slot,
+ Qt::DirectConnection);
+ Q_ASSERT(connection);
+ QObject::connect(
+ sender, signal, receiver,
+ [connection] { QObject::disconnect(connection); }, Qt::DirectConnection);
+ return connection;
+}
- /** A guard pointer that disconnects an interested object upon destruction
- * It's almost QPointer<> except that you have to initialise it with one
- * more additional parameter - a pointer to a QObject that will be
- * disconnected from signals of the underlying pointer upon the guard's
- * destruction.
- */
- template <typename T> class ConnectionsGuard : public QPointer<T>
+/** A guard pointer that disconnects an interested object upon destruction
+ * It's almost QPointer<> except that you have to initialise it with one
+ * more additional parameter - a pointer to a QObject that will be
+ * disconnected from signals of the underlying pointer upon the guard's
+ * destruction.
+ */
+template <typename T>
+class ConnectionsGuard : public QPointer<T>
+{
+public:
+ ConnectionsGuard(T* publisher, QObject* subscriber)
+ : QPointer<T>(publisher)
+ , subscriber(subscriber)
+ {}
+ ~ConnectionsGuard()
{
- public:
- ConnectionsGuard(T* publisher, QObject* subscriber)
- : QPointer<T>(publisher), subscriber(subscriber)
- {
- }
- ~ConnectionsGuard()
- {
- if (*this)
- (*this)->disconnect(subscriber);
- }
- ConnectionsGuard(ConnectionsGuard&&) = default;
- ConnectionsGuard& operator=(ConnectionsGuard&&) = default;
- Q_DISABLE_COPY(ConnectionsGuard)
- using QPointer<T>::operator=;
+ if (*this)
+ (*this)->disconnect(subscriber);
+ }
+ ConnectionsGuard(ConnectionsGuard&&) = default;
+ ConnectionsGuard& operator=(ConnectionsGuard&&) = default;
+ Q_DISABLE_COPY(ConnectionsGuard)
+ using QPointer<T>::operator=;
- private:
- QObject* subscriber;
- };
-}
+private:
+ QObject* subscriber;
+};
+} // namespace QMatrixClient
diff --git a/lib/room.cpp b/lib/room.cpp
index c7c94fe5..ec2a34ef 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -21,6 +21,9 @@
#include "avatar.h"
#include "connection.h"
#include "converters.h"
+#include "syncdata.h"
+#include "user.h"
+
#include "csapi/account-data.h"
#include "csapi/banning.h"
#include "csapi/inviting.h"
@@ -33,6 +36,7 @@
#include "csapi/room_upgrades.h"
#include "csapi/rooms.h"
#include "csapi/tags.h"
+
#include "events/callanswerevent.h"
#include "events/callcandidatesevent.h"
#include "events/callhangupevent.h"
@@ -48,8 +52,6 @@
#include "jobs/downloadfilejob.h"
#include "jobs/mediathumbnailjob.h"
#include "jobs/postreadmarkersjob.h"
-#include "syncdata.h"
-#include "user.h"
#include <QtCore/QDir>
#include <QtCore/QHash>
@@ -70,19 +72,25 @@ using std::move;
using std::llround;
#endif
-enum EventsPlacement : int { Older = -1, Newer = 1 };
+enum EventsPlacement : int
+{
+ Older = -1,
+ Newer = 1
+};
class Room::Private
{
- public:
- /** Map of user names to users. User names potentially duplicate, hence a
- * multi-hashmap. */
+public:
+ /// Map of user names to users
+ /** User names potentially duplicate, hence QMultiHash. */
using members_map_t = QMultiHash<QString, User*>;
Private(Connection* c, QString id_, JoinState initialJoinState)
- : q(nullptr), connection(c), id(move(id_)), joinState(initialJoinState)
- {
- }
+ : q(nullptr)
+ , connection(c)
+ , id(move(id_))
+ , joinState(initialJoinState)
+ {}
Room* q;
@@ -106,6 +114,7 @@ class Room::Private
members_map_t membersMap;
QList<User*> usersTyping;
QMultiHash<QString, User*> eventIdReadUsers;
+ QList<User*> usersInvited;
QList<User*> membersLeft;
int unreadMessages = 0;
bool displayed = false;
@@ -119,16 +128,16 @@ class Room::Private
QPointer<GetRoomEventsJob> eventsHistoryJob;
QPointer<GetMembersByRoomJob> allMembersJob;
- struct FileTransferPrivateInfo {
+ struct FileTransferPrivateInfo
+ {
FileTransferPrivateInfo() = default;
FileTransferPrivateInfo(BaseJob* j, const QString& fileName,
bool isUploading = false)
- : status(FileTransferInfo::Started),
- job(j),
- localFileInfo(fileName),
- isUpload(isUploading)
- {
- }
+ : status(FileTransferInfo::Started)
+ , job(j)
+ , localFileInfo(fileName)
+ , isUpload(isUploading)
+ {}
FileTransferInfo::Status status = FileTransferInfo::None;
QPointer<BaseJob> job = nullptr;
@@ -170,7 +179,7 @@ class Room::Private
// void inviteUser(User* u); // We might get it at some point in time.
void insertMemberIntoMap(User* u);
- void renameMember(User* u, QString oldName);
+ void renameMember(User* u, const QString& oldName);
void removeMemberFromMap(const QString& username, User* u);
// This updates the room displayname field (which is the way a room
@@ -187,11 +196,11 @@ class Room::Private
void getPreviousContent(int limit = 10);
template <typename EventT>
- const EventT* getCurrentState(QString stateKey = {}) const
+ const EventT* getCurrentState(const QString& stateKey = {}) const
{
static const EventT empty;
- const auto* evt = currentState.value(
- { EventT::matrixTypeId(), stateKey }, &empty);
+ const auto* evt =
+ currentState.value({ EventT::matrixTypeId(), stateKey }, &empty);
Q_ASSERT(evt->type() == EventT::typeId()
&& evt->matrixType() == EventT::matrixTypeId());
return static_cast<const EventT*>(evt);
@@ -200,7 +209,7 @@ class Room::Private
bool isEventNotable(const TimelineItem& ti) const
{
return !ti->isRedacted() && ti->senderId() != connection->userId()
- && is<RoomMessageEvent>(*ti);
+ && is<RoomMessageEvent>(*ti);
}
template <typename EventArrayT>
@@ -219,8 +228,9 @@ class Room::Private
baseState[{ evt.matrixType(), evt.stateKey() }] = move(eptr);
}
if (events.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
- qCDebug(PROFILER) << "*** Room::Private::updateStateFrom():"
- << events.size() << "event(s)," << et;
+ qCDebug(PROFILER)
+ << "*** Room::Private::updateStateFrom():" << events.size()
+ << "event(s)," << et;
}
return changes;
}
@@ -236,8 +246,8 @@ class Room::Private
* @param placement - position and direction of insertion: Older for
* historical messages, Newer for new ones
*/
- Timeline::difference_type moveEventsToTimeline(RoomEventsRange events,
- EventsPlacement placement);
+ Timeline::size_type moveEventsToTimeline(RoomEventsRange events,
+ EventsPlacement placement);
/**
* Remove events from the passed container that are already in the timeline
@@ -246,8 +256,7 @@ class Room::Private
Changes setLastReadEvent(User* u, QString eventId);
void updateUnreadCount(rev_iter_t from, rev_iter_t to);
- Changes promoteReadMarker(User* u, rev_iter_t newMarker,
- bool force = false);
+ Changes promoteReadMarker(User* u, rev_iter_t newMarker, bool force = false);
Changes markMessagesAsRead(rev_iter_t upToMarker);
@@ -273,13 +282,14 @@ class Room::Private
if (q->successorId().isEmpty()) {
// TODO: Queue up state events sending (see #133).
return connection->callApi<SetRoomStateWithKeyJob>(
- id, EvT::matrixTypeId(), stateKey, event.contentJson());
+ id, EvT::matrixTypeId(), stateKey, event.contentJson());
}
qCWarning(MAIN) << q << "has been upgraded, state won't be set";
return nullptr;
}
- template <typename EvT> auto requestSetState(const EvT& event)
+ template <typename EvT>
+ auto requestSetState(const EvT& event)
{
return connection->callApi<SetRoomStateJob>(id, EvT::matrixTypeId(),
event.contentJson());
@@ -297,7 +307,7 @@ class Room::Private
QJsonObject toJson() const;
- private:
+private:
using users_shortlist_t = std::array<User*, 3>;
template <typename ContT>
users_shortlist_t buildShortlist(const ContT& users) const;
@@ -307,19 +317,19 @@ class Room::Private
};
Room::Room(Connection* connection, QString id, JoinState initialJoinState)
- : QObject(connection), d(new Private(connection, id, initialJoinState))
+ : QObject(connection)
+ , d(new Private(connection, id, initialJoinState))
{
setObjectName(id);
// See "Accessing the Public Class" section in
// https://marcmutz.wordpress.com/translated-articles/pimp-my-pimpl-%E2%80%94-reloaded/
d->q = this;
d->displayname = d->calculateDisplayname(); // Set initial "Empty room" name
- connectUntil(
- connection, &Connection::loadedRoomState, this, [this](Room* r) {
- if (this == r)
- emit baseStateLoaded();
- return this == r; // loadedRoomState fires only once per room
- });
+ connectUntil(connection, &Connection::loadedRoomState, this, [this](Room* r) {
+ if (this == r)
+ emit baseStateLoaded();
+ return this == r; // loadedRoomState fires only once per room
+ });
qCDebug(MAIN) << "New" << toCString(initialJoinState) << "Room:" << id;
}
@@ -330,13 +340,13 @@ const QString& Room::id() const { return d->id; }
QString Room::version() const
{
const auto v = d->getCurrentState<RoomCreateEvent>()->version();
- return v.isEmpty() ? "1" : v;
+ return v.isEmpty() ? QStringLiteral("1") : v;
}
bool Room::isUnstable() const
{
return !connection()->loadingCapabilities()
- && !connection()->stableRoomVersions().contains(version());
+ && !connection()->stableRoomVersions().contains(version());
}
QString Room::predecessorId() const
@@ -356,6 +366,11 @@ const Room::PendingEvents& Room::pendingEvents() const
return d->unsyncedEvents;
}
+bool Room::allHistoryLoaded() const
+{
+ return !d->timeline.empty() && is<RoomCreateEvent>(*d->timeline.front());
+}
+
QString Room::name() const
{
return d->getCurrentState<RoomNameEvent>()->name();
@@ -373,6 +388,8 @@ QString Room::canonicalAlias() const
QString Room::displayName() const { return d->displayname; }
+void Room::refreshDisplayName() { d->updateDisplayname(); }
+
QString Room::topic() const
{
return d->getCurrentState<RoomTopicEvent>()->topic();
@@ -396,8 +413,7 @@ QImage Room::avatar(int width, int height)
const auto dcUsers = directChatUsers();
for (auto* u : dcUsers)
if (u != localUser())
- return u->avatar(width, height, this,
- [=] { emit avatarChanged(); });
+ return u->avatar(width, height, this, [=] { emit avatarChanged(); });
return {};
}
@@ -465,14 +481,13 @@ void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to)
QElapsedTimer et;
et.start();
- const auto newUnreadMessages = count_if(
- from, to, std::bind(&Room::Private::isEventNotable, this, _1));
+ const auto newUnreadMessages =
+ count_if(from, to, std::bind(&Room::Private::isEventNotable, this, _1));
if (et.nsecsElapsed() > profilerMinNsecs() / 10)
qCDebug(PROFILER) << "Counting gained unread messages took" << et;
if (newUnreadMessages > 0) {
- // See
- // https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
+ // See https://github.com/quotient-im/libQuotient/wiki/unread_count
if (unreadMessages < 0)
unreadMessages = 0;
@@ -480,8 +495,8 @@ void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to)
qCDebug(MAIN) << "Room" << q->objectName() << "has gained"
<< newUnreadMessages << "unread message(s),"
<< (q->readMarker() == timeline.crend()
- ? "in total at least"
- : "in total")
+ ? "in total at least"
+ : "in total")
<< unreadMessages << "unread message(s)";
emit q->unreadMessagesChanged(q);
}
@@ -494,17 +509,18 @@ Room::Changes Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker,
Q_ASSERT(newMarker >= timeline.crbegin() && newMarker <= timeline.crend());
const auto prevMarker = q->readMarker(u);
- if (!force
- && prevMarker <= newMarker) // Remember, we deal with reverse iterators
+ if (!force && prevMarker <= newMarker) // Remember, we deal with reverse
+ // iterators
return Change::NoChange;
Q_ASSERT(newMarker < timeline.crend());
// Try to auto-promote the read marker over the user's own messages
// (switch to direct iterators for that).
- auto eagerMarker = find_if(
- newMarker.base(), timeline.cend(),
- [=](const TimelineItem& ti) { return ti->senderId() != u->id(); });
+ auto eagerMarker = find_if(newMarker.base(), timeline.cend(),
+ [=](const TimelineItem& ti) {
+ return ti->senderId() != u->id();
+ });
auto changes = setLastReadEvent(u, (*(eagerMarker - 1))->id());
if (isLocalUser(u)) {
@@ -512,20 +528,19 @@ Room::Changes Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker,
QElapsedTimer et;
et.start();
unreadMessages =
- count_if(eagerMarker, timeline.cend(),
- std::bind(&Room::Private::isEventNotable, this, _1));
+ int(count_if(eagerMarker, timeline.cend(),
+ std::bind(&Room::Private::isEventNotable, this, _1)));
if (et.nsecsElapsed() > profilerMinNsecs() / 10)
qCDebug(PROFILER) << "Recounting unread messages took" << et;
- // See
- // https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
+ // See https://github.com/quotient-im/libQuotient/wiki/unread_count
if (unreadMessages == 0)
unreadMessages = -1;
if (force || unreadMessages != oldUnreadCount) {
if (unreadMessages == -1) {
- qCDebug(MAIN) << "Room" << displayname
- << "has no more unread messages";
+ qCDebug(MAIN)
+ << "Room" << displayname << "has no more unread messages";
} else
qCDebug(MAIN) << "Room" << displayname << "still has"
<< unreadMessages << "unread message(s)";
@@ -548,8 +563,9 @@ Room::Changes Room::Private::markMessagesAsRead(rev_iter_t upToMarker)
// until the previous last-read message, whichever comes first.
for (; upToMarker < prevMarker; ++upToMarker) {
if ((*upToMarker)->senderId() != q->localUser()->id()) {
- connection->callApi<PostReceiptJob>(id, "m.read",
- (*upToMarker)->id());
+ connection->callApi<PostReceiptJob>(id, QStringLiteral("m.read"),
+ QUrl::toPercentEncoding(
+ (*upToMarker)->id()));
break;
}
}
@@ -569,22 +585,26 @@ void Room::markAllMessagesAsRead()
bool Room::canSwitchVersions() const
{
+ if (!successorId().isEmpty())
+ return false; // No one can upgrade a room that's already upgraded
+
// TODO, #276: m.room.power_levels
- const auto* plEvt = d->currentState.value({ "m.room.power_levels", "" });
+ const auto* plEvt =
+ d->currentState.value({ QStringLiteral("m.room.power_levels"), {} });
if (!plEvt)
return true;
const auto plJson = plEvt->contentJson();
const auto currentUserLevel =
- plJson.value("users"_ls)
- .toObject()
- .value(localUser()->id())
- .toInt(plJson.value("users_default"_ls).toInt());
+ plJson.value("users"_ls)
+ .toObject()
+ .value(localUser()->id())
+ .toInt(plJson.value("users_default"_ls).toInt());
const auto tombstonePowerLevel =
- plJson.value("events")
- .toObject()
- .value("m.room.tombstone"_ls)
- .toInt(plJson.value("state_default"_ls).toInt());
+ plJson.value("events"_ls)
+ .toObject()
+ .value("m.room.tombstone"_ls)
+ .toInt(plJson.value("state_default"_ls).toInt());
return currentUserLevel >= tombstonePowerLevel;
}
@@ -614,13 +634,13 @@ TimelineItem::index_t Room::maxTimelineIndex() const
bool Room::isValidIndex(TimelineItem::index_t timelineIndex) const
{
return !d->timeline.empty() && timelineIndex >= minTimelineIndex()
- && timelineIndex <= maxTimelineIndex();
+ && timelineIndex <= maxTimelineIndex();
}
Room::rev_iter_t Room::findInTimeline(TimelineItem::index_t index) const
{
return timelineEdge()
- - (isValidIndex(index) ? index - minTimelineIndex() + 1 : 0);
+ - (isValidIndex(index) ? index - minTimelineIndex() + 1 : 0);
}
Room::rev_iter_t Room::findInTimeline(const QString& evtId) const
@@ -657,7 +677,7 @@ void Room::Private::getAllMembers()
return;
allMembersJob = connection->callApi<GetMembersByRoomJob>(
- id, connection->nextBatchToken(), "join");
+ id, connection->nextBatchToken(), "join");
auto nextIndex = timeline.empty() ? 0 : timeline.back().index() + 1;
connect(allMembersJob, &BaseJob::success, q, [=] {
Q_ASSERT(timeline.empty() || nextIndex <= q->maxTimelineIndex() + 1);
@@ -760,7 +780,7 @@ void Room::resetNotificationCount()
if (d->notificationCount == 0)
return;
d->notificationCount = 0;
- emit notificationCountChanged(this);
+ emit notificationCountChanged();
}
int Room::highlightCount() const { return d->highlightCount; }
@@ -770,14 +790,20 @@ void Room::resetHighlightCount()
if (d->highlightCount == 0)
return;
d->highlightCount = 0;
- emit highlightCountChanged(this);
+ emit highlightCountChanged();
}
void Room::switchVersion(QString newVersion)
{
- auto* job = connection()->callApi<UpgradeRoomJob>(id(), newVersion);
- connect(job, &BaseJob::failure, this,
- [this, job] { emit upgradeFailed(job->errorString()); });
+ if (!successorId().isEmpty()) {
+ Q_ASSERT(!successorId().isEmpty());
+ emit upgradeFailed(tr("The room is already upgraded"));
+ }
+ if (auto* job = connection()->callApi<UpgradeRoomJob>(id(), newVersion))
+ connect(job, &BaseJob::failure, this,
+ [this, job] { emit upgradeFailed(job->errorString()); });
+ else
+ emit upgradeFailed(tr("Couldn't initiate upgrade"));
}
bool Room::hasAccountData(const QString& type) const
@@ -848,8 +874,8 @@ void Room::setTags(TagsMap newTags)
{
d->setTags(move(newTags));
connection()->callApi<SetAccountDataPerRoomJob>(
- localUser()->id(), id(), TagEvent::matrixTypeId(),
- TagEvent(d->tags).contentJson());
+ localUser()->id(), id(), TagEvent::matrixTypeId(),
+ TagEvent(d->tags).contentJson());
}
void Room::Private::setTags(TagsMap newTags)
@@ -867,7 +893,7 @@ void Room::Private::setTags(TagsMap newTags)
}
tags = move(newTags);
qCDebug(MAIN) << "Room" << q->objectName() << "is tagged with"
- << q->tagNames().join(", ");
+ << q->tagNames().join(QStringLiteral(", "));
emit q->tagsChanged();
}
@@ -980,8 +1006,7 @@ FileTransferInfo Room::fileTransferInfo(const QString& id) const
fti.progress = int(progress);
fti.total = int(total);
fti.localDir = QUrl::fromLocalFile(infoIt->localFileInfo.absolutePath());
- fti.localPath =
- QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath());
+ fti.localPath = QUrl::fromLocalFile(infoIt->localFileInfo.absoluteFilePath());
return fti;
#else
return { infoIt->status,
@@ -1040,8 +1065,8 @@ bool Room::usesEncryption() const
int Room::joinedCount() const
{
return d->summary.joinedMemberCount.omitted()
- ? d->membersMap.size()
- : d->summary.joinedMemberCount.value();
+ ? d->membersMap.size()
+ : d->summary.joinedMemberCount.value();
}
int Room::invitedCount() const
@@ -1059,8 +1084,8 @@ Room::Changes Room::Private::setSummary(RoomSummary&& newSummary)
{
if (!summary.merge(newSummary))
return Change::NoChange;
- qCDebug(MAIN).nospace().noquote() << "Updated room summary for "
- << q->objectName() << ": " << summary;
+ qCDebug(MAIN).nospace().noquote()
+ << "Updated room summary for " << q->objectName() << ": " << summary;
emit q->memberListChanged();
return Change::SummaryChange;
}
@@ -1070,7 +1095,11 @@ void Room::Private::insertMemberIntoMap(User* u)
const auto userName = u->name(q);
// If there is exactly one namesake of the added user, signal member
// renaming for that other one because the two should be disambiguated now.
- auto namesakes = membersMap.values(userName);
+ const auto namesakes = membersMap.values(userName);
+
+ // Callers should check they are not adding an existing user once more.
+ Q_ASSERT(!namesakes.contains(u));
+
if (namesakes.size() == 1)
emit q->memberAboutToRename(namesakes.front(),
namesakes.front()->fullName(q));
@@ -1079,7 +1108,7 @@ void Room::Private::insertMemberIntoMap(User* u)
emit q->memberRenamed(namesakes.front());
}
-void Room::Private::renameMember(User* u, QString oldName)
+void Room::Private::renameMember(User* u, const QString& oldName)
{
if (u->name(q) == oldName) {
qCWarning(MAIN) << "Room::Private::renameMember(): the user "
@@ -1089,7 +1118,6 @@ void Room::Private::renameMember(User* u, QString oldName)
removeMemberFromMap(oldName, u);
insertMemberIntoMap(u);
}
- emit q->memberRenamed(u);
}
void Room::Private::removeMemberFromMap(const QString& username, User* u)
@@ -1097,15 +1125,13 @@ void Room::Private::removeMemberFromMap(const QString& username, User* u)
User* namesake = nullptr;
auto namesakes = membersMap.values(username);
if (namesakes.size() == 2) {
- namesake =
- namesakes.front() == u ? namesakes.back() : namesakes.front();
+ namesake = namesakes.front() == u ? namesakes.back() : namesakes.front();
Q_ASSERT_X(namesake != u, __FUNCTION__, "Room members list is broken");
emit q->memberAboutToRename(namesake, username);
}
membersMap.remove(username, u);
// If there was one namesake besides the removed user, signal member
- // renaming for it because it doesn't need to be disambiguated anymore.
- // TODO: Think about left users.
+ // renaming for it because it doesn't need to be disambiguated any more.
if (namesake)
emit q->memberRenamed(namesake);
}
@@ -1115,7 +1141,7 @@ inline auto makeErrorStr(const Event& e, QByteArray msg)
return msg.append("; event dump follows:\n").append(e.originalJson());
}
-Room::Timeline::difference_type
+Room::Timeline::size_type
Room::Private::moveEventsToTimeline(RoomEventsRange events,
EventsPlacement placement)
{
@@ -1124,21 +1150,19 @@ Room::Private::moveEventsToTimeline(RoomEventsRange events,
// them is almost symmetric to the one for new messages. New messages get
// appended from index 0; old messages go backwards from index -1.
auto index = timeline.empty()
- ? -((placement + 1) / 2) /* 1 -> -1; -1 -> 0 */
- : placement == Older ? timeline.front().index()
- : timeline.back().index();
+ ? -((placement + 1) / 2) /* 1 -> -1; -1 -> 0 */
+ : placement == Older ? timeline.front().index()
+ : timeline.back().index();
auto baseIndex = index;
for (auto&& e : events) {
const auto eId = e->id();
Q_ASSERT_X(e, __FUNCTION__, "Attempt to add nullptr to timeline");
Q_ASSERT_X(
- !eId.isEmpty(), __FUNCTION__,
- makeErrorStr(*e,
- "Event with empty id cannot be in the timeline"));
+ !eId.isEmpty(), __FUNCTION__,
+ makeErrorStr(*e, "Event with empty id cannot be in the timeline"));
Q_ASSERT_X(
- !eventsIndex.contains(eId), __FUNCTION__,
- makeErrorStr(*e,
- "Event is already in the timeline; "
+ !eventsIndex.contains(eId), __FUNCTION__,
+ makeErrorStr(*e, "Event is already in the timeline; "
"incoming events were not properly deduplicated"));
if (placement == Older)
timeline.emplace_front(move(e), --index);
@@ -1210,8 +1234,9 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
et.restart();
roomChanges |= d->addNewMessageEvents(move(data.timeline));
if (data.timeline.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
- qCDebug(PROFILER) << "*** Room::addNewMessageEvents():"
- << data.timeline.size() << "event(s)," << et;
+ qCDebug(PROFILER)
+ << "*** Room::addNewMessageEvents():" << data.timeline.size()
+ << "event(s)," << et;
}
if (roomChanges & TopicChange)
emit topicChanged();
@@ -1223,12 +1248,11 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
emit memberListChanged();
roomChanges |= d->setSummary(move(data.summary));
- d->updateDisplayname();
for (auto&& ephemeralEvent : data.ephemeral)
roomChanges |= processEphemeralEvent(move(ephemeralEvent));
- // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count
+ // See https://github.com/quotient-im/libQuotient/wiki/unread_count
if (data.unreadCount != -2 && data.unreadCount != d->unreadMessages) {
qCDebug(MAIN) << "Setting unread_count to" << data.unreadCount;
d->unreadMessages = data.unreadCount;
@@ -1237,13 +1261,14 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
if (data.highlightCount != d->highlightCount) {
d->highlightCount = data.highlightCount;
- emit highlightCountChanged(this);
+ emit highlightCountChanged();
}
if (data.notificationCount != d->notificationCount) {
d->notificationCount = data.notificationCount;
- emit notificationCountChanged(this);
+ emit notificationCountChanged();
}
if (roomChanges != Change::NoChange) {
+ d->updateDisplayname();
emit changed(roomChanges);
if (!fromCache)
connection()->saveRoomState(this);
@@ -1275,8 +1300,8 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent)
const auto txnId = pEvent->transactionId();
// TODO, #133: Enqueue the job rather than immediately trigger it.
if (auto call = connection->callApi<SendMessageJob>(
- BackgroundRequest, id, pEvent->matrixType(), txnId,
- pEvent->contentJson())) {
+ BackgroundRequest, id, pEvent->matrixType(), txnId,
+ pEvent->contentJson())) {
Room::connect(call, &BaseJob::started, q, [this, txnId] {
auto it = q->findPendingEvent(txnId);
if (it == unsyncedEvents.end()) {
@@ -1285,7 +1310,7 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent)
return;
}
it->setDeparted();
- emit q->pendingEventChanged(it - unsyncedEvents.begin());
+ emit q->pendingEventChanged(int(it - unsyncedEvents.begin()));
});
Room::connect(call, &BaseJob::failure, q,
std::bind(&Room::Private::onEventSendingFailure, this,
@@ -1300,7 +1325,7 @@ QString Room::Private::doSendEvent(const RoomEvent* pEvent)
}
it->setReachedServer(call->eventId());
- emit q->pendingEventChanged(it - unsyncedEvents.begin());
+ emit q->pendingEventChanged(int(it - unsyncedEvents.begin()));
});
} else
onEventSendingFailure(txnId);
@@ -1315,10 +1340,9 @@ void Room::Private::onEventSendingFailure(const QString& txnId, BaseJob* call)
<< "could not be sent";
return;
}
- it->setSendingFailed(call ? call->statusCaption() % ": "
- % call->errorString()
+ it->setSendingFailed(call ? call->statusCaption() % ": " % call->errorString()
: tr("The call could not be started"));
- emit q->pendingEventChanged(it - unsyncedEvents.begin());
+ emit q->pendingEventChanged(int(it - unsyncedEvents.begin()));
}
QString Room::retryMessage(const QString& txnId)
@@ -1340,16 +1364,15 @@ QString Room::retryMessage(const QString& txnId)
emit fileTransferFailed(txnId,
tr("File upload will be retried"));
}
- uploadFile(txnId,
- QUrl::fromLocalFile(
- transferIt->localFileInfo.absoluteFilePath()));
+ uploadFile(txnId, QUrl::fromLocalFile(
+ transferIt->localFileInfo.absoluteFilePath()));
// FIXME: Content type is no more passed here but it should
}
}
if (it->deliveryStatus() == EventStatus::ReachedServer) {
qCWarning(MAIN)
- << "The previous attempt has reached the server; two"
- " events are likely to be in the timeline after retry";
+ << "The previous attempt has reached the server; two"
+ " events are likely to be in the timeline after retry";
}
it->resetStatus();
return d->doSendEvent(it->event());
@@ -1357,9 +1380,10 @@ QString Room::retryMessage(const QString& txnId)
void Room::discardMessage(const QString& txnId)
{
- auto it = std::find_if(
- d->unsyncedEvents.begin(), d->unsyncedEvents.end(),
- [txnId](const auto& evt) { return evt->transactionId() == txnId; });
+ auto it = std::find_if(d->unsyncedEvents.begin(), d->unsyncedEvents.end(),
+ [txnId](const auto& evt) {
+ return evt->transactionId() == txnId;
+ });
Q_ASSERT(it != d->unsyncedEvents.end());
qDebug(EVENTS) << "Discarding transaction" << txnId;
const auto& transferIt = d->fileTransfers.find(txnId);
@@ -1371,8 +1395,8 @@ void Room::discardMessage(const QString& txnId)
emit fileTransferFailed(txnId, tr("File upload cancelled"));
} else if (transferIt->status == FileTransferInfo::Completed) {
qCWarning(MAIN)
- << "File for transaction" << txnId
- << "has been uploaded but the message was discarded";
+ << "File for transaction" << txnId
+ << "has been uploaded but the message was discarded";
}
}
emit pendingEventAboutToDiscard(int(it - d->unsyncedEvents.begin()));
@@ -1394,8 +1418,8 @@ QString Room::postHtmlMessage(const QString& plainText, const QString& html,
MessageEventType type)
{
return d->sendEvent<RoomMessageEvent>(
- plainText, type,
- new EventContent::TextContent(html, QStringLiteral("text/html")));
+ plainText, type,
+ new EventContent::TextContent(html, QStringLiteral("text/html")));
}
QString Room::postHtmlText(const QString& plainText, const QString& html)
@@ -1408,31 +1432,34 @@ QString Room::postFile(const QString& plainText, const QUrl& localPath,
{
QFileInfo localFile { localPath.toLocalFile() };
Q_ASSERT(localFile.isFile());
+
+ const auto txnId = connection()->generateTxnId();
// Remote URL will only be known after upload; fill in the local path
// to enable the preview while the event is pending.
- const auto txnId =
- d->addAsPending(makeEvent<RoomMessageEvent>(plainText, localFile,
- asGenericFile))
- ->transactionId();
uploadFile(txnId, localPath);
+ {
+ auto&& event = makeEvent<RoomMessageEvent>(plainText, localFile,
+ asGenericFile);
+ event->setTransactionId(txnId);
+ d->addAsPending(std::move(event));
+ }
auto* context = new QObject(this);
connect(this, &Room::fileTransferCompleted, context,
- [context, this, txnId](const QString& id, QUrl,
- const QUrl& mxcUri) {
+ [context, this, txnId](const QString& id, QUrl, const QUrl& mxcUri) {
if (id == txnId) {
auto it = findPendingEvent(txnId);
if (it != d->unsyncedEvents.end()) {
it->setFileUploaded(mxcUri);
emit pendingEventChanged(
- int(it - d->unsyncedEvents.begin()));
+ int(it - d->unsyncedEvents.begin()));
d->doSendEvent(it->get());
} else {
// Normally in this situation we should instruct
// the media server to delete the file; alas, there's no
// API specced for that.
- qCWarning(MAIN) << "File uploaded to" << mxcUri
- << "but the event referring to it was "
- "cancelled";
+ qCWarning(MAIN)
+ << "File uploaded to" << mxcUri
+ << "but the event referring to it was cancelled";
}
context->deleteLater();
}
@@ -1445,8 +1472,7 @@ QString Room::postFile(const QString& plainText, const QUrl& localPath,
const auto idx = int(it - d->unsyncedEvents.begin());
emit pendingEventAboutToDiscard(idx);
// See #286 on why iterator may not be valid here.
- d->unsyncedEvents.erase(d->unsyncedEvents.begin()
- + idx);
+ d->unsyncedEvents.erase(d->unsyncedEvents.begin() + idx);
emit pendingEventDiscarded();
}
context->deleteLater();
@@ -1470,7 +1496,7 @@ QString Room::postJson(const QString& matrixType,
const QJsonObject& eventContent)
{
return d->sendEvent(
- loadEvent<RoomEvent>(basicEventJson(matrixType, eventContent)));
+ loadEvent<RoomEvent>(basicEventJson(matrixType, eventContent)));
}
void Room::setName(const QString& newName)
@@ -1519,7 +1545,7 @@ void Room::checkVersion()
{
const auto defaultVersion = connection()->defaultRoomVersion();
const auto stableVersions = connection()->stableRoomVersions();
- Q_ASSERT(!defaultVersion.isEmpty() && successorId().isEmpty());
+ Q_ASSERT(!defaultVersion.isEmpty());
// This method is only called after the base state has been loaded
// or the server capabilities have been loaded.
emit stabilityUpdated(defaultVersion, stableVersions);
@@ -1616,8 +1642,8 @@ void Room::unban(const QString& userId)
void Room::redactEvent(const QString& eventId, const QString& reason)
{
- connection()->callApi<RedactEventJob>(
- id(), eventId, connection()->generateTxnId(), reason);
+ connection()->callApi<RedactEventJob>(id(), QUrl::toPercentEncoding(eventId),
+ connection()->generateTxnId(), reason);
}
void Room::uploadFile(const QString& id, const QUrl& localFilename,
@@ -1660,19 +1686,24 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
const auto* event = d->getEventWithFile(eventId);
if (!event) {
qCCritical(MAIN)
- << eventId
- << "is not in the local timeline or has no file content";
+ << eventId << "is not in the local timeline or has no file content";
Q_ASSERT(false);
return;
}
- const auto fileUrl = event->content()->fileInfo()->url;
+ const auto* const fileInfo = event->content()->fileInfo();
+ if (!fileInfo->isValid()) {
+ qCWarning(MAIN) << "Event" << eventId
+ << "has an empty or malformed mxc URL; won't download";
+ return;
+ }
+ const auto fileUrl = fileInfo->url;
auto filePath = localFilename.toLocalFile();
if (filePath.isEmpty()) {
// Build our own file path, starting with temp directory and eventId.
filePath = eventId;
filePath = QDir::tempPath() % '/'
- % filePath.replace(QRegularExpression("[/\\<>|\"*?:]"), "_")
- % '#' % d->fileNameToDownload(event);
+ % filePath.replace(QRegularExpression("[/\\<>|\"*?:]"), "_")
+ % '#' % d->fileNameToDownload(event);
}
auto job = connection()->downloadFile(fileUrl, filePath);
if (isJobRunning(job)) {
@@ -1687,8 +1718,7 @@ void Room::downloadFile(const QString& eventId, const QUrl& localFilename)
connect(job, &BaseJob::success, this, [this, eventId, fileUrl, job] {
d->fileTransfers[eventId].status = FileTransferInfo::Completed;
emit fileTransferCompleted(
- eventId, fileUrl,
- QUrl::fromLocalFile(job->targetFileName()));
+ eventId, fileUrl, QUrl::fromLocalFile(job->targetFileName()));
});
connect(job, &BaseJob::failure, this,
std::bind(&Private::failedTransfer, d, eventId,
@@ -1718,10 +1748,10 @@ void Room::Private::dropDuplicateEvents(RoomEvents& events) const
// Multiple-remove (by different criteria), single-erase
// 1. Check for duplicates against the timeline.
- auto dupsBegin =
- remove_if(events.begin(), events.end(), [&](const RoomEventPtr& e) {
- return eventsIndex.contains(e->id());
- });
+ auto dupsBegin = remove_if(events.begin(), events.end(),
+ [&](const RoomEventPtr& e) {
+ return eventsIndex.contains(e->id());
+ });
// 2. Check for duplicates within the batch if there are still events.
for (auto eIt = events.begin(); distance(eIt, dupsBegin) > 1; ++eIt)
@@ -1771,9 +1801,8 @@ RoomEventPtr makeRedacted(const RoomEvent& target,
// { QStringLiteral("ban"), QStringLiteral("events"),
// QStringLiteral("events_default"),
// QStringLiteral("kick"), QStringLiteral("redact"),
- // QStringLiteral("state_default"),
- // QStringLiteral("users"), QStringLiteral("users_default")
- // } }
+ // QStringLiteral("state_default"), QStringLiteral("users"),
+ // QStringLiteral("users_default") } }
,
{ RoomAliasesEvent::typeId(), { QStringLiteral("aliases") } }
// , { RoomHistoryVisibility::typeId(),
@@ -1785,9 +1814,9 @@ RoomEventPtr makeRedacted(const RoomEvent& target,
else
++it;
}
- auto keepContentKeys = find_if(
- keepContentKeysMap.begin(), keepContentKeysMap.end(),
- [&target](const auto& t) { return target.type() == t.first; });
+ auto keepContentKeys =
+ find_if(keepContentKeysMap.begin(), keepContentKeysMap.end(),
+ [&target](const auto& t) { return target.type() == t.first; });
if (keepContentKeys == keepContentKeysMap.end()) {
originalJson.remove(ContentKeyL);
originalJson.remove(PrevContentKeyL);
@@ -1833,12 +1862,12 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction)
const StateEventKey evtKey { oldEvent->matrixType(),
oldEvent->stateKey() };
Q_ASSERT(currentState.contains(evtKey));
- if (currentState[evtKey] == oldEvent.get()) {
- Q_ASSERT(ti.index()
- >= 0); // Historical states can't be in currentState
+ if (currentState.value(evtKey) == oldEvent.get()) {
+ Q_ASSERT(ti.index() >= 0); // Historical states can't be in
+ // currentState
qCDebug(MAIN).nospace()
- << "Reverting state " << oldEvent->matrixType() << "/"
- << oldEvent->stateKey();
+ << "Redacting state " << oldEvent->matrixType() << "/"
+ << oldEvent->stateKey();
// Retarget the current state to the newly made event.
if (q->processStateEvent(*ti))
emit q->namesChanged(q);
@@ -1879,17 +1908,17 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
// Try to find the target in the timeline, then in the batch.
if (processRedaction(*r))
continue;
- auto targetIt = std::find_if(
- events.begin(), redactionIt,
- [id = r->redactedEvent()](const RoomEventPtr& ep) {
- return ep->id() == id;
- });
+ auto targetIt =
+ std::find_if(events.begin(), redactionIt,
+ [id = r->redactedEvent()](const RoomEventPtr& ep) {
+ return ep->id() == id;
+ });
if (targetIt != redactionIt)
*targetIt = makeRedacted(**targetIt, *r);
else
qCDebug(MAIN)
- << "Redaction" << r->id() << "ignored: target event"
- << r->redactedEvent() << "is not found";
+ << "Redaction" << r->id() << "ignored: target event"
+ << r->redactedEvent() << "is not found";
// If the target event comes later, it comes already redacted.
}
@@ -1903,11 +1932,11 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
roomChanges |= q->processStateEvent(*eptr);
auto timelineSize = timeline.size();
- auto totalInserted = 0;
+ size_t totalInserted = 0;
for (auto it = events.begin(); it != events.end();) {
- auto nextPendingPair =
- findFirstOf(it, events.end(), unsyncedEvents.begin(),
- unsyncedEvents.end(), isEchoEvent);
+ auto nextPendingPair = findFirstOf(it, events.end(),
+ unsyncedEvents.begin(),
+ unsyncedEvents.end(), isEchoEvent);
auto nextPending = nextPendingPair.first;
if (it != nextPending) {
@@ -1926,7 +1955,7 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
it = nextPending + 1;
auto* nextPendingEvt = nextPending->get();
const auto pendingEvtIdx =
- int(nextPendingPair.second - unsyncedEvents.begin());
+ int(nextPendingPair.second - unsyncedEvents.begin());
emit q->pendingEventAboutToMerge(nextPendingEvt, pendingEvtIdx);
qDebug(EVENTS) << "Merging pending event from transaction"
<< nextPendingEvt->transactionId() << "into"
@@ -1940,8 +1969,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
// unsyncedEvents (see #286). Fortunately, unsyncedEvents only grows at
// its back so we can rely on the index staying valid at least.
unsyncedEvents.erase(unsyncedEvents.begin() + pendingEvtIdx);
- if (auto insertedSize =
- moveEventsToTimeline({ nextPending, it }, Newer)) {
+ if (auto insertedSize = moveEventsToTimeline({ nextPending, it },
+ Newer)) {
totalInserted += insertedSize;
q->onAddNewTimelineEvents(timeline.cend() - insertedSize);
}
@@ -1956,9 +1985,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
emit q->callEvent(q, evt);
if (totalInserted > 0) {
- qCDebug(MAIN) << "Room" << q->objectName() << "received"
- << totalInserted << "new events; the last event is now"
- << timeline.back();
+ qCDebug(MAIN) << "Room" << q->objectName() << "received" << totalInserted
+ << "new events; the last event is now" << timeline.back();
// The first event in the just-added batch (referred to by `from`)
// defines whose read marker can possibly be promoted any further over
@@ -1969,9 +1997,8 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
auto firstWriter = q->user((*from)->senderId());
if (q->readMarker(firstWriter) != timeline.crend()) {
roomChanges |= promoteReadMarker(firstWriter, rev_iter_t(from) - 1);
- qCDebug(MAIN) << "Auto-promoted read marker for"
- << firstWriter->id() << "to"
- << *q->readMarker(firstWriter);
+ qCDebug(MAIN) << "Auto-promoted read marker for" << firstWriter->id()
+ << "to" << *q->readMarker(firstWriter);
}
updateUnreadCount(timeline.crbegin(), rev_iter_t(from));
@@ -2028,93 +2055,122 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
return Change::NoChange;
const auto* oldStateEvent =
- std::exchange(d->currentState[{ e.matrixType(), e.stateKey() }],
- static_cast<const StateEventBase*>(&e));
+ std::exchange(d->currentState[{ e.matrixType(), e.stateKey() }],
+ static_cast<const StateEventBase*>(&e));
Q_ASSERT(!oldStateEvent
|| (oldStateEvent->matrixType() == e.matrixType()
&& oldStateEvent->stateKey() == e.stateKey()));
- if (!is<RoomMemberEvent>(e))
+ if (!is<RoomMemberEvent>(e)) // Room member events are too numerous
qCDebug(EVENTS) << "Room state event:" << e;
return visit(
- e, [](const RoomNameEvent&) { return NameChange; },
- [this, oldStateEvent](const RoomAliasesEvent& ae) {
- const auto previousAliases = oldStateEvent
- ? static_cast<const RoomAliasesEvent*>(oldStateEvent)
- ->aliases()
- : QStringList();
- connection()->updateRoomAliases(id(), previousAliases,
- ae.aliases());
- return OtherChange;
- },
- [this](const RoomCanonicalAliasEvent& evt) {
- setObjectName(evt.alias().isEmpty() ? d->id : evt.alias());
- return CanonicalAliasChange;
- },
- [](const RoomTopicEvent&) { return TopicChange; },
- [this](const RoomAvatarEvent& evt) {
- if (d->avatar.updateUrl(evt.url()))
- emit avatarChanged();
- return AvatarChange;
- },
- [this](const RoomMemberEvent& evt) {
- auto* u = user(evt.userId());
- u->processEvent(evt, this);
- if (u == localUser() && memberJoinState(u) == JoinState::Invite
- && evt.isDirect())
- connection()->addToDirectChats(this, user(evt.senderId()));
-
- if (evt.membership() == MembershipType::Join) {
- if (memberJoinState(u) != JoinState::Join) {
- d->insertMemberIntoMap(u);
- connect(u, &User::nameAboutToChange, this,
- [=](QString newName, QString,
- const Room* context) {
- if (context == this)
- emit memberAboutToRename(u, newName);
- });
- connect(u, &User::nameChanged, this,
- [=](QString, QString oldName,
- const Room* context) {
- if (context == this)
- d->renameMember(u, oldName);
- });
- emit userAdded(u);
- }
- } else if (evt.membership() != MembershipType::Join) {
- if (memberJoinState(u) == JoinState::Join) {
- if (evt.membership() == MembershipType::Invite)
- qCWarning(MAIN)
- << "Invalid membership change:" << evt;
- if (!d->membersLeft.contains(u))
- d->membersLeft.append(u);
- d->removeMemberFromMap(u->name(this), u);
- emit userRemoved(u);
- }
+ e, [](const RoomNameEvent&) { return NameChange; },
+ [this, oldStateEvent](const RoomAliasesEvent& ae) {
+ const auto previousAliases =
+ oldStateEvent
+ ? static_cast<const RoomAliasesEvent*>(oldStateEvent)->aliases()
+ : QStringList();
+ connection()->updateRoomAliases(id(), previousAliases, ae.aliases());
+ return OtherChange;
+ },
+ [this](const RoomCanonicalAliasEvent& evt) {
+ setObjectName(evt.alias().isEmpty() ? d->id : evt.alias());
+ return CanonicalAliasChange;
+ },
+ [](const RoomTopicEvent&) { return TopicChange; },
+ [this](const RoomAvatarEvent& evt) {
+ if (d->avatar.updateUrl(evt.url()))
+ emit avatarChanged();
+ return AvatarChange;
+ },
+ [this, oldStateEvent](const RoomMemberEvent& evt) {
+ auto* u = user(evt.userId());
+ const auto* oldMemberEvent =
+ static_cast<const RoomMemberEvent*>(oldStateEvent);
+ u->processEvent(evt, this, oldMemberEvent == nullptr);
+ const auto prevMembership = oldMemberEvent
+ ? oldMemberEvent->membership()
+ : MembershipType::Leave;
+ if (u == localUser() && evt.membership() == MembershipType::Invite
+ && evt.isDirect())
+ connection()->addToDirectChats(this, user(evt.senderId()));
+
+ switch (prevMembership) {
+ case MembershipType::Invite:
+ if (evt.membership() != prevMembership) {
+ d->usersInvited.removeOne(u);
+ Q_ASSERT(!d->usersInvited.contains(u));
}
- return MembersChange;
- },
- [this](const EncryptionEvent&) {
- emit encryption(); // It can only be done once, so emit it here.
- return OtherChange;
- },
- [this](const RoomTombstoneEvent& evt) {
- const auto successorId = evt.successorRoomId();
- if (auto* successor = connection()->room(successorId))
- emit upgraded(evt.serverMessage(), successor);
- else
- connectUntil(
- connection(), &Connection::loadedRoomState, this,
- [this, successorId,
- serverMsg = evt.serverMessage()](Room* newRoom) {
- if (newRoom->id() != successorId)
- return false;
- emit upgraded(serverMsg, newRoom);
- return true;
- });
+ break;
+ case MembershipType::Join:
+ if (evt.membership() == MembershipType::Invite)
+ qCWarning(MAIN)
+ << "Invalid membership change from Join to Invite:"
+ << evt;
+ if (evt.membership() != prevMembership) {
+ disconnect(u, &User::nameAboutToChange, this, nullptr);
+ disconnect(u, &User::nameChanged, this, nullptr);
+ d->removeMemberFromMap(u->name(this), u);
+ emit userRemoved(u);
+ }
+ break;
+ default:
+ if (evt.membership() == MembershipType::Invite
+ || evt.membership() == MembershipType::Join) {
+ d->membersLeft.removeOne(u);
+ Q_ASSERT(!d->membersLeft.contains(u));
+ }
+ }
- return OtherChange;
- });
+ switch (evt.membership()) {
+ case MembershipType::Join:
+ if (prevMembership != MembershipType::Join) {
+ d->insertMemberIntoMap(u);
+ connect(u, &User::nameAboutToChange, this,
+ [=](QString newName, QString, const Room* context) {
+ if (context == this)
+ emit memberAboutToRename(u, newName);
+ });
+ connect(u, &User::nameChanged, this,
+ [=](QString, QString oldName, const Room* context) {
+ if (context == this) {
+ d->renameMember(u, oldName);
+ emit memberRenamed(u);
+ }
+ });
+ emit userAdded(u);
+ }
+ break;
+ case MembershipType::Invite:
+ if (!d->usersInvited.contains(u))
+ d->usersInvited.push_back(u);
+ break;
+ default:
+ if (!d->membersLeft.contains(u))
+ d->membersLeft.append(u);
+ }
+ return MembersChange;
+ },
+ [this](const EncryptionEvent&) {
+ emit encryption(); // It can only be done once, so emit it here.
+ return OtherChange;
+ },
+ [this](const RoomTombstoneEvent& evt) {
+ const auto successorId = evt.successorRoomId();
+ if (auto* successor = connection()->room(successorId))
+ emit upgraded(evt.serverMessage(), successor);
+ else
+ connectUntil(connection(), &Connection::loadedRoomState, this,
+ [this, successorId,
+ serverMsg = evt.serverMessage()](Room* newRoom) {
+ if (newRoom->id() != successorId)
+ return false;
+ emit upgraded(serverMsg, newRoom);
+ return true;
+ });
+
+ return OtherChange;
+ });
}
Room::Changes Room::processEphemeralEvent(EventPtr&& event)
@@ -2175,9 +2231,9 @@ Room::Changes Room::processEphemeralEvent(EventPtr&& event)
if (evt->eventsWithReceipts().size() > 3 || totalReceipts > 10
|| et.nsecsElapsed() >= profilerMinNsecs())
qCDebug(PROFILER)
- << "*** Room::processEphemeralEvent(receipts):"
- << evt->eventsWithReceipts().size() << "event(s) with"
- << totalReceipts << "receipt(s)," << et;
+ << "*** Room::processEphemeralEvent(receipts):"
+ << evt->eventsWithReceipts().size() << "event(s) with"
+ << totalReceipts << "receipt(s)," << et;
}
return changes;
}
@@ -2196,8 +2252,8 @@ Room::Changes Room::processAccountDataEvent(EventPtr&& event)
d->serverReadMarker = readEventId;
const auto newMarker = findInTimeline(readEventId);
changes |= newMarker != timelineEdge()
- ? d->markMessagesAsRead(newMarker)
- : d->setLastReadEvent(localUser(), readEventId);
+ ? d->markMessagesAsRead(newMarker)
+ : d->setLastReadEvent(localUser(), readEventId);
}
// For all account data events
auto& currentData = d->accountData[event->matrixType()];
@@ -2225,12 +2281,11 @@ Room::Private::buildShortlist(const ContT& users) const
// slightly extending the spec.
users_shortlist_t shortlist {}; // Prefill with nullptrs
std::partial_sort_copy(
- users.begin(), users.end(), shortlist.begin(), shortlist.end(),
- [this](const User* u1, const User* u2) {
- // localUser(), if it's in the list, is sorted below all others
- return isLocalUser(u2)
- || (!isLocalUser(u1) && u1->id() < u2->id());
- });
+ users.begin(), users.end(), shortlist.begin(), shortlist.end(),
+ [this](const User* u1, const User* u2) {
+ // localUser(), if it's in the list, is sorted below all others
+ return isLocalUser(u2) || (!isLocalUser(u1) && u1->id() < u2->id());
+ });
return shortlist;
}
@@ -2261,41 +2316,61 @@ QString Room::Private::calculateDisplayname() const
return dispName;
// Using m.room.aliases in naming is explicitly discouraged by the spec
- // if (!q->aliases().empty() && !q->aliases().at(0).isEmpty())
- // return q->aliases().at(0);
// Supplementary code for 3 and 4: build the shortlist of users whose names
// will be used to construct the room name. Takes into account MSC688's
// "heroes" if available.
+ const bool localUserIsIn = joinState == JoinState::Join;
const bool emptyRoom = membersMap.isEmpty()
- || (membersMap.size() == 1 && isLocalUser(*membersMap.begin()));
- const auto shortlist = !summary.heroes.omitted()
- ? buildShortlist(summary.heroes.value())
- : !emptyRoom ? buildShortlist(membersMap)
- : buildShortlist(membersLeft);
+ || (membersMap.size() == 1
+ && isLocalUser(*membersMap.begin()));
+ const bool nonEmptySummary = !summary.heroes.omitted()
+ && !summary.heroes->empty();
+ auto shortlist = nonEmptySummary ? buildShortlist(summary.heroes.value())
+ : !emptyRoom ? buildShortlist(membersMap)
+ : users_shortlist_t {};
+
+ // When lazy-loading is on, we can rely on the heroes list.
+ // If it's off, the below code gathers invited and left members.
+ // NB: including invitations, if any, into naming is a spec extension.
+ // This kicks in when there's no lazy loading and it's a room with
+ // the local user as the only member, with more users invited.
+ if (!shortlist.front() && localUserIsIn)
+ shortlist = buildShortlist(usersInvited);
+
+ if (!shortlist.front()) // Still empty shortlist; use left members
+ shortlist = buildShortlist(membersLeft);
QStringList names;
for (auto u : shortlist) {
if (u == nullptr || isLocalUser(u))
break;
- names.push_back(q->roomMembername(u));
+ // Only disambiguate if the room is not empty
+ names.push_back(u->displayname(emptyRoom ? nullptr : q));
}
- auto usersCountExceptLocal = emptyRoom
- ? membersLeft.size() - int(joinState == JoinState::Leave)
- : q->joinedCount() - int(joinState == JoinState::Join);
+ const auto usersCountExceptLocal =
+ !emptyRoom
+ ? q->joinedCount() - int(joinState == JoinState::Join)
+ : !usersInvited.empty()
+ ? usersInvited.count()
+ : membersLeft.size() - int(joinState == JoinState::Leave);
if (usersCountExceptLocal > int(shortlist.size()))
names << tr(
- "%Ln other(s)",
- "Used to make a room name from user names: A, B and _N others_",
- usersCountExceptLocal);
- auto namesList = QLocale().createSeparatedList(names);
+ "%Ln other(s)",
+ "Used to make a room name from user names: A, B and _N others_",
+ usersCountExceptLocal - int(shortlist.size()));
+ const auto namesList = QLocale().createSeparatedList(names);
// 3. Room members
if (!emptyRoom)
return namesList;
+ // (Spec extension) Invited users
+ if (!usersInvited.empty())
+ return tr("Empty room (invited: %1)").arg(namesList);
+
// 4. Users that previously left the room
if (membersLeft.size() > 0)
return tr("Empty room (was: %1)").arg(namesList);
@@ -2339,11 +2414,10 @@ QJsonObject Room::Private::toJson() const
}
const auto stateObjName = joinState == JoinState::Invite
- ? QStringLiteral("invite_state")
- : QStringLiteral("state");
- result.insert(
- stateObjName,
- QJsonObject { { QStringLiteral("events"), stateEvents } });
+ ? QStringLiteral("invite_state")
+ : QStringLiteral("state");
+ result.insert(stateObjName,
+ QJsonObject { { QStringLiteral("events"), stateEvents } });
}
if (!accountData.empty()) {
@@ -2353,16 +2427,15 @@ QJsonObject Room::Private::toJson() const
accountDataEvents.append(e.second->fullJson());
}
result.insert(QStringLiteral("account_data"),
- QJsonObject { { QStringLiteral("events"),
- accountDataEvents } });
+ QJsonObject {
+ { QStringLiteral("events"), accountDataEvents } });
}
QJsonObject unreadNotifObj { { SyncRoomData::UnreadCountKey,
unreadMessages } };
if (highlightCount > 0)
- unreadNotifObj.insert(QStringLiteral("highlight_count"),
- highlightCount);
+ unreadNotifObj.insert(QStringLiteral("highlight_count"), highlightCount);
if (notificationCount > 0)
unreadNotifObj.insert(QStringLiteral("notification_count"),
notificationCount);
@@ -2370,8 +2443,7 @@ QJsonObject Room::Private::toJson() const
result.insert(QStringLiteral("unread_notifications"), unreadNotifObj);
if (et.elapsed() > 30)
- qCDebug(PROFILER) << "Room::toJson() for" << displayname << "took"
- << et;
+ qCDebug(PROFILER) << "Room::toJson() for" << displayname << "took" << et;
return result;
}
diff --git a/lib/room.h b/lib/room.h
index 4645d02a..fb5f5738 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -18,11 +18,13 @@
#pragma once
-#include "csapi/message_pagination.h"
#include "eventitem.h"
+#include "joinstate.h"
+
+#include "csapi/message_pagination.h"
+
#include "events/accountdataevents.h"
#include "events/roommessageevent.h"
-#include "joinstate.h"
#include <QtGui/QImage>
@@ -30,590 +32,621 @@
#include <memory>
#include <utility>
-namespace QMatrixClient {
- class Event;
- class Avatar;
- class SyncRoomData;
- class RoomMemberEvent;
- class Connection;
- class User;
- class MemberSorter;
- class LeaveRoomJob;
- class SetRoomStateWithKeyJob;
- class RedactEventJob;
-
- /** The data structure used to expose file transfer information to views
- *
- * This is specifically tuned to work with QML exposing all traits as
- * Q_PROPERTY values.
- */
- class FileTransferInfo
+namespace QMatrixClient
+{
+class Event;
+class Avatar;
+class SyncRoomData;
+class RoomMemberEvent;
+class Connection;
+class User;
+class MemberSorter;
+class LeaveRoomJob;
+class SetRoomStateWithKeyJob;
+class RedactEventJob;
+
+/** The data structure used to expose file transfer information to views
+ *
+ * This is specifically tuned to work with QML exposing all traits as
+ * Q_PROPERTY values.
+ */
+class FileTransferInfo
+{
+ Q_GADGET
+ Q_PROPERTY(bool isUpload MEMBER isUpload CONSTANT)
+ Q_PROPERTY(bool active READ active CONSTANT)
+ Q_PROPERTY(bool started READ started CONSTANT)
+ Q_PROPERTY(bool completed READ completed CONSTANT)
+ Q_PROPERTY(bool failed READ failed CONSTANT)
+ Q_PROPERTY(int progress MEMBER progress CONSTANT)
+ Q_PROPERTY(int total MEMBER total CONSTANT)
+ Q_PROPERTY(QUrl localDir MEMBER localDir CONSTANT)
+ Q_PROPERTY(QUrl localPath MEMBER localPath CONSTANT)
+public:
+ enum Status
{
- Q_GADGET
- Q_PROPERTY(bool isUpload MEMBER isUpload CONSTANT)
- Q_PROPERTY(bool active READ active CONSTANT)
- Q_PROPERTY(bool started READ started CONSTANT)
- Q_PROPERTY(bool completed READ completed CONSTANT)
- Q_PROPERTY(bool failed READ failed CONSTANT)
- Q_PROPERTY(int progress MEMBER progress CONSTANT)
- Q_PROPERTY(int total MEMBER total CONSTANT)
- Q_PROPERTY(QUrl localDir MEMBER localDir CONSTANT)
- Q_PROPERTY(QUrl localPath MEMBER localPath CONSTANT)
- public:
- enum Status { None, Started, Completed, Failed, Cancelled };
- Status status = None;
- bool isUpload = false;
- int progress = 0;
- int total = -1;
- QUrl localDir {};
- QUrl localPath {};
-
- bool started() const { return status == Started; }
- bool completed() const { return status == Completed; }
- bool active() const { return started() || completed(); }
- bool failed() const { return status == Failed; }
+ None,
+ Started,
+ Completed,
+ Failed,
+ Cancelled
};
-
- class Room : public QObject
+ Status status = None;
+ bool isUpload = false;
+ int progress = 0;
+ int total = -1;
+ QUrl localDir {};
+ QUrl localPath {};
+
+ bool started() const { return status == Started; }
+ bool completed() const { return status == Completed; }
+ bool active() const { return started() || completed(); }
+ bool failed() const { return status == Failed; }
+};
+
+class Room : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Connection* connection READ connection CONSTANT)
+ Q_PROPERTY(User* localUser READ localUser CONSTANT)
+ Q_PROPERTY(QString id READ id CONSTANT)
+ Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded)
+ Q_PROPERTY(bool isUnstable READ isUnstable NOTIFY stabilityUpdated)
+ Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded)
+ Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded)
+ Q_PROPERTY(QString name READ name NOTIFY namesChanged)
+ Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged)
+ Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
+ Q_PROPERTY(QString displayName READ displayName NOTIFY displaynameChanged)
+ Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
+ Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
+ STORED false)
+ Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
+ Q_PROPERTY(bool usesEncryption READ usesEncryption NOTIFY encryption)
+
+ Q_PROPERTY(int timelineSize READ timelineSize NOTIFY addedMessages)
+ Q_PROPERTY(QStringList memberNames READ memberNames NOTIFY memberListChanged)
+ Q_PROPERTY(int memberCount READ memberCount NOTIFY memberListChanged)
+ Q_PROPERTY(int joinedCount READ joinedCount NOTIFY memberListChanged)
+ Q_PROPERTY(int invitedCount READ invitedCount NOTIFY memberListChanged)
+ Q_PROPERTY(int totalMemberCount READ totalMemberCount NOTIFY memberListChanged)
+
+ Q_PROPERTY(bool displayed READ displayed WRITE setDisplayed NOTIFY
+ displayedChanged)
+ Q_PROPERTY(QString firstDisplayedEventId READ firstDisplayedEventId WRITE
+ setFirstDisplayedEventId NOTIFY firstDisplayedEventChanged)
+ Q_PROPERTY(QString lastDisplayedEventId READ lastDisplayedEventId WRITE
+ setLastDisplayedEventId NOTIFY lastDisplayedEventChanged)
+
+ Q_PROPERTY(QString readMarkerEventId READ readMarkerEventId WRITE
+ markMessagesAsRead NOTIFY readMarkerMoved)
+ Q_PROPERTY(bool hasUnreadMessages READ hasUnreadMessages NOTIFY
+ unreadMessagesChanged)
+ Q_PROPERTY(int unreadCount READ unreadCount NOTIFY unreadMessagesChanged)
+ Q_PROPERTY(int highlightCount READ highlightCount NOTIFY
+ highlightCountChanged RESET resetHighlightCount)
+ Q_PROPERTY(int notificationCount READ notificationCount NOTIFY
+ notificationCountChanged RESET resetNotificationCount)
+ 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(GetRoomEventsJob* eventsHistoryJob READ eventsHistoryJob NOTIFY
+ eventsHistoryJobChanged)
+
+public:
+ using Timeline = std::deque<TimelineItem>;
+ using PendingEvents = std::vector<PendingEventItem>;
+ using rev_iter_t = Timeline::const_reverse_iterator;
+ using timeline_iter_t = Timeline::const_iterator;
+
+ enum Change : uint
{
- Q_OBJECT
- Q_PROPERTY(Connection* connection READ connection CONSTANT)
- Q_PROPERTY(User* localUser READ localUser CONSTANT)
- Q_PROPERTY(QString id READ id CONSTANT)
- Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded)
- Q_PROPERTY(bool isUnstable READ isUnstable NOTIFY stabilityUpdated)
- Q_PROPERTY(
- QString predecessorId READ predecessorId NOTIFY baseStateLoaded)
- Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded)
- Q_PROPERTY(QString name READ name NOTIFY namesChanged)
- Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged)
- Q_PROPERTY(
- QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
- Q_PROPERTY(QString displayName READ displayName NOTIFY namesChanged)
- Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
- Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
- STORED false)
- Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
- Q_PROPERTY(bool usesEncryption READ usesEncryption NOTIFY encryption)
-
- Q_PROPERTY(int timelineSize READ timelineSize NOTIFY addedMessages)
- Q_PROPERTY(QStringList memberNames READ memberNames NOTIFY
- memberListChanged)
- Q_PROPERTY(int memberCount READ memberCount NOTIFY memberListChanged)
- Q_PROPERTY(int joinedCount READ joinedCount NOTIFY memberListChanged)
- Q_PROPERTY(int invitedCount READ invitedCount NOTIFY memberListChanged)
- Q_PROPERTY(int totalMemberCount READ totalMemberCount NOTIFY
- memberListChanged)
-
- Q_PROPERTY(bool displayed READ displayed WRITE setDisplayed NOTIFY
- displayedChanged)
- Q_PROPERTY(QString firstDisplayedEventId READ firstDisplayedEventId
- WRITE setFirstDisplayedEventId NOTIFY
- firstDisplayedEventChanged)
- Q_PROPERTY(QString lastDisplayedEventId READ lastDisplayedEventId WRITE
- setLastDisplayedEventId NOTIFY
- lastDisplayedEventChanged)
-
- Q_PROPERTY(QString readMarkerEventId READ readMarkerEventId WRITE
- markMessagesAsRead NOTIFY readMarkerMoved)
- Q_PROPERTY(bool hasUnreadMessages READ hasUnreadMessages NOTIFY
- unreadMessagesChanged)
- Q_PROPERTY(
- int unreadCount READ unreadCount NOTIFY unreadMessagesChanged)
- 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(GetRoomEventsJob* eventsHistoryJob READ eventsHistoryJob
- NOTIFY eventsHistoryJobChanged)
-
- public:
- using Timeline = std::deque<TimelineItem>;
- using PendingEvents = std::vector<PendingEventItem>;
- using rev_iter_t = Timeline::const_reverse_iterator;
- using timeline_iter_t = Timeline::const_iterator;
-
- enum Change : uint {
- NoChange = 0x0,
- NameChange = 0x1,
- CanonicalAliasChange = 0x2,
- TopicChange = 0x4,
- UnreadNotifsChange = 0x8,
- AvatarChange = 0x10,
- JoinStateChange = 0x20,
- TagsChange = 0x40,
- MembersChange = 0x80,
- /* = 0x100, */
- AccountDataChange = 0x200,
- SummaryChange = 0x400,
- ReadMarkerChange = 0x800,
- OtherChange = 0x8000,
- AnyChange = 0xFFFF
- };
- Q_DECLARE_FLAGS(Changes, Change)
- Q_FLAG(Changes)
-
- Room(Connection* connection, QString id, JoinState initialJoinState);
- ~Room() override;
-
- // Property accessors
-
- Connection* connection() const;
- User* localUser() const;
- const QString& id() const;
- QString version() const;
- bool isUnstable() const;
- QString predecessorId() const;
- QString successorId() const;
- QString name() const;
- QStringList aliases() const;
- QString canonicalAlias() const;
- QString displayName() const;
- QString topic() const;
- QString avatarMediaId() const;
- QUrl avatarUrl() const;
- const Avatar& avatarObject() const;
- Q_INVOKABLE JoinState joinState() const;
- Q_INVOKABLE QList<User*> usersTyping() const;
- QList<User*> membersLeft() const;
-
- Q_INVOKABLE QList<User*> users() const;
- QStringList memberNames() const;
- [[deprecated(
- "Use joinedCount(), invitedCount(), totalMemberCount()")]] int
- memberCount() const;
- int timelineSize() const;
- bool usesEncryption() const;
- int joinedCount() const;
- int invitedCount() const;
- int totalMemberCount() const;
-
- GetRoomEventsJob* eventsHistoryJob() const;
-
- /**
- * Returns a square room avatar with the given size and requests it
- * from the network if needed
- * \return a pixmap with the avatar or a placeholder if there's none
- * available yet
- */
- Q_INVOKABLE QImage avatar(int dimension);
- /**
- * Returns a room avatar with the given dimensions and requests it
- * from the network if needed
- * \return a pixmap with the avatar or a placeholder if there's none
- * available yet
- */
- Q_INVOKABLE QImage avatar(int width, int height);
-
- /**
- * \brief Get a user object for a given user id
- * This is the recommended way to get a user object in a room
- * context. The actual object type may be changed in further
- * versions to provide room-specific user information (display name,
- * avatar etc.).
- * \note The method will return a valid user regardless of
- * the membership.
- */
- Q_INVOKABLE User* user(const QString& userId) const;
-
- /**
- * \brief Check the join state of a given user in this room
- *
- * \note Banned and invited users are not tracked for now (Leave
- * will be returned for them).
- *
- * \return either of Join, Leave, depending on the given
- * user's state in the room
- */
- Q_INVOKABLE JoinState memberJoinState(User* user) const;
-
- /**
- * Get a disambiguated name for a given user in
- * the context of the room
- */
- Q_INVOKABLE QString roomMembername(const User* u) const;
- /**
- * Get a disambiguated name for a user with this id in
- * the context of the room
- */
- Q_INVOKABLE QString roomMembername(const QString& userId) const;
-
- const Timeline& messageEvents() const;
- const PendingEvents& pendingEvents() const;
- /**
- * A convenience method returning the read marker to the position
- * before the "oldest" event; same as messageEvents().crend()
- */
- rev_iter_t historyEdge() const;
- /**
- * A convenience method returning the iterator beyond the latest
- * arrived event; same as messageEvents().cend()
- */
- Timeline::const_iterator syncEdge() const;
- /// \deprecated Use historyEdge instead
- rev_iter_t timelineEdge() const;
- Q_INVOKABLE TimelineItem::index_t minTimelineIndex() const;
- Q_INVOKABLE TimelineItem::index_t maxTimelineIndex() const;
- Q_INVOKABLE bool
- isValidIndex(TimelineItem::index_t timelineIndex) const;
-
- rev_iter_t findInTimeline(TimelineItem::index_t index) const;
- rev_iter_t findInTimeline(const QString& evtId) const;
- PendingEvents::iterator findPendingEvent(const QString& txnId);
- PendingEvents::const_iterator
- findPendingEvent(const QString& txnId) const;
-
- bool displayed() const;
- /// Mark the room as currently displayed to the user
- /**
- * Marking the room displayed causes the room to obtain the full
- * list of members if it's been lazy-loaded before; in the future
- * it may do more things bound to "screen time" of the room, e.g.
- * measure that "screen time".
- */
- void setDisplayed(bool displayed = true);
- QString firstDisplayedEventId() const;
- rev_iter_t firstDisplayedMarker() const;
- void setFirstDisplayedEventId(const QString& eventId);
- void setFirstDisplayedEvent(TimelineItem::index_t index);
- QString lastDisplayedEventId() const;
- rev_iter_t lastDisplayedMarker() const;
- void setLastDisplayedEventId(const QString& eventId);
- void setLastDisplayedEvent(TimelineItem::index_t index);
-
- rev_iter_t readMarker(const User* user) const;
- rev_iter_t readMarker() const;
- QString readMarkerEventId() const;
- QList<User*> usersAtEventId(const QString& eventId);
- /**
- * \brief Mark the event with uptoEventId as read
- *
- * Finds in the timeline and marks as read the event with
- * the specified id; also posts a read receipt to the server either
- * for this message or, if it's from the local user, for
- * the nearest non-local message before. uptoEventId must be non-empty.
- */
- void markMessagesAsRead(QString uptoEventId);
-
- /// Check whether there are unread messages in the room
- bool hasUnreadMessages() const;
-
- /** Get the number of unread messages in the room
- * Depending on the read marker state, this call may return either
- * a precise or an estimate number of unread events. Only "notable"
- * events (non-redacted message events from users other than local)
- * are counted.
- *
- * In a case when readMarker() == timelineEdge() (the local read
- * marker is beyond the local timeline) only the bottom limit of
- * the unread messages number can be estimated (and even that may
- * be slightly off due to, e.g., redactions of events not loaded
- * to the local timeline).
- *
- * If all messages are read, this function will return -1 (_not_ 0,
- * as zero may mean "zero or more unread messages" in a situation
- * when the read marker is outside the local timeline.
- */
- int unreadCount() const;
-
- Q_INVOKABLE int notificationCount() const;
- Q_INVOKABLE void resetNotificationCount();
- Q_INVOKABLE int highlightCount() const;
- Q_INVOKABLE void resetHighlightCount();
-
- /** Check whether the room has account data of the given type
- * Tags and read markers are not supported by this method _yet_.
- */
- bool hasAccountData(const QString& type) const;
-
- /** Get a generic account data event of the given type
- * This returns a generic hashmap for any room account data event
- * stored on the server. Tags and read markers cannot be retrieved
- * using this method _yet_.
- */
- const EventPtr& accountData(const QString& type) const;
-
- QStringList tagNames() const;
- TagsMap tags() const;
- TagRecord tag(const QString& name) const;
-
- /** Add a new tag to this room
- * If this room already has this tag, nothing happens. If it's a new
- * tag for the room, the respective tag record is added to the set
- * of tags and the new set is sent to the server to update other
- * clients.
- */
- void addTag(const QString& name, const TagRecord& record = {});
- Q_INVOKABLE void addTag(const QString& name, float order);
-
- /// Remove a tag from the room
- Q_INVOKABLE void removeTag(const QString& name);
-
- /** Overwrite the room's tags
- * This completely replaces the existing room's tags with a set
- * of new ones and updates the new set on the server. Unlike
- * most other methods in Room, this one sends a signal about changes
- * immediately, not waiting for confirmation from the server
- * (because tags are saved in account data rather than in shared
- * room state).
- */
- void setTags(TagsMap newTags);
-
- /// Check whether the list of tags has m.favourite
- bool isFavourite() const;
- /// Check whether the list of tags has m.lowpriority
- bool isLowPriority() const;
-
- /// Check whether this room is a direct chat
- Q_INVOKABLE bool isDirectChat() const;
-
- /// Get the list of users this room is a direct chat with
- QList<User*> directChatUsers() const;
-
- Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId) const;
- Q_INVOKABLE QUrl urlToDownload(const QString& eventId) const;
- Q_INVOKABLE QString fileNameToDownload(const QString& eventId) const;
- Q_INVOKABLE FileTransferInfo fileTransferInfo(const QString& id) const;
- Q_INVOKABLE QUrl fileSource(const QString& id) const;
-
- /** Pretty-prints plain text into HTML
- * As of now, it's exactly the same as QMatrixClient::prettyPrint();
- * in the future, it will also linkify room aliases, mxids etc.
- * using the room context.
- */
- QString prettyPrint(const QString& plainText) const;
-
- MemberSorter memberSorter() const;
-
- Q_INVOKABLE void inviteCall(const QString& callId, const int lifetime,
- const QString& sdp);
- Q_INVOKABLE void sendCallCandidates(const QString& callId,
- const QJsonArray& candidates);
- Q_INVOKABLE void answerCall(const QString& callId, const int lifetime,
- const QString& sdp);
- Q_INVOKABLE void answerCall(const QString& callId, const QString& sdp);
- Q_INVOKABLE void hangupCall(const QString& callId);
- Q_INVOKABLE bool supportsCalls() const;
-
- public slots:
- /** Check whether the room should be upgraded */
- void checkVersion();
-
- QString postMessage(const QString& plainText, MessageEventType type);
- QString postPlainText(const QString& plainText);
- QString postHtmlMessage(const QString& plainText, const QString& html,
- MessageEventType type = MessageEventType::Text);
- QString postHtmlText(const QString& plainText, const QString& html);
- QString postFile(const QString& plainText, const QUrl& localPath,
- bool asGenericFile = false);
- /** Post a pre-created room message event
- *
- * Takes ownership of the event, deleting it once the matching one
- * arrives with the sync
- * \return transaction id associated with the event.
- */
- QString postEvent(RoomEvent* event);
- QString postJson(const QString& matrixType,
- const QJsonObject& eventContent);
- QString retryMessage(const QString& txnId);
- void discardMessage(const QString& txnId);
- void setName(const QString& newName);
- void setCanonicalAlias(const QString& newAlias);
- void setAliases(const QStringList& aliases);
- void setTopic(const QString& newTopic);
-
- void getPreviousContent(int limit = 10);
-
- void inviteToRoom(const QString& memberId);
- LeaveRoomJob* leaveRoom();
- SetRoomStateWithKeyJob*
- setMemberState(const QString& memberId,
- const RoomMemberEvent& event) const;
- void kickMember(const QString& memberId, const QString& reason = {});
- void ban(const QString& userId, const QString& reason = {});
- void unban(const QString& userId);
- void redactEvent(const QString& eventId, const QString& reason = {});
-
- void uploadFile(const QString& id, const QUrl& localFilename,
- const QString& overrideContentType = {});
- // If localFilename is empty a temporary file is created
- void downloadFile(const QString& eventId,
- const QUrl& localFilename = {});
- void cancelFileTransfer(const QString& id);
-
- /// Mark all messages in the room as read
- void markAllMessagesAsRead();
-
- /// Whether the current user is allowed to upgrade the room
- bool canSwitchVersions() const;
-
- /// Switch the room's version (aka upgrade)
- void switchVersion(QString newVersion);
-
- signals:
- /// Initial set of state events has been loaded
- /**
- * The initial set is what comes from the initial sync for the room.
- * This includes all basic things like RoomCreateEvent,
- * RoomNameEvent, a (lazy-loaded, not full) set of RoomMemberEvents
- * etc. This is a per-room reflection of Connection::loadedRoomState
- * \sa Connection::loadedRoomState
- */
- void baseStateLoaded();
- void eventsHistoryJobChanged();
- void aboutToAddHistoricalMessages(RoomEventsRange events);
- void aboutToAddNewMessages(RoomEventsRange events);
- void addedMessages(int fromIndex, int toIndex);
- /// The event is about to be appended to the list of pending events
- void pendingEventAboutToAdd(RoomEvent* event);
- /// An event has been appended to the list of pending events
- void pendingEventAdded();
- /// The remote echo has arrived with the sync and will be merged
- /// with its local counterpart
- /** NB: Requires a sync loop to be emitted */
- void pendingEventAboutToMerge(RoomEvent* serverEvent,
- int pendingEventIndex);
- /// The remote and local copies of the event have been merged
- /** NB: Requires a sync loop to be emitted */
- void pendingEventMerged();
- /// An event will be removed from the list of pending events
- void pendingEventAboutToDiscard(int pendingEventIndex);
- /// An event has just been removed from the list of pending events
- void pendingEventDiscarded();
- /// The status of a pending event has changed
- /** \sa PendingEventItem::deliveryStatus */
- void pendingEventChanged(int pendingEventIndex);
- /// The server accepted the message
- /** This is emitted when an event sending request has successfully
- * completed. This does not mean that the event is already in the
- * local timeline, only that the server has accepted it.
- * \param txnId transaction id assigned by the client during sending
- * \param eventId event id assigned by the server upon acceptance
- * \sa postEvent, postPlainText, postMessage, postHtmlMessage
- * \sa pendingEventMerged, aboutToAddNewMessages
- */
- void messageSent(QString txnId, QString eventId);
-
- /** A common signal for various kinds of changes in the room
- * Aside from all changes in the room state
- * @param changes a set of flags describing what changes occured
- * upon the last sync
- * \sa StateChange
- */
- void changed(Changes changes);
- /**
- * \brief The room name, the canonical alias or other aliases changed
- *
- * Not triggered when displayname changes.
- */
- void namesChanged(Room* room);
- void displaynameAboutToChange(Room* room);
- void displaynameChanged(Room* room, QString oldName);
- void topicChanged();
- void avatarChanged();
- void userAdded(User* user);
- void userRemoved(User* user);
- void memberAboutToRename(User* user, QString newName);
- void memberRenamed(User* user);
- /// The list of members has changed
- /** Emitted no more than once per sync, this is a good signal to
- * for cases when some action should be done upon any change in
- * the member list. If you need per-item granularity you should use
- * userAdded, userRemoved and memberAboutToRename / memberRenamed
- * instead.
- */
- void memberListChanged();
- /// The previously lazy-loaded members list is now loaded entirely
- /// \sa setDisplayed
- void allMembersLoaded();
- void encryption();
-
- void joinStateChanged(JoinState oldState, JoinState newState);
- void typingChanged();
-
- void highlightCountChanged(Room* room);
- void notificationCountChanged(Room* room);
-
- void displayedChanged(bool displayed);
- void firstDisplayedEventChanged();
- void lastDisplayedEventChanged();
- void lastReadEventChanged(User* user);
- void readMarkerMoved(QString fromEventId, QString toEventId);
- void readMarkerForUserMoved(User* user, QString fromEventId,
- QString toEventId);
- void unreadMessagesChanged(Room* room);
-
- void accountDataAboutToChange(QString type);
- void accountDataChanged(QString type);
- void tagsAboutToChange();
- void tagsChanged();
-
- void replacedEvent(const RoomEvent* newEvent,
- const RoomEvent* oldEvent);
-
- void newFileTransfer(QString id, QUrl localFile);
- 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);
-
- void callEvent(Room* room, const RoomEvent* event);
-
- /// The room's version stability may have changed
- void stabilityUpdated(QString recommendedDefault,
- QStringList stableVersions);
- /// This room has been upgraded and won't receive updates anymore
- void upgraded(QString serverMessage, Room* successor);
- /// An attempted room upgrade has failed
- void upgradeFailed(QString errorMessage);
-
- /// The room is about to be deleted
- void beforeDestruction(Room*);
-
- protected:
- /// Returns true if any of room names/aliases has changed
- virtual Changes processStateEvent(const RoomEvent& e);
- virtual Changes processEphemeralEvent(EventPtr&& event);
- virtual Changes processAccountDataEvent(EventPtr&& event);
- virtual void onAddNewTimelineEvents(timeline_iter_t /*from*/) {}
- virtual void onAddHistoricalTimelineEvents(rev_iter_t /*from*/) {}
- virtual void onRedaction(const RoomEvent& /*prevEvent*/,
- const RoomEvent& /*after*/)
- {
- }
- virtual QJsonObject toJson() const;
- virtual void updateData(SyncRoomData&& data, bool fromCache = false);
-
- private:
- friend class Connection;
-
- class Private;
- Private* d;
-
- // This is called from Connection, reflecting a state change that
- // arrived from the server. Clients should use
- // Connection::joinRoom() and Room::leaveRoom() to change the state.
- void setJoinState(JoinState state);
+ NoChange = 0x0,
+ NameChange = 0x1,
+ CanonicalAliasChange = 0x2,
+ TopicChange = 0x4,
+ UnreadNotifsChange = 0x8,
+ AvatarChange = 0x10,
+ JoinStateChange = 0x20,
+ TagsChange = 0x40,
+ MembersChange = 0x80,
+ /* = 0x100, */
+ AccountDataChange = 0x200,
+ SummaryChange = 0x400,
+ ReadMarkerChange = 0x800,
+ OtherChange = 0x8000,
+ AnyChange = 0xFFFF
};
+ Q_DECLARE_FLAGS(Changes, Change)
+ Q_FLAG(Changes)
+
+ Room(Connection* connection, QString id, JoinState initialJoinState);
+ ~Room() override;
+
+ // Property accessors
+
+ Connection* connection() const;
+ User* localUser() const;
+ const QString& id() const;
+ QString version() const;
+ bool isUnstable() const;
+ QString predecessorId() const;
+ QString successorId() const;
+ QString name() const;
+ QStringList aliases() const;
+ QString canonicalAlias() const;
+ QString displayName() const;
+ QString topic() const;
+ QString avatarMediaId() const;
+ QUrl avatarUrl() const;
+ const Avatar& avatarObject() const;
+ Q_INVOKABLE JoinState joinState() const;
+ Q_INVOKABLE QList<User*> usersTyping() const;
+ QList<User*> membersLeft() const;
+
+ Q_INVOKABLE QList<User*> users() const;
+ QStringList memberNames() const;
+ [[deprecated("Use joinedCount(), invitedCount(), totalMemberCount()")]] int
+ memberCount() const;
+ int timelineSize() const;
+ bool usesEncryption() const;
+ int joinedCount() const;
+ int invitedCount() const;
+ int totalMemberCount() const;
+
+ GetRoomEventsJob* eventsHistoryJob() const;
+
+ /**
+ * Returns a square room avatar with the given size and requests it
+ * from the network if needed
+ * \return a pixmap with the avatar or a placeholder if there's none
+ * available yet
+ */
+ Q_INVOKABLE QImage avatar(int dimension);
+ /**
+ * Returns a room avatar with the given dimensions and requests it
+ * from the network if needed
+ * \return a pixmap with the avatar or a placeholder if there's none
+ * available yet
+ */
+ Q_INVOKABLE QImage avatar(int width, int height);
+
+ /**
+ * \brief Get a user object for a given user id
+ * This is the recommended way to get a user object in a room
+ * context. The actual object type may be changed in further
+ * versions to provide room-specific user information (display name,
+ * avatar etc.).
+ * \note The method will return a valid user regardless of
+ * the membership.
+ */
+ Q_INVOKABLE User* user(const QString& userId) const;
- class MemberSorter
- {
- public:
- explicit MemberSorter(const Room* r) : room(r) {}
+ /**
+ * \brief Check the join state of a given user in this room
+ *
+ * \note Banned and invited users are not tracked for now (Leave
+ * will be returned for them).
+ *
+ * \return either of Join, Leave, depending on the given
+ * user's state in the room
+ */
+ Q_INVOKABLE JoinState memberJoinState(User* user) const;
- bool operator()(User* u1, User* u2) const;
- bool operator()(User* u1, const QString& u2name) const;
+ /**
+ * Get a disambiguated name for a given user in
+ * the context of the room
+ */
+ Q_INVOKABLE QString roomMembername(const User* u) const;
+ /**
+ * Get a disambiguated name for a user with this id in
+ * the context of the room
+ */
+ Q_INVOKABLE QString roomMembername(const QString& userId) const;
- template <typename ContT, typename ValT>
- typename ContT::size_type lowerBoundIndex(const ContT& c,
- const ValT& v) const
- {
- return std::lower_bound(c.begin(), c.end(), v, *this) - c.begin();
- }
+ const Timeline& messageEvents() const;
+ const PendingEvents& pendingEvents() const;
- private:
- const Room* room;
- };
+ /// Check whether all historical messages are already loaded
+ /**
+ * \return true if the "oldest" event in the timeline is
+ * a room creation event and there's no further history
+ * to load; false otherwise
+ */
+ bool allHistoryLoaded() const;
+ /**
+ * A convenience method returning the read marker to the position
+ * before the "oldest" event; same as messageEvents().crend()
+ */
+ rev_iter_t historyEdge() const;
+ /**
+ * A convenience method returning the iterator beyond the latest
+ * arrived event; same as messageEvents().cend()
+ */
+ Timeline::const_iterator syncEdge() const;
+ /// \deprecated Use historyEdge instead
+ rev_iter_t timelineEdge() const;
+ Q_INVOKABLE TimelineItem::index_t minTimelineIndex() const;
+ Q_INVOKABLE TimelineItem::index_t maxTimelineIndex() const;
+ Q_INVOKABLE bool isValidIndex(TimelineItem::index_t timelineIndex) const;
+
+ rev_iter_t findInTimeline(TimelineItem::index_t index) const;
+ rev_iter_t findInTimeline(const QString& evtId) const;
+ PendingEvents::iterator findPendingEvent(const QString& txnId);
+ PendingEvents::const_iterator findPendingEvent(const QString& txnId) const;
+
+ bool displayed() const;
+ /// Mark the room as currently displayed to the user
+ /**
+ * Marking the room displayed causes the room to obtain the full
+ * list of members if it's been lazy-loaded before; in the future
+ * it may do more things bound to "screen time" of the room, e.g.
+ * measure that "screen time".
+ */
+ void setDisplayed(bool displayed = true);
+ QString firstDisplayedEventId() const;
+ rev_iter_t firstDisplayedMarker() const;
+ void setFirstDisplayedEventId(const QString& eventId);
+ void setFirstDisplayedEvent(TimelineItem::index_t index);
+ QString lastDisplayedEventId() const;
+ rev_iter_t lastDisplayedMarker() const;
+ void setLastDisplayedEventId(const QString& eventId);
+ void setLastDisplayedEvent(TimelineItem::index_t index);
+
+ rev_iter_t readMarker(const User* user) const;
+ rev_iter_t readMarker() const;
+ QString readMarkerEventId() const;
+ QList<User*> usersAtEventId(const QString& eventId);
+ /**
+ * \brief Mark the event with uptoEventId as read
+ *
+ * Finds in the timeline and marks as read the event with
+ * the specified id; also posts a read receipt to the server either
+ * for this message or, if it's from the local user, for
+ * the nearest non-local message before. uptoEventId must be non-empty.
+ */
+ void markMessagesAsRead(QString uptoEventId);
+
+ /// Check whether there are unread messages in the room
+ bool hasUnreadMessages() const;
+
+ /** Get the number of unread messages in the room
+ * Depending on the read marker state, this call may return either
+ * a precise or an estimate number of unread events. Only "notable"
+ * events (non-redacted message events from users other than local)
+ * are counted.
+ *
+ * In a case when readMarker() == timelineEdge() (the local read
+ * marker is beyond the local timeline) only the bottom limit of
+ * the unread messages number can be estimated (and even that may
+ * be slightly off due to, e.g., redactions of events not loaded
+ * to the local timeline).
+ *
+ * If all messages are read, this function will return -1 (_not_ 0,
+ * as zero may mean "zero or more unread messages" in a situation
+ * when the read marker is outside the local timeline.
+ */
+ int unreadCount() const;
+
+ Q_INVOKABLE int notificationCount() const;
+ Q_INVOKABLE void resetNotificationCount();
+ Q_INVOKABLE int highlightCount() const;
+ Q_INVOKABLE void resetHighlightCount();
+
+ /** Check whether the room has account data of the given type
+ * Tags and read markers are not supported by this method _yet_.
+ */
+ bool hasAccountData(const QString& type) const;
+
+ /** Get a generic account data event of the given type
+ * This returns a generic hash map for any room account data event
+ * stored on the server. Tags and read markers cannot be retrieved
+ * using this method _yet_.
+ */
+ const EventPtr& accountData(const QString& type) const;
+
+ QStringList tagNames() const;
+ TagsMap tags() const;
+ TagRecord tag(const QString& name) const;
+
+ /** Add a new tag to this room
+ * If this room already has this tag, nothing happens. If it's a new
+ * tag for the room, the respective tag record is added to the set
+ * of tags and the new set is sent to the server to update other
+ * clients.
+ */
+ void addTag(const QString& name, const TagRecord& record = {});
+ Q_INVOKABLE void addTag(const QString& name, float order);
+
+ /// Remove a tag from the room
+ Q_INVOKABLE void removeTag(const QString& name);
+
+ /** Overwrite the room's tags
+ * This completely replaces the existing room's tags with a set
+ * of new ones and updates the new set on the server. Unlike
+ * most other methods in Room, this one sends a signal about changes
+ * immediately, not waiting for confirmation from the server
+ * (because tags are saved in account data rather than in shared
+ * room state).
+ */
+ void setTags(TagsMap newTags);
+
+ /// Check whether the list of tags has m.favourite
+ bool isFavourite() const;
+ /// Check whether the list of tags has m.lowpriority
+ bool isLowPriority() const;
+
+ /// Check whether this room is a direct chat
+ Q_INVOKABLE bool isDirectChat() const;
+
+ /// Get the list of users this room is a direct chat with
+ QList<User*> directChatUsers() const;
+
+ Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId) const;
+ Q_INVOKABLE QUrl urlToDownload(const QString& eventId) const;
+
+ /// Get a file name for downloading for a given event id
+ /*!
+ * The event MUST be RoomMessageEvent and have content
+ * for downloading. \sa RoomMessageEvent::hasContent
+ */
+ Q_INVOKABLE QString fileNameToDownload(const QString& eventId) const;
+
+ /// Get information on file upload/download
+ /*!
+ * \param id uploads are identified by the corresponding event's
+ * transactionId (because uploads are done before
+ * the event is even sent), while downloads are using
+ * the normal event id for identifier.
+ */
+ Q_INVOKABLE FileTransferInfo fileTransferInfo(const QString& id) const;
+
+ /// Get the URL to the actual file source in a unified way
+ /*!
+ * For uploads it will return a URL to a local file; for downloads
+ * the URL will be taken from the corresponding room event.
+ */
+ Q_INVOKABLE QUrl fileSource(const QString& id) const;
+
+ /** Pretty-prints plain text into HTML
+ * As of now, it's exactly the same as QMatrixClient::prettyPrint();
+ * in the future, it will also linkify room aliases, mxids etc.
+ * using the room context.
+ */
+ Q_INVOKABLE QString prettyPrint(const QString& plainText) const;
+
+ MemberSorter memberSorter() const;
+
+ Q_INVOKABLE void inviteCall(const QString& callId, const int lifetime,
+ const QString& sdp);
+ Q_INVOKABLE void sendCallCandidates(const QString& callId,
+ const QJsonArray& candidates);
+ Q_INVOKABLE void answerCall(const QString& callId, const int lifetime,
+ const QString& sdp);
+ Q_INVOKABLE void answerCall(const QString& callId, const QString& sdp);
+ Q_INVOKABLE void hangupCall(const QString& callId);
+ Q_INVOKABLE bool supportsCalls() const;
+
+public slots:
+ /** Check whether the room should be upgraded */
+ void checkVersion();
+
+ QString postMessage(const QString& plainText, MessageEventType type);
+ QString postPlainText(const QString& plainText);
+ QString postHtmlMessage(const QString& plainText, const QString& html,
+ MessageEventType type = MessageEventType::Text);
+ QString postHtmlText(const QString& plainText, const QString& html);
+ QString postFile(const QString& plainText, const QUrl& localPath,
+ bool asGenericFile = false);
+ /** Post a pre-created room message event
+ *
+ * Takes ownership of the event, deleting it once the matching one
+ * arrives with the sync
+ * \return transaction id associated with the event.
+ */
+ QString postEvent(RoomEvent* event);
+ QString postJson(const QString& matrixType, const QJsonObject& eventContent);
+ QString retryMessage(const QString& txnId);
+ void discardMessage(const QString& txnId);
+ void setName(const QString& newName);
+ void setCanonicalAlias(const QString& newAlias);
+ void setAliases(const QStringList& aliases);
+ void setTopic(const QString& newTopic);
+
+ /// You shouldn't normally call this method; it's here for debugging
+ void refreshDisplayName();
+
+ void getPreviousContent(int limit = 10);
+
+ void inviteToRoom(const QString& memberId);
+ LeaveRoomJob* leaveRoom();
+ SetRoomStateWithKeyJob* setMemberState(const QString& memberId,
+ const RoomMemberEvent& event) const;
+ void kickMember(const QString& memberId, const QString& reason = {});
+ void ban(const QString& userId, const QString& reason = {});
+ void unban(const QString& userId);
+ void redactEvent(const QString& eventId, const QString& reason = {});
+
+ void uploadFile(const QString& id, const QUrl& localFilename,
+ const QString& overrideContentType = {});
+ // If localFilename is empty a temporary file is created
+ void downloadFile(const QString& eventId, const QUrl& localFilename = {});
+ void cancelFileTransfer(const QString& id);
+
+ /// Mark all messages in the room as read
+ void markAllMessagesAsRead();
+
+ /// Whether the current user is allowed to upgrade the room
+ bool canSwitchVersions() const;
+
+ /// Switch the room's version (aka upgrade)
+ void switchVersion(QString newVersion);
+
+signals:
+ /// Initial set of state events has been loaded
+ /**
+ * The initial set is what comes from the initial sync for the room.
+ * This includes all basic things like RoomCreateEvent,
+ * RoomNameEvent, a (lazy-loaded, not full) set of RoomMemberEvents
+ * etc. This is a per-room reflection of Connection::loadedRoomState
+ * \sa Connection::loadedRoomState
+ */
+ void baseStateLoaded();
+ void eventsHistoryJobChanged();
+ void aboutToAddHistoricalMessages(RoomEventsRange events);
+ void aboutToAddNewMessages(RoomEventsRange events);
+ void addedMessages(int fromIndex, int toIndex);
+ /// The event is about to be appended to the list of pending events
+ void pendingEventAboutToAdd(RoomEvent* event);
+ /// An event has been appended to the list of pending events
+ void pendingEventAdded();
+ /// The remote echo has arrived with the sync and will be merged
+ /// with its local counterpart
+ /** NB: Requires a sync loop to be emitted */
+ void pendingEventAboutToMerge(RoomEvent* serverEvent, int pendingEventIndex);
+ /// The remote and local copies of the event have been merged
+ /** NB: Requires a sync loop to be emitted */
+ void pendingEventMerged();
+ /// An event will be removed from the list of pending events
+ void pendingEventAboutToDiscard(int pendingEventIndex);
+ /// An event has just been removed from the list of pending events
+ void pendingEventDiscarded();
+ /// The status of a pending event has changed
+ /** \sa PendingEventItem::deliveryStatus */
+ void pendingEventChanged(int pendingEventIndex);
+ /// The server accepted the message
+ /** This is emitted when an event sending request has successfully
+ * completed. This does not mean that the event is already in the
+ * local timeline, only that the server has accepted it.
+ * \param txnId transaction id assigned by the client during sending
+ * \param eventId event id assigned by the server upon acceptance
+ * \sa postEvent, postPlainText, postMessage, postHtmlMessage
+ * \sa pendingEventMerged, aboutToAddNewMessages
+ */
+ void messageSent(QString txnId, QString eventId);
+
+ /** A common signal for various kinds of changes in the room
+ * Aside from all changes in the room state
+ * @param changes a set of flags describing what changes occurred
+ * upon the last sync
+ * \sa StateChange
+ */
+ void changed(Changes changes);
+ /**
+ * \brief The room name, the canonical alias or other aliases changed
+ *
+ * Not triggered when display name changes.
+ */
+ void namesChanged(Room* room);
+ void displaynameAboutToChange(Room* room);
+ void displaynameChanged(Room* room, QString oldName);
+ void topicChanged();
+ void avatarChanged();
+ void userAdded(User* user);
+ void userRemoved(User* user);
+ void memberAboutToRename(User* user, QString newName);
+ void memberRenamed(User* user);
+ /// The list of members has changed
+ /** Emitted no more than once per sync, this is a good signal to
+ * for cases when some action should be done upon any change in
+ * the member list. If you need per-item granularity you should use
+ * userAdded, userRemoved and memberAboutToRename / memberRenamed
+ * instead.
+ */
+ void memberListChanged();
+ /// The previously lazy-loaded members list is now loaded entirely
+ /// \sa setDisplayed
+ void allMembersLoaded();
+ void encryption();
+
+ void joinStateChanged(JoinState oldState, JoinState newState);
+ void typingChanged();
+
+ void highlightCountChanged();
+ void notificationCountChanged();
+
+ void displayedChanged(bool displayed);
+ void firstDisplayedEventChanged();
+ void lastDisplayedEventChanged();
+ void lastReadEventChanged(User* user);
+ void readMarkerMoved(QString fromEventId, QString toEventId);
+ void readMarkerForUserMoved(User* user, QString fromEventId,
+ QString toEventId);
+ void unreadMessagesChanged(Room* room);
+
+ void accountDataAboutToChange(QString type);
+ void accountDataChanged(QString type);
+ void tagsAboutToChange();
+ void tagsChanged();
+
+ void replacedEvent(const RoomEvent* newEvent, const RoomEvent* oldEvent);
+
+ void newFileTransfer(QString id, QUrl localFile);
+ 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);
+
+ void callEvent(Room* room, const RoomEvent* event);
+
+ /// The room's version stability may have changed
+ void stabilityUpdated(QString recommendedDefault,
+ QStringList stableVersions);
+ /// This room has been upgraded and won't receive updates any more
+ void upgraded(QString serverMessage, Room* successor);
+ /// An attempted room upgrade has failed
+ void upgradeFailed(QString errorMessage);
+
+ /// The room is about to be deleted
+ void beforeDestruction(Room*);
+
+protected:
+ /// Returns true if any of room names/aliases has changed
+ virtual Changes processStateEvent(const RoomEvent& e);
+ virtual Changes processEphemeralEvent(EventPtr&& event);
+ virtual Changes processAccountDataEvent(EventPtr&& event);
+ virtual void onAddNewTimelineEvents(timeline_iter_t /*from*/) {}
+ virtual void onAddHistoricalTimelineEvents(rev_iter_t /*from*/) {}
+ virtual void onRedaction(const RoomEvent& /*prevEvent*/,
+ const RoomEvent& /*after*/)
+ {}
+ virtual QJsonObject toJson() const;
+ virtual void updateData(SyncRoomData&& data, bool fromCache = false);
+
+private:
+ friend class Connection;
+
+ class Private;
+ Private* d;
+
+ // This is called from Connection, reflecting a state change that
+ // arrived from the server. Clients should use
+ // Connection::joinRoom() and Room::leaveRoom() to change the state.
+ void setJoinState(JoinState state);
+};
+
+class MemberSorter
+{
+public:
+ explicit MemberSorter(const Room* r)
+ : room(r)
+ {}
+
+ bool operator()(User* u1, User* u2) const;
+ bool operator()(User* u1, const QString& u2name) const;
+
+ template <typename ContT, typename ValT>
+ typename ContT::size_type lowerBoundIndex(const ContT& c, const ValT& v) const
+ {
+ return std::lower_bound(c.begin(), c.end(), v, *this) - c.begin();
+ }
+
+private:
+ const Room* room;
+};
} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::FileTransferInfo)
Q_DECLARE_OPERATORS_FOR_FLAGS(QMatrixClient::Room::Changes)
diff --git a/lib/settings.cpp b/lib/settings.cpp
index e0a1783f..f8f1eae5 100644
--- a/lib/settings.cpp
+++ b/lib/settings.cpp
@@ -32,8 +32,7 @@ QVariant Settings::value(const QString& key, const QVariant& defaultValue) const
// (QVariant("false") == true in JavaScript). Since we have a mixed
// environment where both QSettings and Qt.labs.Settings may potentially
// work with same settings, better ensure compatibility.
- return value.toString() == QStringLiteral("false") ? QVariant(false)
- : value;
+ return value.toString() == QStringLiteral("false") ? QVariant(false) : value;
}
bool Settings::contains(const QString& key) const
@@ -83,40 +82,44 @@ void SettingsGroup::remove(const QString& key)
Settings::remove(fullKey);
}
-QMC_DEFINE_SETTING(AccountSettings, QString, deviceId, "device_id", "",
+QMC_DEFINE_SETTING(AccountSettings, QString, deviceId, "device_id", {},
setDeviceId)
-QMC_DEFINE_SETTING(AccountSettings, QString, deviceName, "device_name", "",
+QMC_DEFINE_SETTING(AccountSettings, QString, deviceName, "device_name", {},
setDeviceName)
QMC_DEFINE_SETTING(AccountSettings, bool, keepLoggedIn, "keep_logged_in", false,
setKeepLoggedIn)
+static const auto HomeserverKey = QStringLiteral("homeserver");
+static const auto AccessTokenKey = QStringLiteral("access_token");
+
QUrl AccountSettings::homeserver() const
{
- return QUrl::fromUserInput(value("homeserver").toString());
+ return QUrl::fromUserInput(value(HomeserverKey).toString());
}
void AccountSettings::setHomeserver(const QUrl& url)
{
- setValue("homeserver", url.toString());
+ setValue(HomeserverKey, url.toString());
}
QString AccountSettings::userId() const { return group().section('/', -1); }
QString AccountSettings::accessToken() const
{
- return value("access_token").toString();
+ return value(AccessTokenKey).toString();
}
void AccountSettings::setAccessToken(const QString& accessToken)
{
qCWarning(MAIN) << "Saving access_token to QSettings is insecure."
" Developers, please save access_token separately.";
- setValue("access_token", accessToken);
+ setValue(AccessTokenKey, accessToken);
}
void AccountSettings::clearAccessToken()
{
- legacySettings.remove("access_token");
- legacySettings.remove("device_id"); // Force the server to re-issue it
- remove("access_token");
+ legacySettings.remove(AccessTokenKey);
+ legacySettings.remove(QStringLiteral("device_id")); // Force the server to
+ // re-issue it
+ remove(AccessTokenKey);
}
diff --git a/lib/settings.h b/lib/settings.h
index 0cde47a3..cb09c479 100644
--- a/lib/settings.h
+++ b/lib/settings.h
@@ -24,131 +24,128 @@
class QVariant;
-namespace QMatrixClient {
- class Settings : public QSettings
- {
- Q_OBJECT
- public:
- /**
- * Use this function before creating any Settings objects in order
- * to setup a read-only location where configuration has previously
- * been stored. This will provide an additional fallback in case of
- * renaming the organisation/application.
- */
- static void setLegacyNames(const QString& organizationName,
- const QString& applicationName = {});
+namespace QMatrixClient
+{
+class Settings : public QSettings
+{
+ Q_OBJECT
+public:
+ /**
+ * Use this function before creating any Settings objects in order
+ * to setup a read-only location where configuration has previously
+ * been stored. This will provide an additional fallback in case of
+ * renaming the organisation/application.
+ */
+ static void setLegacyNames(const QString& organizationName,
+ const QString& applicationName = {});
#if defined(_MSC_VER) && _MSC_VER < 1900
- // VS 2013 (and probably older) aren't friends with 'using' statements
- // that involve private constructors
- explicit Settings(QObject* parent = 0) : QSettings(parent) {}
+ // VS 2013 (and probably older) aren't friends with 'using' statements
+ // that involve private constructors
+ explicit Settings(QObject* parent = 0)
+ : QSettings(parent)
+ {}
#else
- using QSettings::QSettings;
+ using QSettings::QSettings;
#endif
- Q_INVOKABLE void setValue(const QString& key, const QVariant& value);
- Q_INVOKABLE QVariant value(const QString& key,
- const QVariant& defaultValue = {}) const;
+ Q_INVOKABLE void setValue(const QString& key, const QVariant& value);
+ Q_INVOKABLE QVariant value(const QString& key,
+ const QVariant& defaultValue = {}) const;
+
+ template <typename T>
+ T get(const QString& key, const T& defaultValue = {}) const
+ {
+ const auto qv = value(key, QVariant());
+ return qv.isValid() && qv.canConvert<T>() ? qv.value<T>() : defaultValue;
+ }
+
+ Q_INVOKABLE bool contains(const QString& key) const;
+ Q_INVOKABLE QStringList childGroups() const;
- template <typename T>
- T get(const QString& key, const T& defaultValue = {}) const
- {
- const auto qv = value(key, QVariant());
- return qv.isValid() && qv.canConvert<T>() ? qv.value<T>()
- : defaultValue;
- }
+private:
+ static QString legacyOrganizationName;
+ static QString legacyApplicationName;
- Q_INVOKABLE bool contains(const QString& key) const;
- Q_INVOKABLE QStringList childGroups() const;
+protected:
+ QSettings legacySettings { legacyOrganizationName, legacyApplicationName };
+};
- private:
- static QString legacyOrganizationName;
- static QString legacyApplicationName;
+class SettingsGroup : public Settings
+{
+public:
+ template <typename... ArgTs>
+ explicit SettingsGroup(QString path, ArgTs&&... qsettingsArgs)
+ : Settings(std::forward<ArgTs>(qsettingsArgs)...)
+ , groupPath(std::move(path))
+ {}
- protected:
- QSettings legacySettings { legacyOrganizationName,
- legacyApplicationName };
- };
+ Q_INVOKABLE bool contains(const QString& key) const;
+ Q_INVOKABLE QVariant value(const QString& key,
+ const QVariant& defaultValue = {}) const;
- class SettingsGroup : public Settings
+ template <typename T>
+ T get(const QString& key, const T& defaultValue = {}) const
{
- public:
- template <typename... ArgTs>
- explicit SettingsGroup(QString path, ArgTs&&... qsettingsArgs)
- : Settings(std::forward<ArgTs>(qsettingsArgs)...),
- groupPath(std::move(path))
- {
- }
-
- Q_INVOKABLE bool contains(const QString& key) const;
- Q_INVOKABLE QVariant value(const QString& key,
- const QVariant& defaultValue = {}) const;
-
- template <typename T>
- T get(const QString& key, const T& defaultValue = {}) const
- {
- const auto qv = value(key, QVariant());
- return qv.isValid() && qv.canConvert<T>() ? qv.value<T>()
- : defaultValue;
- }
-
- Q_INVOKABLE QString group() const;
- Q_INVOKABLE QStringList childGroups() const;
- Q_INVOKABLE void setValue(const QString& key, const QVariant& value);
-
- Q_INVOKABLE void remove(const QString& key);
-
- private:
- QString groupPath;
- };
-
-#define QMC_DECLARE_SETTING(type, propname, setter) \
- Q_PROPERTY(type propname READ propname WRITE setter) \
- public: \
- type propname() const; \
- void setter(type newValue); \
- \
- private:
-
-#define QMC_DEFINE_SETTING(classname, type, propname, qsettingname, \
- defaultValue, setter) \
- type classname::propname() const \
- { \
- return get<type>(QStringLiteral(qsettingname), defaultValue); \
- } \
- \
- void classname::setter(type newValue) \
- { \
- setValue(QStringLiteral(qsettingname), newValue); \
+ const auto qv = value(key, QVariant());
+ return qv.isValid() && qv.canConvert<T>() ? qv.value<T>() : defaultValue;
}
- class AccountSettings : public SettingsGroup
- {
- Q_OBJECT
- Q_PROPERTY(QString userId READ userId CONSTANT)
- QMC_DECLARE_SETTING(QString, deviceId, setDeviceId)
- QMC_DECLARE_SETTING(QString, deviceName, setDeviceName)
- QMC_DECLARE_SETTING(bool, keepLoggedIn, setKeepLoggedIn)
- /** \deprecated \sa setAccessToken */
- Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken)
- public:
- template <typename... ArgTs>
- explicit AccountSettings(const QString& accountId,
- ArgTs... qsettingsArgs)
- : SettingsGroup("Accounts/" + accountId, qsettingsArgs...)
- {
- }
-
- QString userId() const;
-
- QUrl homeserver() const;
- void setHomeserver(const QUrl& url);
-
- /** \deprecated \sa setToken */
- QString accessToken() const;
- /** \deprecated Storing accessToken in QSettings is unsafe,
- * see QMatrixClient/Quaternion#181 */
- void setAccessToken(const QString& accessToken);
- Q_INVOKABLE void clearAccessToken();
- };
+ Q_INVOKABLE QString group() const;
+ Q_INVOKABLE QStringList childGroups() const;
+ Q_INVOKABLE void setValue(const QString& key, const QVariant& value);
+
+ Q_INVOKABLE void remove(const QString& key);
+
+private:
+ QString groupPath;
+};
+
+#define QMC_DECLARE_SETTING(type, propname, setter) \
+ Q_PROPERTY(type propname READ propname WRITE setter) \
+public: \
+ type propname() const; \
+ void setter(type newValue); \
+ \
+private:
+
+#define QMC_DEFINE_SETTING(classname, type, propname, qsettingname, \
+ defaultValue, setter) \
+ type classname::propname() const \
+ { \
+ return get<type>(QStringLiteral(qsettingname), defaultValue); \
+ } \
+ \
+ void classname::setter(type newValue) \
+ { \
+ setValue(QStringLiteral(qsettingname), std::move(newValue)); \
+ }
+
+class AccountSettings : public SettingsGroup
+{
+ Q_OBJECT
+ Q_PROPERTY(QString userId READ userId CONSTANT)
+ QMC_DECLARE_SETTING(QString, deviceId, setDeviceId)
+ QMC_DECLARE_SETTING(QString, deviceName, setDeviceName)
+ QMC_DECLARE_SETTING(bool, keepLoggedIn, setKeepLoggedIn)
+ /** \deprecated \sa setAccessToken */
+ Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken)
+public:
+ template <typename... ArgTs>
+ explicit AccountSettings(const QString& accountId, ArgTs... qsettingsArgs)
+ : SettingsGroup("Accounts/" + accountId, qsettingsArgs...)
+ {}
+
+ QString userId() const;
+
+ QUrl homeserver() const;
+ void setHomeserver(const QUrl& url);
+
+ /** \deprecated \sa setToken */
+ QString accessToken() const;
+ /** \deprecated Storing accessToken in QSettings is unsafe,
+ * see QMatrixClient/Quaternion#181 */
+ void setAccessToken(const QString& accessToken);
+ Q_INVOKABLE void clearAccessToken();
+};
} // namespace QMatrixClient
diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp
index d8fb7bb6..0c39b438 100644
--- a/lib/syncdata.cpp
+++ b/lib/syncdata.cpp
@@ -26,20 +26,20 @@
using namespace QMatrixClient;
const QString SyncRoomData::UnreadCountKey =
- QStringLiteral("x-qmatrixclient.unread_count");
+ QStringLiteral("x-qmatrixclient.unread_count");
bool RoomSummary::isEmpty() const
{
return joinedMemberCount.omitted() && invitedMemberCount.omitted()
- && heroes.omitted();
+ && heroes.omitted();
}
bool RoomSummary::merge(const RoomSummary& other)
{
// Using bitwise OR to prevent computation shortcut.
return joinedMemberCount.merge(other.joinedMemberCount)
- | invitedMemberCount.merge(other.invitedMemberCount)
- | heroes.merge(other.heroes);
+ | invitedMemberCount.merge(other.invitedMemberCount)
+ | heroes.merge(other.heroes);
}
QDebug QMatrixClient::operator<<(QDebug dbg, const RoomSummary& rs)
@@ -71,24 +71,23 @@ void JsonObjectConverter<RoomSummary>::fillFrom(const QJsonObject& jo,
{
fromJson(jo["m.joined_member_count"_ls], rs.joinedMemberCount);
fromJson(jo["m.invited_member_count"_ls], rs.invitedMemberCount);
- fromJson(jo["m.heroes"], rs.heroes);
+ fromJson(jo["m.heroes"_ls], rs.heroes);
}
template <typename EventsArrayT, typename StrT>
inline EventsArrayT load(const QJsonObject& batches, StrT keyName)
{
- return fromJson<EventsArrayT>(
- batches[keyName].toObject().value("events"_ls));
+ return fromJson<EventsArrayT>(batches[keyName].toObject().value("events"_ls));
}
SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_,
const QJsonObject& room_)
- : roomId(roomId_),
- joinState(joinState_),
- summary(fromJson<RoomSummary>(room_["summary"])),
- state(load<StateEvents>(room_,
- joinState == JoinState::Invite ? "invite_state"_ls
- : "state"_ls))
+ : roomId(roomId_)
+ , joinState(joinState_)
+ , summary(fromJson<RoomSummary>(room_["summary"_ls]))
+ , state(load<StateEvents>(room_, joinState == JoinState::Invite
+ ? "invite_state"_ls
+ : "state"_ls))
{
switch (joinState) {
case JoinState::Join:
@@ -122,7 +121,7 @@ SyncData::SyncData(const QString& cacheFileName)
auto json = loadJson(cacheFileName);
auto requiredVersion = std::get<0>(cacheVersion());
auto actualVersion =
- json.value("cache_version").toObject().value("major").toInt();
+ json.value("cache_version"_ls).toObject().value("major"_ls).toInt();
if (actualVersion == requiredVersion)
parseJson(json, cacheFileInfo.absolutePath() + '/');
else
@@ -159,10 +158,10 @@ QJsonObject SyncData::loadJson(const QString& fileName)
}
auto data = roomFile.readAll();
- const auto json =
- (data.startsWith('{') ? QJsonDocument::fromJson(data)
- : QJsonDocument::fromBinaryData(data))
- .object();
+ const auto json = (data.startsWith('{')
+ ? QJsonDocument::fromJson(data)
+ : QJsonDocument::fromBinaryData(data))
+ .object();
if (json.isEmpty()) {
qCWarning(MAIN) << "State cache in" << fileName
<< "is broken or empty, discarding";
@@ -189,7 +188,8 @@ void SyncData::parseJson(const QJsonObject& json, const QString& baseDir)
// We have a Qt container on the right and an STL one on the left
roomData.reserve(static_cast<size_t>(rs.size()));
for (auto roomIt = rs.begin(); roomIt != rs.end(); ++roomIt) {
- auto roomJson = roomIt->isObject()
+ auto roomJson =
+ roomIt->isObject()
? roomIt->toObject()
: loadJson(baseDir + fileNameForRoom(roomIt.key()));
if (roomJson.isEmpty()) {
@@ -199,7 +199,7 @@ void SyncData::parseJson(const QJsonObject& json, const QString& baseDir)
roomData.emplace_back(roomIt.key(), JoinState(ii), roomJson);
const auto& r = roomData.back();
totalEvents += r.state.size() + r.ephemeral.size()
- + r.accountData.size() + r.timeline.size();
+ + r.accountData.size() + r.timeline.size();
}
totalRooms += rs.size();
}
diff --git a/lib/syncdata.h b/lib/syncdata.h
index 139af130..49df8db6 100644
--- a/lib/syncdata.h
+++ b/lib/syncdata.h
@@ -18,97 +18,102 @@
#pragma once
-#include "events/stateevent.h"
#include "joinstate.h"
-namespace QMatrixClient {
- /// Room summary, as defined in MSC688
- /**
- * Every member of this structure is an Omittable; as per the MSC, only
- * changed values are sent from the server so if nothing is in the payload
- * the respective member will be omitted. In particular, `heroes.omitted()`
- * means that nothing has come from the server; heroes.value().isEmpty()
- * means a peculiar case of a room with the only member - the current user.
+#include "events/stateevent.h"
+
+namespace QMatrixClient
+{
+/// Room summary, as defined in MSC688
+/**
+ * Every member of this structure is an Omittable; as per the MSC, only
+ * changed values are sent from the server so if nothing is in the payload
+ * the respective member will be omitted. In particular, `heroes.omitted()`
+ * means that nothing has come from the server; heroes.value().isEmpty()
+ * means a peculiar case of a room with the only member - the current user.
+ */
+struct RoomSummary
+{
+ Omittable<int> joinedMemberCount;
+ Omittable<int> invitedMemberCount;
+ Omittable<QStringList> heroes; //< mxids of users to take part in the room
+ //name
+
+ bool isEmpty() const;
+ /// Merge the contents of another RoomSummary object into this one
+ /// \return true, if the current object has changed; false otherwise
+ bool merge(const RoomSummary& other);
+
+ friend QDebug operator<<(QDebug dbg, const RoomSummary& rs);
+};
+
+template <>
+struct JsonObjectConverter<RoomSummary>
+{
+ static void dumpTo(QJsonObject& jo, const RoomSummary& rs);
+ static void fillFrom(const QJsonObject& jo, RoomSummary& rs);
+};
+
+class SyncRoomData
+{
+public:
+ QString roomId;
+ JoinState joinState;
+ RoomSummary summary;
+ StateEvents state;
+ RoomEvents timeline;
+ Events ephemeral;
+ Events accountData;
+
+ bool timelineLimited;
+ QString timelinePrevBatch;
+ int unreadCount;
+ int highlightCount;
+ int notificationCount;
+
+ SyncRoomData(const QString& roomId, JoinState joinState_,
+ const QJsonObject& room_);
+ SyncRoomData(SyncRoomData&&) = default;
+ SyncRoomData& operator=(SyncRoomData&&) = default;
+
+ static const QString UnreadCountKey;
+};
+
+// QVector cannot work with non-copiable objects, std::vector can.
+using SyncDataList = std::vector<SyncRoomData>;
+
+class SyncData
+{
+public:
+ SyncData() = default;
+ explicit SyncData(const QString& cacheFileName);
+ /** Parse sync response into room events
+ * \param json response from /sync or a room state cache
+ * \return the list of rooms with missing cache files; always
+ * empty when parsing response from /sync
*/
- struct RoomSummary {
- Omittable<int> joinedMemberCount;
- Omittable<int> invitedMemberCount;
- Omittable<QStringList>
- heroes; //< mxids of users to take part in the room name
-
- bool isEmpty() const;
- /// Merge the contents of another RoomSummary object into this one
- /// \return true, if the current object has changed; false otherwise
- bool merge(const RoomSummary& other);
-
- friend QDebug operator<<(QDebug dbg, const RoomSummary& rs);
- };
-
- template <> struct JsonObjectConverter<RoomSummary> {
- static void dumpTo(QJsonObject& jo, const RoomSummary& rs);
- static void fillFrom(const QJsonObject& jo, RoomSummary& rs);
- };
-
- class SyncRoomData
- {
- public:
- QString roomId;
- JoinState joinState;
- RoomSummary summary;
- StateEvents state;
- RoomEvents timeline;
- Events ephemeral;
- Events accountData;
-
- bool timelineLimited;
- QString timelinePrevBatch;
- int unreadCount;
- int highlightCount;
- int notificationCount;
-
- SyncRoomData(const QString& roomId, JoinState joinState_,
- const QJsonObject& room_);
- SyncRoomData(SyncRoomData&&) = default;
- SyncRoomData& operator=(SyncRoomData&&) = default;
-
- static const QString UnreadCountKey;
- };
-
- // QVector cannot work with non-copiable objects, std::vector can.
- using SyncDataList = std::vector<SyncRoomData>;
-
- class SyncData
- {
- public:
- SyncData() = default;
- explicit SyncData(const QString& cacheFileName);
- /** Parse sync response into room events
- * \param json response from /sync or a room state cache
- * \return the list of rooms with missing cache files; always
- * empty when parsing response from /sync
- */
- void parseJson(const QJsonObject& json, const QString& baseDir = {});
-
- Events&& takePresenceData();
- Events&& takeAccountData();
- Events&& takeToDeviceEvents();
- SyncDataList&& takeRoomData();
-
- QString nextBatch() const { return nextBatch_; }
-
- QStringList unresolvedRooms() const { return unresolvedRoomIds; }
-
- static std::pair<int, int> cacheVersion() { return { 10, 0 }; }
- static QString fileNameForRoom(QString roomId);
-
- private:
- QString nextBatch_;
- Events presenceData;
- Events accountData;
- Events toDeviceEvents;
- SyncDataList roomData;
- QStringList unresolvedRoomIds;
-
- static QJsonObject loadJson(const QString& fileName);
- };
+ void parseJson(const QJsonObject& json, const QString& baseDir = {});
+
+ Events&& takePresenceData();
+ Events&& takeAccountData();
+ Events&& takeToDeviceEvents();
+ SyncDataList&& takeRoomData();
+
+ QString nextBatch() const { return nextBatch_; }
+
+ QStringList unresolvedRooms() const { return unresolvedRoomIds; }
+
+ static std::pair<int, int> cacheVersion() { return { 10, 0 }; }
+ static QString fileNameForRoom(QString roomId);
+
+private:
+ QString nextBatch_;
+ Events presenceData;
+ Events accountData;
+ Events toDeviceEvents;
+ SyncDataList roomData;
+ QStringList unresolvedRoomIds;
+
+ static QJsonObject loadJson(const QString& fileName);
+};
} // namespace QMatrixClient
diff --git a/lib/user.cpp b/lib/user.cpp
index 43792e74..8adb1dae 100644
--- a/lib/user.cpp
+++ b/lib/user.cpp
@@ -20,18 +20,22 @@
#include "avatar.h"
#include "connection.h"
+#include "room.h"
+
#include "csapi/content-repo.h"
#include "csapi/profile.h"
#include "csapi/room_state.h"
+
#include "events/event.h"
#include "events/roommemberevent.h"
-#include "room.h"
+#include <QtCore/QCryptographicHash>
#include <QtCore/QElapsedTimer>
#include <QtCore/QPointer>
#include <QtCore/QRegularExpression>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
+#include <QtCore/QtEndian>
#include <functional>
@@ -41,23 +45,39 @@ using std::move;
class User::Private
{
- public:
+public:
static Avatar makeAvatar(QUrl url) { return Avatar(move(url)); }
- Private(QString userId, Connection* connection)
- : userId(move(userId)), connection(connection)
+ qreal makeHueF()
{
+ Q_ASSERT(!userId.isEmpty());
+ QByteArray hash = QCryptographicHash::hash(userId.toUtf8(),
+ QCryptographicHash::Sha1);
+ QDataStream dataStream(qToLittleEndian(hash).left(2));
+ dataStream.setByteOrder(QDataStream::LittleEndian);
+ quint16 hashValue;
+ dataStream >> hashValue;
+ const auto hueF = qreal(hashValue) / std::numeric_limits<quint16>::max();
+ Q_ASSERT((0 <= hueF) && (hueF <= 1));
+ return hueF;
}
+ Private(QString userId, Connection* connection)
+ : userId(move(userId))
+ , connection(connection)
+ , hueF(makeHueF())
+ {}
+
QString userId;
Connection* connection;
QString bridged;
QString mostUsedName;
QMultiHash<QString, const Room*> otherNames;
+ qreal hueF;
Avatar mostUsedAvatar { makeAvatar({}) };
std::vector<Avatar> otherAvatars;
- auto otherAvatar(QUrl url)
+ auto otherAvatar(const QUrl& url)
{
return std::find_if(otherAvatars.begin(), otherAvatars.end(),
[&url](const auto& av) { return av.url() == url; });
@@ -67,10 +87,9 @@ class User::Private
mutable int totalRooms = 0;
QString nameForRoom(const Room* r, const QString& hint = {}) const;
- void setNameForRoom(const Room* r, QString newName, QString oldName);
+ void setNameForRoom(const Room* r, QString newName, const QString& oldName);
QUrl avatarUrlForRoom(const Room* r, const QUrl& hint = {}) const;
- void setAvatarForRoom(const Room* r, const QUrl& newUrl,
- const QUrl& oldUrl);
+ void setAvatarForRoom(const Room* r, const QUrl& newUrl, const QUrl& oldUrl);
void setAvatarOnServer(QString contentUri, User* q);
};
@@ -78,7 +97,7 @@ class User::Private
QString User::Private::nameForRoom(const Room* r, const QString& hint) const
{
// If the hint is accurate, this function is O(1) instead of O(n)
- if (hint == mostUsedName || otherNames.contains(hint, r))
+ if (!hint.isNull() && (hint == mostUsedName || otherNames.contains(hint, r)))
return hint;
return otherNames.key(r, mostUsedName);
}
@@ -86,7 +105,7 @@ QString User::Private::nameForRoom(const Room* r, const QString& hint) const
static constexpr int MIN_JOINED_ROOMS_TO_LOG = 20;
void User::Private::setNameForRoom(const Room* r, QString newName,
- QString oldName)
+ const QString& oldName)
{
Q_ASSERT(oldName != newName);
Q_ASSERT(oldName == mostUsedName || otherNames.contains(oldName, r));
@@ -103,14 +122,14 @@ void User::Private::setNameForRoom(const Room* r, QString newName,
Q_ASSERT(totalRooms > 1);
QElapsedTimer et;
if (totalRooms > MIN_JOINED_ROOMS_TO_LOG) {
- qCDebug(MAIN)
- << "Switching the most used name of user" << userId
- << "from" << mostUsedName << "to" << newName;
+ qCDebug(MAIN) << "Switching the most used name of user" << userId
+ << "from" << mostUsedName << "to" << newName;
qCDebug(MAIN) << "The user is in" << totalRooms << "rooms";
et.start();
}
- for (auto* r1 : connection->roomMap())
+ const auto& roomMap = connection->roomMap();
+ for (auto* r1 : roomMap)
if (nameForRoom(r1) == mostUsedName)
otherNames.insert(mostUsedName, r1);
@@ -152,21 +171,21 @@ void User::Private::setAvatarForRoom(const Room* r, const QUrl& newUrl,
}
if (newUrl != mostUsedAvatar.url()) {
// Check if the new avatar is about to become most used.
- if (avatarsToRooms.count(newUrl)
- >= totalRooms - avatarsToRooms.size()) {
+ if (avatarsToRooms.count(newUrl) >= totalRooms - avatarsToRooms.size()) {
QElapsedTimer et;
if (totalRooms > MIN_JOINED_ROOMS_TO_LOG) {
qCDebug(MAIN)
- << "Switching the most used avatar of user" << userId
- << "from" << mostUsedAvatar.url().toDisplayString()
- << "to" << newUrl.toDisplayString();
+ << "Switching the most used avatar of user" << userId
+ << "from" << mostUsedAvatar.url().toDisplayString() << "to"
+ << newUrl.toDisplayString();
et.start();
}
avatarsToRooms.remove(newUrl);
auto nextMostUsedIt = otherAvatar(newUrl);
Q_ASSERT(nextMostUsedIt != otherAvatars.end());
std::swap(mostUsedAvatar, *nextMostUsedIt);
- for (const auto* r1 : connection->roomMap())
+ const auto& roomMap = connection->roomMap();
+ for (const auto* r1 : roomMap)
if (avatarUrlForRoom(r1) == nextMostUsedIt->url())
avatarsToRooms.insert(nextMostUsedIt->url(), r1);
@@ -181,7 +200,8 @@ void User::Private::setAvatarForRoom(const Room* r, const QUrl& newUrl,
}
User::User(QString userId, Connection* connection)
- : QObject(connection), d(new Private(move(userId), connection))
+ : QObject(connection)
+ , d(new Private(move(userId), connection))
{
setObjectName(userId);
}
@@ -205,6 +225,8 @@ bool User::isGuest() const
return *it == ':';
}
+int User::hue() const { return int(hueF() * 359); }
+
QString User::name(const Room* room) const { return d->nameForRoom(room); }
QString User::rawName(const Room* room) const
@@ -245,8 +267,9 @@ void User::updateAvatarUrl(const QUrl& newUrl, const QUrl& oldUrl,
void User::rename(const QString& newName)
{
- auto job = connection()->callApi<SetDisplayNameJob>(id(), newName);
- connect(job, &BaseJob::success, this, [=] { updateName(newName); });
+ const auto actualNewName = sanitized(newName);
+ connect(connection()->callApi<SetDisplayNameJob>(id(), actualNewName),
+ &BaseJob::success, this, [=] { updateName(actualNewName); });
}
void User::rename(const QString& newName, const Room* r)
@@ -259,24 +282,25 @@ void User::rename(const QString& newName, const Room* r)
}
Q_ASSERT_X(r->memberJoinState(this) == JoinState::Join, __FUNCTION__,
"Attempt to rename a user that's not a room member");
+ const auto actualNewName = sanitized(newName);
MemberEventContent evtC;
- evtC.displayName = newName;
- auto job = r->setMemberState(id(), RoomMemberEvent(move(evtC)));
- connect(job, &BaseJob::success, this, [=] { updateName(newName, r); });
+ evtC.displayName = actualNewName;
+ connect(r->setMemberState(id(), RoomMemberEvent(move(evtC))),
+ &BaseJob::success, this, [=] { updateName(actualNewName, r); });
}
bool User::setAvatar(const QString& fileName)
{
- return avatarObject().upload(
- connection(), fileName,
- std::bind(&Private::setAvatarOnServer, d.data(), _1, this));
+ return avatarObject().upload(connection(), fileName,
+ std::bind(&Private::setAvatarOnServer,
+ d.data(), _1, this));
}
bool User::setAvatar(QIODevice* source)
{
- return avatarObject().upload(
- connection(), source,
- std::bind(&Private::setAvatarOnServer, d.data(), _1, this));
+ return avatarObject().upload(connection(), source,
+ std::bind(&Private::setAvatarOnServer,
+ d.data(), _1, this));
}
void User::requestDirectChat() { connection()->requestDirectChat(this); }
@@ -346,19 +370,18 @@ QUrl User::avatarUrl(const Room* room) const
return avatarObject(room).url();
}
-void User::processEvent(const RoomMemberEvent& event, const Room* room)
+void User::processEvent(const RoomMemberEvent& event, const Room* room,
+ bool firstMention)
{
Q_ASSERT(room);
+
+ if (firstMention)
+ ++d->totalRooms;
+
if (event.membership() != MembershipType::Invite
&& event.membership() != MembershipType::Join)
return;
- auto aboutToEnter = room->memberJoinState(this) == JoinState::Leave
- && (event.membership() == MembershipType::Join
- || event.membership() == MembershipType::Invite);
- if (aboutToEnter)
- ++d->totalRooms;
-
auto newName = event.displayName();
// `bridged` value uses the same notification signal as the name;
// it is assumed that first setting of the bridge occurs together with
@@ -366,29 +389,31 @@ void User::processEvent(const RoomMemberEvent& event, const Room* room)
// exceptionally rare (the only reasonable case being that the bridge
// changes the naming convention). For the same reason room-specific
// bridge tags are not supported at all.
- QRegularExpression reSuffix(" \\((IRC|Gitter|Telegram)\\)$");
+ QRegularExpression reSuffix(
+ QStringLiteral(" \\((IRC|Gitter|Telegram)\\)$"));
auto match = reSuffix.match(newName);
if (match.hasMatch()) {
if (d->bridged != match.captured(1)) {
if (!d->bridged.isEmpty())
qCWarning(MAIN)
- << "Bridge for user" << id() << "changed:" << d->bridged
- << "->" << match.captured(1);
+ << "Bridge for user" << id() << "changed:" << d->bridged
+ << "->" << match.captured(1);
d->bridged = match.captured(1);
}
newName.truncate(match.capturedStart(0));
}
if (event.prevContent()) {
// FIXME: the hint doesn't work for bridged users
- auto oldNameHint =
- d->nameForRoom(room, event.prevContent()->displayName);
+ auto oldNameHint = d->nameForRoom(room,
+ event.prevContent()->displayName);
updateName(newName, oldNameHint, room);
- updateAvatarUrl(
- event.avatarUrl(),
- d->avatarUrlForRoom(room, event.prevContent()->avatarUrl),
- room);
+ updateAvatarUrl(event.avatarUrl(),
+ d->avatarUrlForRoom(room, event.prevContent()->avatarUrl),
+ room);
} else {
updateName(newName, room);
updateAvatarUrl(event.avatarUrl(), d->avatarUrlForRoom(room), room);
}
}
+
+qreal User::hueF() const { return d->hueF; }
diff --git a/lib/user.h b/lib/user.h
index c174314e..f4d7cff3 100644
--- a/lib/user.h
+++ b/lib/user.h
@@ -19,135 +19,148 @@
#pragma once
#include "avatar.h"
+
#include <QtCore/QObject>
#include <QtCore/QString>
-namespace QMatrixClient {
- class Connection;
- class Room;
- class RoomMemberEvent;
-
- class User : public QObject
- {
- Q_OBJECT
- Q_PROPERTY(QString id READ id CONSTANT)
- Q_PROPERTY(bool isGuest READ isGuest CONSTANT)
- Q_PROPERTY(QString name READ name NOTIFY nameChanged)
- Q_PROPERTY(QString displayName READ displayname NOTIFY nameChanged
- STORED false)
- Q_PROPERTY(
- QString fullName READ fullName NOTIFY nameChanged STORED false)
- Q_PROPERTY(
- QString bridgeName READ bridged NOTIFY nameChanged STORED false)
- Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
- STORED false)
- Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
- public:
- User(QString userId, Connection* connection);
- ~User() override;
-
- Connection* connection() const;
-
- /** Get unique stable user id
- * User id is generated by the server and is not changed ever.
- */
- QString id() const;
-
- /** Get the name chosen by the user
- * 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
- */
- 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
- */
- 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.
- * When \p room is non-null, this call is equivalent to
- * Room::roomMembername invocation for the user (i.e. the user's
- * disambiguated room-specific name is returned).
- * \sa name, id, fullName, Room::roomMembername
- */
- QString displayname(const Room* room = nullptr) const;
-
- /** Get user name and id in one string
- * The constructed string follows the format 'name (id)'
- * which the spec recommends for users disambiguation in
- * a room context and in other places.
- * \sa displayName, Room::roomMembername
- */
- QString fullName(const Room* room = nullptr) const;
-
- /**
- * Returns the name of bridge the user is connected from or empty.
- */
- 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
- * may not work with non-Synapse servers.
- */
- bool isGuest() const;
-
- const Avatar& avatarObject(const Room* room = nullptr) const;
- Q_INVOKABLE QImage avatar(int dimension, const Room* room = nullptr);
- Q_INVOKABLE QImage avatar(int requestedWidth, int requestedHeight,
- const Room* room = nullptr);
- QImage avatar(int width, int height, const Room* room,
- const Avatar::get_callback_t& callback);
-
- QString avatarMediaId(const Room* room = nullptr) const;
- QUrl avatarUrl(const Room* room = nullptr) const;
-
- void processEvent(const RoomMemberEvent& event, const Room* r);
-
- public slots:
- /** Set a new name in the global user profile */
- void rename(const QString& newName);
- /** Set a new name for the user in one room */
- void rename(const QString& newName, const Room* r);
- /** Upload the file and use it as an avatar */
- bool setAvatar(const QString& fileName);
- /** Upload contents of the QIODevice and set that as an avatar */
- bool setAvatar(QIODevice* source);
- /** Create or find a direct chat with this user
- * The resulting chat is returned asynchronously via
- * Connection::directChatAvailable()
- */
- void requestDirectChat();
- /** Add the user to the ignore list */
- void ignore();
- /** Remove the user from the ignore list */
- void unmarkIgnore();
- /** Check whether the user is in ignore list */
- bool isIgnored() const;
-
- signals:
- void nameAboutToChange(QString newName, QString oldName,
- const Room* roomContext);
- void nameChanged(QString newName, QString oldName,
- const Room* roomContext);
- void avatarChanged(User* user, const Room* roomContext);
-
- private slots:
- void updateName(const QString& newName, const Room* room = nullptr);
- void updateName(const QString& newName, const QString& oldName,
- const Room* room = nullptr);
- void updateAvatarUrl(const QUrl& newUrl, const QUrl& oldUrl,
- const Room* room = nullptr);
-
- private:
- class Private;
- QScopedPointer<Private> d;
- };
-}
+namespace QMatrixClient
+{
+class Connection;
+class Room;
+class RoomMemberEvent;
+
+class User : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString id READ id CONSTANT)
+ Q_PROPERTY(bool isGuest READ isGuest CONSTANT)
+ Q_PROPERTY(int hue READ hue CONSTANT)
+ Q_PROPERTY(qreal hueF READ hueF CONSTANT)
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
+ Q_PROPERTY(QString displayName READ displayname NOTIFY nameChanged STORED false)
+ Q_PROPERTY(QString fullName READ fullName NOTIFY nameChanged STORED false)
+ Q_PROPERTY(QString bridgeName READ bridged NOTIFY nameChanged STORED false)
+ Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
+ STORED false)
+ Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
+public:
+ User(QString userId, Connection* connection);
+ ~User() override;
+
+ Connection* connection() const;
+
+ /** Get unique stable user id
+ * User id is generated by the server and is not changed ever.
+ */
+ QString id() const;
+
+ /** Get the name chosen by the user
+ * 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
+ */
+ 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
+ */
+ 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.
+ * When \p room is non-null, this call is equivalent to
+ * Room::roomMembername invocation for the user (i.e. the user's
+ * disambiguated room-specific name is returned).
+ * \sa name, id, fullName, Room::roomMembername
+ */
+ QString displayname(const Room* room = nullptr) const;
+
+ /** Get user name and id in one string
+ * The constructed string follows the format 'name (id)'
+ * which the spec recommends for users disambiguation in
+ * a room context and in other places.
+ * \sa displayName, Room::roomMembername
+ */
+ QString fullName(const Room* room = nullptr) const;
+
+ /**
+ * Returns the name of bridge the user is connected from or empty.
+ */
+ 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
+ * may not work with non-Synapse servers.
+ */
+ bool isGuest() const;
+
+ /** Hue color component of this user based on id.
+ * The implementation is based on XEP-0392:
+ * https://xmpp.org/extensions/xep-0392.html
+ * Naming and ranges are the same as QColor's hue methods:
+ * https://doc.qt.io/qt-5/qcolor.html#integer-vs-floating-point-precision
+ */
+ int hue() const;
+ qreal hueF() const;
+
+ const Avatar& avatarObject(const Room* room = nullptr) const;
+ Q_INVOKABLE QImage avatar(int dimension, const Room* room = nullptr);
+ Q_INVOKABLE QImage avatar(int requestedWidth, int requestedHeight,
+ const Room* room = nullptr);
+ QImage avatar(int width, int height, const Room* room,
+ const Avatar::get_callback_t& callback);
+
+ QString avatarMediaId(const Room* room = nullptr) const;
+ QUrl avatarUrl(const Room* room = nullptr) const;
+
+ /// This method is for internal use and should not be called
+ /// from client code
+ // FIXME: Move it away to private in lib 0.6
+ void processEvent(const RoomMemberEvent& event, const Room* r,
+ bool firstMention);
+
+public slots:
+ /** Set a new name in the global user profile */
+ void rename(const QString& newName);
+ /** Set a new name for the user in one room */
+ void rename(const QString& newName, const Room* r);
+ /** Upload the file and use it as an avatar */
+ bool setAvatar(const QString& fileName);
+ /** Upload contents of the QIODevice and set that as an avatar */
+ bool setAvatar(QIODevice* source);
+ /** Create or find a direct chat with this user
+ * The resulting chat is returned asynchronously via
+ * Connection::directChatAvailable()
+ */
+ void requestDirectChat();
+ /** Add the user to the ignore list */
+ void ignore();
+ /** Remove the user from the ignore list */
+ void unmarkIgnore();
+ /** Check whether the user is in ignore list */
+ bool isIgnored() const;
+
+signals:
+ void nameAboutToChange(QString newName, QString oldName,
+ const Room* roomContext);
+ void nameChanged(QString newName, QString oldName, const Room* roomContext);
+ void avatarChanged(User* user, const Room* roomContext);
+
+private slots:
+ void updateName(const QString& newName, const Room* room = nullptr);
+ void updateName(const QString& newName, const QString& oldName,
+ const Room* room = nullptr);
+ void updateAvatarUrl(const QUrl& newUrl, const QUrl& oldUrl,
+ const Room* room = nullptr);
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::User*)
diff --git a/lib/util.cpp b/lib/util.cpp
index a7c745d4..be2665c5 100644
--- a/lib/util.cpp
+++ b/lib/util.cpp
@@ -23,63 +23,73 @@
#include <QtCore/QStandardPaths>
#include <QtCore/QStringBuilder>
-static const auto RegExpOptions = QRegularExpression::CaseInsensitiveOption
- | QRegularExpression::OptimizeOnFirstUsageOption
- | QRegularExpression::UseUnicodePropertiesOption;
+static const auto RegExpOptions =
+ QRegularExpression::CaseInsensitiveOption
+ | QRegularExpression::OptimizeOnFirstUsageOption
+ | QRegularExpression::UseUnicodePropertiesOption;
// Converts all that looks like a URL into HTML links
-static void linkifyUrls(QString& htmlEscapedText)
+void QMatrixClient::linkifyUrls(QString& htmlEscapedText)
{
+ // Note: outer parentheses are a part of C++ raw string delimiters, not of
+ // the regex (see http://en.cppreference.com/w/cpp/language/string_literal).
+ // Note2: the next-outer parentheses are \N in the replacement.
+
+ // generic url:
// regexp is originally taken from Konsole (https://github.com/KDE/konsole)
- // full url:
// protocolname:// or www. followed by anything other than whitespaces,
// <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, ), :,
// comma or dot
- // Note: outer parentheses are a part of C++ raw string delimiters, not of
- // the regex (see http://en.cppreference.com/w/cpp/language/string_literal).
- // Note2: yet another pair of outer parentheses are \1 in the replacement.
static const QRegularExpression FullUrlRegExp(
- QStringLiteral(
- R"(((www\.(?!\.)|(https?|ftp|magnet)://)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))"),
- RegExpOptions);
+ QStringLiteral(
+ R"(\b((www\.(?!\.)(?!(\w|\.|-)+@)|(https?|ftp|magnet)://)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))"),
+ RegExpOptions);
// email address:
// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
static const QRegularExpression EmailAddressRegExp(
- QStringLiteral(R"((mailto:)?(\b(\w|\.|-)+@(\w|\.|-)+\.\w+\b))"),
- RegExpOptions);
+ QStringLiteral(R"(\b(mailto:)?((\w|\.|-)+@(\w|\.|-)+\.\w+\b))"),
+ RegExpOptions);
// An interim liberal implementation of
// https://matrix.org/docs/spec/appendices.html#identifier-grammar
static const QRegularExpression MxIdRegExp(
- QStringLiteral(
- R"((^|[^<>/])([!#@][-a-z0-9_=/.]{1,252}:[-.a-z0-9]+))"),
- RegExpOptions);
+ QStringLiteral(
+ R"((^|[^<>/])([!#@][-a-z0-9_=/.]{1,252}:(?:\w|\.|-)+\.\w+(?::\d{1,5})?))"),
+ RegExpOptions);
- // NOTE: htmlEscapedText is already HTML-escaped! No literal <,>,&
+ // NOTE: htmlEscapedText is already HTML-escaped! No literal <,>,&,"
htmlEscapedText.replace(EmailAddressRegExp,
QStringLiteral(R"(<a href="mailto:\2">\1\2</a>)"));
htmlEscapedText.replace(FullUrlRegExp,
QStringLiteral(R"(<a href="\1">\1</a>)"));
htmlEscapedText.replace(
- MxIdRegExp,
- QStringLiteral(R"(\1<a href="https://matrix.to/#/\2">\2</a>)"));
+ MxIdRegExp,
+ QStringLiteral(R"(\1<a href="https://matrix.to/#/\2">\2</a>)"));
}
-QString QMatrixClient::prettyPrint(const QString& plainText)
+QString QMatrixClient::sanitized(const QString& plainText)
{
- auto pt = QStringLiteral("<span style='white-space:pre-wrap'>")
- + plainText.toHtmlEscaped() + QStringLiteral("</span>");
- pt.replace('\n', QStringLiteral("<br/>"));
+ auto text = plainText;
+ text.remove(QChar(0x202e)); // RLO
+ text.remove(QChar(0x202d)); // LRO
+ text.remove(QChar(0xfffc)); // Object replacement character
+ return text;
+}
+QString QMatrixClient::prettyPrint(const QString& plainText)
+{
+ auto pt = plainText.toHtmlEscaped();
linkifyUrls(pt);
- return pt;
+ pt.replace('\n', QStringLiteral("<br/>"));
+ return QStringLiteral("<span style='white-space:pre-wrap'>") + pt
+ + QStringLiteral("</span>");
}
QString QMatrixClient::cacheLocation(const QString& dirName)
{
const QString cachePath =
- QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
- % '/' % dirName % '/';
+ QStandardPaths::writableLocation(QStandardPaths::CacheLocation) % '/'
+ % dirName % '/';
QDir dir;
if (!dir.exists(cachePath))
dir.mkpath(cachePath);
@@ -89,8 +99,8 @@ QString QMatrixClient::cacheLocation(const QString& dirName)
// Tests for function_traits<>
#ifdef Q_CC_CLANG
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "OCSimplifyInspection"
+# pragma clang diagnostic push
+# pragma ide diagnostic ignored "OCSimplifyInspection"
#endif
using namespace QMatrixClient;
@@ -106,14 +116,16 @@ void f2(int, QString);
static_assert(std::is_same<fn_arg_t<decltype(f2), 1>, QString>::value,
"Test fn_arg_t<>");
-struct S {
+struct S
+{
int mf();
};
static_assert(is_callable_v<decltype(&S::mf)>, "Test member function");
static_assert(returns<int, decltype(&S::mf)>(),
"Test returns<> with member function");
-struct Fo {
+struct Fo
+{
int operator()();
};
static_assert(is_callable_v<Fo>, "Test is_callable<> with function object");
@@ -121,7 +133,8 @@ static_assert(function_traits<Fo>::arg_number == 0, "Test function object");
static_assert(std::is_same<fn_return_t<Fo>, int>::value,
"Test return type of function object");
-struct Fo1 {
+struct Fo1
+{
void operator()(int);
};
static_assert(function_traits<Fo1>::arg_number == 1, "Test function object 1");
@@ -136,10 +149,14 @@ static_assert(std::is_same<fn_return_t<decltype(l)>, int>::value,
"Test fn_return_t<> with lambda");
#endif
-template <typename T> struct fn_object {
+template <typename T>
+struct fn_object
+{
static int smf(double) { return 0; }
};
-template <> struct fn_object<QString> {
+template <>
+struct fn_object<QString>
+{
void operator()(QString);
};
static_assert(is_callable_v<fn_object<QString>>, "Test function object");
@@ -152,10 +169,14 @@ static_assert(!is_callable_v<fn_object<int>>, "Test non-function object");
// static_assert(returns<int, decltype(&fn_object<int>::smf)>(),
// "Test returns<> with static member function");
-template <typename T> QString ft(T&&);
+template <typename T>
+QString ft(T&&)
+{
+ return {};
+}
static_assert(std::is_same<fn_arg_t<decltype(ft<QString>)>, QString&&>(),
"Test function templates");
#ifdef Q_CC_CLANG
-#pragma clang diagnostic pop
+# pragma clang diagnostic pop
#endif
diff --git a/lib/util.h b/lib/util.h
index fbcafc0d..d626834c 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -21,26 +21,26 @@
#include <QtCore/QLatin1String>
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
-#include <QtCore/QDebug>
-#include <QtCore/QMetaEnum>
+# include <QtCore/QDebug>
+# include <QtCore/QMetaEnum>
#endif
#include <functional>
#include <memory>
#if __has_cpp_attribute(fallthrough)
-#define FALLTHROUGH [[fallthrough]]
+# define FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(clang::fallthrough)
-#define FALLTHROUGH [[clang::fallthrough]]
+# define FALLTHROUGH [[clang::fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
-#define FALLTHROUGH [[gnu::fallthrough]]
+# define FALLTHROUGH [[gnu::fallthrough]]
#else
-#define FALLTHROUGH // -fallthrough
+# define FALLTHROUGH // -fallthrough
#endif
// Along the lines of Q_DISABLE_COPY
-#define DISABLE_MOVE(_ClassName) \
- _ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \
+#define DISABLE_MOVE(_ClassName) \
+ _ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \
_ClassName& operator=(_ClassName&&) Q_DECL_EQ_DELETE;
#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
@@ -51,264 +51,294 @@ Q_DECL_CONSTEXPR typename std::add_const<T>::type& qAsConst(T& t) Q_DECL_NOTHROW
return t;
}
// prevent rvalue arguments:
-template <typename T> static void qAsConst(const T&&) Q_DECL_EQ_DELETE;
+template <typename T>
+static void qAsConst(const T&&) Q_DECL_EQ_DELETE;
#endif
// MSVC 2015 and older GCC's don't handle initialisation from initializer lists
// right in the absense of a constructor; MSVC 2015, notably, fails with
// "error C2440: 'return': cannot convert from 'initializer list' to '<type>'"
-#if (defined(_MSC_VER) && _MSC_VER < 1910) \
- || (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4)
-#define BROKEN_INITIALIZER_LISTS
+#if (defined(_MSC_VER) && _MSC_VER < 1910) \
+ || (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4)
+# define BROKEN_INITIALIZER_LISTS
#endif
-namespace QMatrixClient {
- // The below enables pretty-printing of enums in logs
+namespace QMatrixClient
+{
+// The below enables pretty-printing of enums in logs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
-#define REGISTER_ENUM(EnumName) Q_ENUM(EnumName)
+# define REGISTER_ENUM(EnumName) Q_ENUM(EnumName)
#else
- // Thanks to Olivier for spelling it and for making Q_ENUM to replace it:
- // https://woboq.com/blog/q_enum.html
-#define REGISTER_ENUM(EnumName) \
- Q_ENUMS(EnumName) \
- friend QDebug operator<<(QDebug dbg, EnumName val) \
- { \
- static int enumIdx = staticMetaObject.indexOfEnumerator(#EnumName); \
- return dbg << Event::staticMetaObject.enumerator(enumIdx).valueToKey( \
- int(val)); \
- }
+// Thanks to Olivier for spelling it and for making Q_ENUM to replace it:
+// https://woboq.com/blog/q_enum.html
+# define REGISTER_ENUM(EnumName) \
+ Q_ENUMS(EnumName) \
+ friend QDebug operator<<(QDebug dbg, EnumName val) \
+ { \
+ static int enumIdx = staticMetaObject.indexOfEnumerator(#EnumName); \
+ return dbg << Event::staticMetaObject.enumerator(enumIdx).valueToKey( \
+ int(val)); \
+ }
#endif
- /** static_cast<> for unique_ptr's */
- template <typename T1, typename PtrT2>
- inline auto unique_ptr_cast(PtrT2&& p)
+/** static_cast<> for unique_ptr's */
+template <typename T1, typename PtrT2>
+inline auto unique_ptr_cast(PtrT2&& p)
+{
+ return std::unique_ptr<T1>(static_cast<T1*>(p.release()));
+}
+
+struct NoneTag
+{};
+constexpr NoneTag none {};
+
+/** A crude substitute for `optional` while we're not C++17
+ *
+ * Only works with default-constructible types.
+ */
+template <typename T>
+class Omittable
+{
+ static_assert(!std::is_reference<T>::value,
+ "You cannot make an Omittable<> with a reference type");
+
+public:
+ using value_type = std::decay_t<T>;
+
+ explicit Omittable()
+ : Omittable(none)
+ {}
+ Omittable(NoneTag)
+ : _value(value_type())
+ , _omitted(true)
+ {}
+ Omittable(const value_type& val)
+ : _value(val)
+ {}
+ Omittable(value_type&& val)
+ : _value(std::move(val))
+ {}
+ Omittable<T>& operator=(const value_type& val)
{
- return std::unique_ptr<T1>(static_cast<T1*>(p.release()));
+ _value = val;
+ _omitted = false;
+ return *this;
+ }
+ Omittable<T>& operator=(value_type&& val)
+ {
+ // For some reason GCC complains about -Wmaybe-uninitialized
+ // in the context of using Omittable<bool> with converters.h;
+ // though the logic looks very much benign (GCC bug???)
+ _value = std::move(val);
+ _omitted = false;
+ return *this;
}
- struct NoneTag {
- };
- constexpr NoneTag none {};
+ bool operator==(const value_type& rhs) const
+ {
+ return !omitted() && value() == rhs;
+ }
+ friend bool operator==(const value_type& lhs,
+ const Omittable<value_type>& rhs)
+ {
+ return rhs == lhs;
+ }
+ bool operator!=(const value_type& rhs) const { return !operator==(rhs); }
+ friend bool operator!=(const value_type& lhs,
+ const Omittable<value_type>& rhs)
+ {
+ return !(rhs == lhs);
+ }
- /** A crude substitute for `optional` while we're not C++17
- *
- * Only works with default-constructible types.
- */
- template <typename T> class Omittable
+ bool omitted() const { return _omitted; }
+ const value_type& value() const
{
- static_assert(!std::is_reference<T>::value,
- "You cannot make an Omittable<> with a reference type");
-
- public:
- using value_type = std::decay_t<T>;
-
- explicit Omittable() : Omittable(none) {}
- Omittable(NoneTag) : _value(value_type()), _omitted(true) {}
- Omittable(const value_type& val) : _value(val) {}
- Omittable(value_type&& val) : _value(std::move(val)) {}
- Omittable<T>& operator=(const value_type& val)
- {
- _value = val;
- _omitted = false;
- return *this;
- }
- Omittable<T>& operator=(value_type&& val)
- {
- // For some reason GCC complains about -Wmaybe-uninitialized
- // in the context of using Omittable<bool> with converters.h;
- // though the logic looks very much benign (GCC bug???)
- _value = std::move(val);
- _omitted = false;
- return *this;
- }
+ Q_ASSERT(!_omitted);
+ return _value;
+ }
+ value_type& editValue()
+ {
+ _omitted = false;
+ return _value;
+ }
+ /// Merge the value from another Omittable
+ /// \return true if \p other is not omitted and the value of
+ /// the current Omittable was different (or omitted);
+ /// in other words, if the current Omittable has changed;
+ /// false otherwise
+ template <typename T1>
+ auto merge(const Omittable<T1>& other)
+ -> std::enable_if_t<std::is_convertible<T1, T>::value, bool>
+ {
+ if (other.omitted() || (!_omitted && _value == other.value()))
+ return false;
+ _omitted = false;
+ _value = other.value();
+ return true;
+ }
+ value_type&& release()
+ {
+ _omitted = true;
+ return std::move(_value);
+ }
- bool operator==(const value_type& rhs) const
- {
- return !omitted() && value() == rhs;
- }
- friend bool operator==(const value_type& lhs,
- const Omittable<value_type>& rhs)
- {
- return rhs == lhs;
- }
- bool operator!=(const value_type& rhs) const
- {
- return !operator==(rhs);
- }
- friend bool operator!=(const value_type& lhs,
- const Omittable<value_type>& rhs)
- {
- return !(rhs == lhs);
- }
+ const value_type* operator->() const& { return &value(); }
+ value_type* operator->() & { return &editValue(); }
+ const value_type& operator*() const& { return value(); }
+ value_type& operator*() & { return editValue(); }
- bool omitted() const { return _omitted; }
- const value_type& value() const
- {
- Q_ASSERT(!_omitted);
- return _value;
- }
- value_type& editValue()
- {
- _omitted = false;
- return _value;
- }
- /// Merge the value from another Omittable
- /// \return true if \p other is not omitted and the value of
- /// the current Omittable was different (or omitted);
- /// in other words, if the current Omittable has changed;
- /// false otherwise
- template <typename T1>
- auto merge(const Omittable<T1>& other)
- -> std::enable_if_t<std::is_convertible<T1, T>::value, bool>
- {
- if (other.omitted() || (!_omitted && _value == other.value()))
- return false;
- _omitted = false;
- _value = other.value();
- return true;
- }
- value_type&& release()
- {
- _omitted = true;
- return std::move(_value);
- }
-
- const value_type* operator->() const& { return &value(); }
- value_type* operator->() & { return &editValue(); }
- const value_type& operator*() const& { return value(); }
- value_type& operator*() & { return editValue(); }
+private:
+ T _value;
+ bool _omitted = false;
+};
- private:
- T _value;
- bool _omitted = false;
- };
+namespace _impl
+{
+ template <typename AlwaysVoid, typename>
+ struct fn_traits;
+}
- namespace _impl {
- template <typename AlwaysVoid, typename> struct fn_traits;
- }
+/** Determine traits of an arbitrary function/lambda/functor
+ * Doesn't work with generic lambdas and function objects that have
+ * operator() overloaded.
+ * \sa
+ * https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765
+ */
+template <typename T>
+struct function_traits : public _impl::fn_traits<void, T>
+{};
- /** Determine traits of an arbitrary function/lambda/functor
- * Doesn't work with generic lambdas and function objects that have
- * operator() overloaded.
- * \sa
- * https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765
- */
- template <typename T>
- struct function_traits : public _impl::fn_traits<void, T> {
+// Specialisation for a function
+template <typename ReturnT, typename... ArgTs>
+struct function_traits<ReturnT(ArgTs...)>
+{
+ static constexpr auto is_callable = true;
+ using return_type = ReturnT;
+ using arg_types = std::tuple<ArgTs...>;
+ using function_type = std::function<ReturnT(ArgTs...)>;
+ static constexpr auto arg_number = std::tuple_size<arg_types>::value;
+};
+
+namespace _impl
+{
+ template <typename AlwaysVoid, typename T>
+ struct fn_traits
+ {
+ static constexpr auto is_callable = false;
};
- // Specialisation for a function
- template <typename ReturnT, typename... ArgTs>
- struct function_traits<ReturnT(ArgTs...)> {
- static constexpr auto is_callable = true;
- using return_type = ReturnT;
- using arg_types = std::tuple<ArgTs...>;
- using function_type = std::function<ReturnT(ArgTs...)>;
- static constexpr auto arg_number = std::tuple_size<arg_types>::value;
- };
+ template <typename T>
+ struct fn_traits<decltype(void(&T::operator())), T>
+ : public fn_traits<void, decltype(&T::operator())>
+ {}; // A generic function object that has (non-overloaded) operator()
+
+ // Specialisation for a member function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...)>
+ : function_traits<ReturnT(ArgTs...)>
+ {};
+
+ // Specialisation for a const member function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const>
+ : function_traits<ReturnT(ArgTs...)>
+ {};
+} // namespace _impl
+
+template <typename FnT>
+using fn_return_t = typename function_traits<FnT>::return_type;
+
+template <typename FnT, int ArgN = 0>
+using fn_arg_t =
+ std::tuple_element_t<ArgN, typename function_traits<FnT>::arg_types>;
+
+template <typename R, typename FnT>
+constexpr bool returns()
+{
+ return std::is_same<fn_return_t<FnT>, R>::value;
+}
- namespace _impl {
- template <typename AlwaysVoid, typename T> struct fn_traits {
- static constexpr auto is_callable = false;
- };
-
- template <typename T>
- struct fn_traits<decltype(void(&T::operator())), T>
- : public fn_traits<void, decltype(&T::operator())> {
- }; // A generic function object that has (non-overloaded) operator()
-
- // Specialisation for a member function
- template <typename ReturnT, typename ClassT, typename... ArgTs>
- struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...)>
- : function_traits<ReturnT(ArgTs...)> {
- };
-
- // Specialisation for a const member function
- template <typename ReturnT, typename ClassT, typename... ArgTs>
- struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const>
- : function_traits<ReturnT(ArgTs...)> {
- };
- } // namespace _impl
-
- template <typename FnT>
- using fn_return_t = typename function_traits<FnT>::return_type;
-
- template <typename FnT, int ArgN = 0>
- using fn_arg_t =
- std::tuple_element_t<ArgN,
- typename function_traits<FnT>::arg_types>;
-
- template <typename R, typename FnT> constexpr bool returns()
- {
- return std::is_same<fn_return_t<FnT>, R>::value;
- }
+// Poor-man's is_invokable
+template <typename T>
+constexpr auto is_callable_v = function_traits<T>::is_callable;
- // Poor-man's is_invokable
- template <typename T>
- constexpr auto is_callable_v = function_traits<T>::is_callable;
+inline auto operator"" _ls(const char* s, std::size_t size)
+{
+ return QLatin1String(s, int(size));
+}
- inline auto operator"" _ls(const char* s, std::size_t size)
+/** An abstraction over a pair of iterators
+ * This is a very basic range type over a container with iterators that
+ * are at least ForwardIterators. Inspired by Ranges TS.
+ */
+template <typename ArrayT>
+class Range
+{
+ // Looking forward for Ranges TS to produce something (in C++23?..)
+ using iterator = typename ArrayT::iterator;
+ using const_iterator = typename ArrayT::const_iterator;
+ using size_type = typename ArrayT::size_type;
+
+public:
+ Range(ArrayT& arr)
+ : from(std::begin(arr))
+ , to(std::end(arr))
+ {}
+ Range(iterator from, iterator to)
+ : from(from)
+ , to(to)
+ {}
+
+ size_type size() const
{
- return QLatin1String(s, int(size));
+ Q_ASSERT(std::distance(from, to) >= 0);
+ return size_type(std::distance(from, to));
}
+ bool empty() const { return from == to; }
+ const_iterator begin() const { return from; }
+ const_iterator end() const { return to; }
+ iterator begin() { return from; }
+ iterator end() { return to; }
+
+private:
+ iterator from;
+ iterator to;
+};
+
+/** A replica of std::find_first_of that returns a pair of iterators
+ *
+ * Convenient for cases when you need to know which particular "first of"
+ * [sFirst, sLast) has been found in [first, last).
+ */
+template <typename InputIt, typename ForwardIt, typename Pred>
+inline std::pair<InputIt, ForwardIt> findFirstOf(InputIt first, InputIt last,
+ ForwardIt sFirst,
+ ForwardIt sLast, Pred pred)
+{
+ for (; first != last; ++first)
+ for (auto it = sFirst; it != sLast; ++it)
+ if (pred(*first, *it))
+ return std::make_pair(first, it);
- /** An abstraction over a pair of iterators
- * This is a very basic range type over a container with iterators that
- * are at least ForwardIterators. Inspired by Ranges TS.
- */
- template <typename ArrayT> class Range
- {
- // Looking forward for Ranges TS to produce something (in C++23?..)
- using iterator = typename ArrayT::iterator;
- using const_iterator = typename ArrayT::const_iterator;
- using size_type = typename ArrayT::size_type;
-
- public:
- Range(ArrayT& arr) : from(std::begin(arr)), to(std::end(arr)) {}
- Range(iterator from, iterator to) : from(from), to(to) {}
-
- size_type size() const
- {
- Q_ASSERT(std::distance(from, to) >= 0);
- return size_type(std::distance(from, to));
- }
- bool empty() const { return from == to; }
- const_iterator begin() const { return from; }
- const_iterator end() const { return to; }
- iterator begin() { return from; }
- iterator end() { return to; }
-
- private:
- iterator from;
- iterator to;
- };
+ return std::make_pair(last, sLast);
+}
- /** A replica of std::find_first_of that returns a pair of iterators
- *
- * Convenient for cases when you need to know which particular "first of"
- * [sFirst, sLast) has been found in [first, last).
- */
- template <typename InputIt, typename ForwardIt, typename Pred>
- inline std::pair<InputIt, ForwardIt>
- findFirstOf(InputIt first, InputIt last, ForwardIt sFirst, ForwardIt sLast,
- Pred pred)
- {
- for (; first != last; ++first)
- for (auto it = sFirst; it != sLast; ++it)
- if (pred(*first, *it))
- return std::make_pair(first, it);
+/** Convert what looks like a URL or a Matrix ID to an HTML hyperlink */
+void linkifyUrls(QString& htmlEscapedText);
- return std::make_pair(last, sLast);
- }
+/** Sanitize the text before showing in HTML
+ * This does toHtmlEscaped() and removes Unicode BiDi marks.
+ */
+QString sanitized(const QString& plainText);
- /** Pretty-prints plain text into HTML
- * This includes HTML escaping of <,>,",& and URLs linkification.
- */
- QString prettyPrint(const QString& plainText);
+/** Pretty-print plain text into HTML
+ * This includes HTML escaping of <,>,",& and calling linkifyUrls()
+ */
+QString prettyPrint(const QString& plainText);
- /** Return a path to cache directory after making sure that it exists
- * The returned path has a trailing slash, clients don't need to append it.
- * \param dir path to cache directory relative to the standard cache path
- */
- QString cacheLocation(const QString& dirName);
+/** Return a path to cache directory after making sure that it exists
+ * The returned path has a trailing slash, clients don't need to append it.
+ * \param dir path to cache directory relative to the standard cache path
+ */
+QString cacheLocation(const QString& dirName);
} // namespace QMatrixClient