aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/avatar.cpp2
-rw-r--r--lib/connection.cpp206
-rw-r--r--lib/connection.h9
-rw-r--r--lib/csapi/capabilities.cpp2
-rw-r--r--lib/csapi/content-repo.cpp2
-rw-r--r--lib/csapi/create_room.cpp2
-rw-r--r--lib/csapi/filter.cpp2
-rw-r--r--lib/csapi/joining.cpp4
-rw-r--r--lib/csapi/keys.cpp2
-rw-r--r--lib/csapi/list_joined_rooms.cpp2
-rw-r--r--lib/csapi/notifications.cpp2
-rw-r--r--lib/csapi/openid.cpp8
-rw-r--r--lib/csapi/presence.cpp2
-rw-r--r--lib/csapi/pushrules.cpp6
-rw-r--r--lib/csapi/registration.cpp2
-rw-r--r--lib/csapi/room_upgrades.cpp2
-rw-r--r--lib/csapi/search.cpp2
-rw-r--r--lib/csapi/users.cpp4
-rw-r--r--lib/csapi/versions.cpp2
-rw-r--r--lib/csapi/whoami.cpp2
-rw-r--r--lib/csapi/{{base}}.cpp.mustache2
-rw-r--r--lib/events/accountdataevents.h2
-rw-r--r--lib/events/event.h6
-rw-r--r--lib/jobs/basejob.cpp2
-rw-r--r--lib/jobs/basejob.h34
-rw-r--r--lib/room.cpp13
-rw-r--r--lib/room.h8
27 files changed, 183 insertions, 149 deletions
diff --git a/lib/avatar.cpp b/lib/avatar.cpp
index 9279ef9d..0d849eae 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>
*
diff --git a/lib/connection.cpp b/lib/connection.cpp
index d75d8e56..a7eae30f 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -73,15 +73,14 @@ class Connection::Private
: 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;
@@ -91,6 +90,10 @@ 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;
@@ -107,8 +110,6 @@ class Connection::Private
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
@@ -141,7 +142,7 @@ class Connection::Private
Connection::Connection(const QUrl& server, QObject* parent)
: QObject(parent)
- , d(std::make_unique<Private>(std::make_unique<ConnectionData>(server)))
+ , d(new Private(std::make_unique<ConnectionData>(server)))
{
d->q = this; // All d initialization should occur before this line
}
@@ -294,6 +295,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();
@@ -377,6 +379,20 @@ 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());
for (auto&& roomData: data.takeRoomData())
@@ -411,62 +427,90 @@ void Connection::onSyncSuccess(SyncData &&data, bool fromCache) {
// Let UI update itself after updating each room
QCoreApplication::processEvents();
}
- for (auto&& accountEvent: data.takeAccountData())
+ // 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())
{
- 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());
- });
- 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) << 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()
+ 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, [&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 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();
- }
- 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());
- }
+ }
+ } 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();
}
}
@@ -662,8 +706,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)
@@ -700,6 +744,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())
{
@@ -709,7 +755,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);
@@ -1010,28 +1056,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);
@@ -1040,8 +1064,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)
@@ -1054,15 +1078,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; });
d->directChatUsers.remove(roomId);
+ d->dcLocalRemovals += removals;
}
- d->broadcastDirectChatUpdates({}, removals);
+ emit directChatsListChanged({}, removals);
}
bool Connection::isDirectChat(const QString& roomId) const
diff --git a/lib/connection.h b/lib/connection.h
index 2ff27ea6..cc2feed8 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -29,7 +29,6 @@
#include <QtCore/QDir>
#include <functional>
-#include <memory>
namespace QMatrixClient
{
@@ -96,9 +95,6 @@ namespace QMatrixClient
class Connection: public QObject {
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)
@@ -341,6 +337,9 @@ namespace QMatrixClient
*/
QDir stateCacheDir() const;
+ /** Whether or not the rooms state should be cached locally
+ * \sa loadState(), saveState()
+ */
bool cacheState() const;
void setCacheState(bool newValue);
@@ -744,7 +743,7 @@ namespace QMatrixClient
private:
class Private;
- std::unique_ptr<Private> d;
+ QScopedPointer<Private> d;
/**
* A single entry for functions that need to check whether the
diff --git a/lib/csapi/capabilities.cpp b/lib/csapi/capabilities.cpp
index 210423f5..fb506784 100644
--- a/lib/csapi/capabilities.cpp
+++ b/lib/csapi/capabilities.cpp
@@ -76,7 +76,7 @@ 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/content-repo.cpp b/lib/csapi/content-repo.cpp
index 22223985..7e490604 100644
--- a/lib/csapi/content-repo.cpp
+++ b/lib/csapi/content-repo.cpp
@@ -50,7 +50,7 @@ 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;
diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp
index 448547ae..3101152a 100644
--- a/lib/csapi/create_room.cpp
+++ b/lib/csapi/create_room.cpp
@@ -77,7 +77,7 @@ 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/filter.cpp b/lib/csapi/filter.cpp
index 982e60b5..9f412d53 100644
--- a/lib/csapi/filter.cpp
+++ b/lib/csapi/filter.cpp
@@ -39,7 +39,7 @@ 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;
diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp
index 00d930fa..544f442f 100644
--- a/lib/csapi/joining.cpp
+++ b/lib/csapi/joining.cpp
@@ -57,7 +57,7 @@ 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;
@@ -124,7 +124,7 @@ 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/keys.cpp b/lib/csapi/keys.cpp
index 6c16a8a3..5bbc1aab 100644
--- a/lib/csapi/keys.cpp
+++ b/lib/csapi/keys.cpp
@@ -42,7 +42,7 @@ 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;
diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp
index 85a9cae4..297a5ae0 100644
--- a/lib/csapi/list_joined_rooms.cpp
+++ b/lib/csapi/list_joined_rooms.cpp
@@ -44,7 +44,7 @@ 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/notifications.cpp b/lib/csapi/notifications.cpp
index c00b7cb0..5d3bdb47 100644
--- a/lib/csapi/notifications.cpp
+++ b/lib/csapi/notifications.cpp
@@ -80,7 +80,7 @@ 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/openid.cpp b/lib/csapi/openid.cpp
index b27fe0b8..03d24790 100644
--- a/lib/csapi/openid.cpp
+++ b/lib/csapi/openid.cpp
@@ -57,19 +57,19 @@ 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/presence.cpp b/lib/csapi/presence.cpp
index 024d7a34..210ee0ae 100644
--- a/lib/csapi/presence.cpp
+++ b/lib/csapi/presence.cpp
@@ -74,7 +74,7 @@ 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);
diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp
index b91d18f7..9b5b7cd1 100644
--- a/lib/csapi/pushrules.cpp
+++ b/lib/csapi/pushrules.cpp
@@ -44,7 +44,7 @@ BaseJob::Status GetPushRulesJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
if (!json.contains("global"_ls))
- return { JsonParseError,
+ return { IncorrectResponse,
"The key 'global' not found in the response" };
fromJson(json.value("global"_ls), d->global);
return Success;
@@ -152,7 +152,7 @@ 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;
@@ -201,7 +201,7 @@ 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;
diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp
index 5dc9c1e5..76741a50 100644
--- a/lib/csapi/registration.cpp
+++ b/lib/csapi/registration.cpp
@@ -74,7 +74,7 @@ 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);
diff --git a/lib/csapi/room_upgrades.cpp b/lib/csapi/room_upgrades.cpp
index f58fd675..f80c3aba 100644
--- a/lib/csapi/room_upgrades.cpp
+++ b/lib/csapi/room_upgrades.cpp
@@ -41,7 +41,7 @@ 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/search.cpp b/lib/csapi/search.cpp
index a5f83c79..ad2c34a3 100644
--- a/lib/csapi/search.cpp
+++ b/lib/csapi/search.cpp
@@ -164,7 +164,7 @@ 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/users.cpp b/lib/csapi/users.cpp
index 97d8962d..0d867145 100644
--- a/lib/csapi/users.cpp
+++ b/lib/csapi/users.cpp
@@ -63,11 +63,11 @@ 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/versions.cpp b/lib/csapi/versions.cpp
index 6ee6725d..4b7c4ced 100644
--- a/lib/csapi/versions.cpp
+++ b/lib/csapi/versions.cpp
@@ -50,7 +50,7 @@ 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);
diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp
index aebdf5d3..ce024c33 100644
--- a/lib/csapi/whoami.cpp
+++ b/lib/csapi/whoami.cpp
@@ -44,7 +44,7 @@ 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/{{base}}.cpp.mustache b/lib/csapi/{{base}}.cpp.mustache
index ff888d76..010f9116 100644
--- a/lib/csapi/{{base}}.cpp.mustache
+++ b/lib/csapi/{{base}}.cpp.mustache
@@ -115,7 +115,7 @@ BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data
{{#inlineResponse}} fromJson(data, d->{{paramName}});
{{/inlineResponse}}{{^inlineResponse}} 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}});
{{/properties}}{{/inlineResponse}} return Success;
diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h
index a99d85ac..ffee5ba6 100644
--- a/lib/events/accountdataevents.h
+++ b/lib/events/accountdataevents.h
@@ -85,7 +85,7 @@ namespace QMatrixClient
toJson(std::move(content)) } }) \
{ } \
auto _ContentKey() const \
- { return fromJson<content_type>(contentJson()[#_ContentKey##_ls]); } \
+ { return content<content_type>(#_ContentKey##_ls); } \
}; \
REGISTER_EVENT_TYPE(_Name) \
// End of macro
diff --git a/lib/events/event.h b/lib/events/event.h
index d7ac4292..b7bbd83e 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -32,19 +32,23 @@ namespace QMatrixClient
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) // unwrap
+ 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);
diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp
index 0d9b9f10..34fc0f57 100644
--- a/lib/jobs/basejob.cpp
+++ b/lib/jobs/basejob.cpp
@@ -555,8 +555,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:
diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h
index 4c1c7706..4ee63adb 100644
--- a/lib/jobs/basejob.h
+++ b/lib/jobs/basejob.h
@@ -46,28 +46,36 @@ namespace QMatrixClient
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
+ , 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
- , JsonParseError // TODO: Merge into IncorrectResponseError
- , TimeoutError
+ , Timeout
+ , TimeoutError = Timeout
, ContentAccessError
, NotFoundError
- , IncorrectRequestError
- , IncorrectResponseError
- , TooManyRequestsError
- , RequestNotImplementedError
- , UnsupportedRoomVersionError
- , NetworkAuthRequiredError
- , UserConsentRequiredError
- , UserDefinedError = 200
+ , 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
};
/**
diff --git a/lib/room.cpp b/lib/room.cpp
index 2ce37acc..9042130a 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -75,7 +75,8 @@ 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. */
+ /// 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)
@@ -515,7 +516,7 @@ void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to)
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;
@@ -556,7 +557,7 @@ Room::Changes Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker,
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;
@@ -612,7 +613,7 @@ void Room::markAllMessagesAsRead()
bool Room::canSwitchVersions() const
{
if (!successorId().isEmpty())
- return false; // Noone can upgrade a room that's already upgraded
+ return false; // No one can upgrade a room that's already upgraded
// TODO, #276: m.room.power_levels
const auto* plEvt =
@@ -1235,7 +1236,7 @@ void Room::Private::removeMemberFromMap(const QString& username, User* u)
}
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.
+ // for it because it doesn't need to be disambiguated any more.
if (namesake)
emit q->memberRenamed(namesake);
}
@@ -1354,7 +1355,7 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
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;
diff --git a/lib/room.h b/lib/room.h
index 055da3da..d4a1b959 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -322,7 +322,7 @@ namespace QMatrixClient
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
+ * 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_.
*/
@@ -516,7 +516,7 @@ namespace QMatrixClient
/** 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
+ * @param changes a set of flags describing what changes occurred
* upon the last sync
* \sa StateChange
*/
@@ -524,7 +524,7 @@ namespace QMatrixClient
/**
* \brief The room name, the canonical alias or other aliases changed
*
- * Not triggered when displayname changes.
+ * Not triggered when display name changes.
*/
void namesChanged(Room* room);
void displaynameAboutToChange(Room* room);
@@ -581,7 +581,7 @@ namespace QMatrixClient
/// 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
+ /// 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);