aboutsummaryrefslogtreecommitdiff
path: root/lib/room.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/room.cpp')
-rw-r--r--lib/room.cpp150
1 files changed, 72 insertions, 78 deletions
diff --git a/lib/room.cpp b/lib/room.cpp
index ba63f50d..1450eb3b 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -16,6 +16,7 @@
#include "syncdata.h"
#include "user.h"
#include "eventstats.h"
+#include "roomstateview.h"
// NB: since Qt 6, moc_room.cpp needs User fully defined
#include "moc_room.cpp"
@@ -103,7 +104,7 @@ public:
static decltype(baseState) stubbedState;
/// The state of the room at syncEdge()
/// \sa syncEdge
- QHash<StateEventKey, const StateEventBase*> currentState;
+ RoomStateView currentState;
/// Servers with aliases for this room except the one of the local user
/// \sa Room::remoteAliases
QSet<QString> aliasServers;
@@ -227,34 +228,6 @@ public:
return evt;
}
- QVector<const StateEventBase*> stateEventsOfType(const QString& evtType) const
- {
- auto vals = QVector<const StateEventBase*>();
- for (auto it = currentState.cbegin(); it != currentState.cend(); ++it)
- if (it.key().first == evtType)
- vals.append(it.value());
-
- return vals;
- }
-
- template <typename EventT>
- const EventT* getCurrentState(const QString& stateKey = {}) const
- {
- const auto* evt = getCurrentState({ EventT::matrixTypeId(), stateKey });
- Q_ASSERT(evt->type() == EventT::typeId()
- && evt->matrixType() == EventT::matrixTypeId());
- return static_cast<const EventT*>(evt);
- }
-
-// template <typename EventT>
-// const auto& getCurrentStateContent(const QString& stateKey = {}) const
-// {
-// if (const auto* evt =
-// currentState.value({ EventT::matrixTypeId(), stateKey }, nullptr))
-// return evt->content();
-// return EventT::content_type()
-// }
-
template <typename EventArrayT>
Changes updateStateFrom(EventArrayT&& events)
{
@@ -480,8 +453,8 @@ const QString& Room::id() const { return d->id; }
QString Room::version() const
{
- const auto v = d->getCurrentState<RoomCreateEvent>()->version();
- return v.isEmpty() ? QStringLiteral("1") : v;
+ const auto v = currentState().query(&RoomCreateEvent::version);
+ return v && !v->isEmpty() ? *v : QStringLiteral("1");
}
bool Room::isUnstable() const
@@ -492,7 +465,10 @@ bool Room::isUnstable() const
QString Room::predecessorId() const
{
- return d->getCurrentState<RoomCreateEvent>()->predecessor().roomId;
+ if (const auto* evt = currentState().get<RoomCreateEvent>())
+ return evt->predecessor().roomId;
+
+ return {};
}
Room* Room::predecessor(JoinStates statesFilter) const
@@ -507,7 +483,8 @@ Room* Room::predecessor(JoinStates statesFilter) const
QString Room::successorId() const
{
- return d->getCurrentState<RoomTombstoneEvent>()->successorRoomId();
+ return currentState().queryOr(&RoomTombstoneEvent::successorRoomId,
+ QString());
}
Room* Room::successor(JoinStates statesFilter) const
@@ -534,39 +511,41 @@ bool Room::allHistoryLoaded() const
QString Room::name() const
{
- return d->getCurrentState<RoomNameEvent>()->name();
+ return currentState().queryOr(&RoomNameEvent::name, QString());
}
QStringList Room::aliases() const
{
- const auto* evt = d->getCurrentState<RoomCanonicalAliasEvent>();
- auto result = evt->altAliases();
- if (!evt->alias().isEmpty())
- result << evt->alias();
- return result;
+ if (const auto* evt = currentState().get<RoomCanonicalAliasEvent>()) {
+ auto result = evt->altAliases();
+ if (!evt->alias().isEmpty())
+ result << evt->alias();
+ return result;
+ }
+ return {};
}
QStringList Room::altAliases() const
{
- return d->getCurrentState<RoomCanonicalAliasEvent>()->altAliases();
+ return currentState().queryOr(&RoomCanonicalAliasEvent::altAliases,
+ QStringList());
}
QString Room::canonicalAlias() const
{
- return d->getCurrentState<RoomCanonicalAliasEvent>()->alias();
+ return currentState().queryOr(&RoomCanonicalAliasEvent::alias, QString());
}
QString Room::displayName() const { return d->displayname; }
QStringList Room::pinnedEventIds() const {
- return d->getCurrentState<RoomPinnedEvent>()->pinnedEvents();
+ return currentState().queryOr(&RoomPinnedEvent::pinnedEvents, QStringList());
}
QVector<const Quotient::RoomEvent*> Quotient::Room::pinnedEvents() const
{
- const auto& pinnedIds = d->getCurrentState<RoomPinnedEvent>()->pinnedEvents();
QVector<const RoomEvent*> pinnedEvents;
- for (auto&& evtId: pinnedIds)
+ for (const auto& evtId : pinnedEventIds())
if (const auto& it = findInTimeline(evtId); it != historyEdge())
pinnedEvents.append(it->event());
@@ -582,7 +561,7 @@ void Room::refreshDisplayName() { d->updateDisplayname(); }
QString Room::topic() const
{
- return d->getCurrentState<RoomTopicEvent>()->topic();
+ return currentState().queryOr(&RoomTopicEvent::topic, QString());
}
QString Room::avatarMediaId() const { return d->avatar.mediaId(); }
@@ -621,7 +600,8 @@ JoinState Room::memberJoinState(User* user) const
Membership Room::memberState(const QString& userId) const
{
- return d->getCurrentState<RoomMemberEvent>(userId)->membership();
+ return currentState().queryOr(userId, &RoomMemberEvent::membership,
+ Membership::Leave);
}
bool Room::isMember(const QString& userId) const
@@ -899,8 +879,9 @@ bool Room::canSwitchVersions() const
if (!successorId().isEmpty())
return false; // No one can upgrade a room that's already upgraded
- if (const auto* plEvt = d->getCurrentState<RoomPowerLevelsEvent>()) {
- const auto currentUserLevel = plEvt->powerLevelForUser(localUser()->id());
+ if (const auto* plEvt = currentState().get<RoomPowerLevelsEvent>()) {
+ const auto currentUserLevel =
+ plEvt->powerLevelForUser(localUser()->id());
const auto tombstonePowerLevel =
plEvt->powerLevelForState("m.room.tombstone"_ls);
return currentUserLevel >= tombstonePowerLevel;
@@ -1008,6 +989,16 @@ const Room::RelatedEvents Room::relatedEvents(
return relatedEvents(evt.id(), relType);
}
+const RoomCreateEvent* Room::creation() const
+{
+ return currentState().get<RoomCreateEvent>();
+}
+
+const RoomTombstoneEvent *Room::tombstone() const
+{
+ return currentState().get<RoomTombstoneEvent>();
+}
+
void Room::Private::getAllMembers()
{
// If already loaded or already loading, there's nothing to do here.
@@ -1472,7 +1463,9 @@ int Room::timelineSize() const { return int(d->timeline.size()); }
bool Room::usesEncryption() const
{
- return !d->getCurrentState<EncryptionEvent>()->algorithm().isEmpty();
+ return !currentState()
+ .queryOr(&EncryptionEvent::algorithm, QString())
+ .isEmpty();
}
const StateEventBase* Room::getCurrentState(const QString& evtType,
@@ -1481,13 +1474,7 @@ const StateEventBase* Room::getCurrentState(const QString& evtType,
return d->getCurrentState({ evtType, stateKey });
}
-const QVector<const StateEventBase*>
-Room::stateEventsOfType(const QString& evtType) const
-{
- return d->stateEventsOfType(evtType);
-}
-
-const QHash<StateEventKey, const StateEventBase*>& Room::currentState() const
+RoomStateView Room::currentState() const
{
return d->currentState;
}
@@ -1564,7 +1551,7 @@ Room::Changes Room::Private::setSummary(RoomSummary&& newSummary)
void Room::Private::insertMemberIntoMap(User* u)
{
const auto maybeUserName =
- getCurrentState<RoomMemberEvent>(u->id())->newDisplayName();
+ currentState.query(u->id(), &RoomMemberEvent::newDisplayName);
if (!maybeUserName)
qCWarning(MEMBERS) << "insertMemberIntoMap():" << u->id()
<< "has no name (even empty)";
@@ -1594,9 +1581,9 @@ void Room::Private::insertMemberIntoMap(User* u)
void Room::Private::removeMemberFromMap(User* u)
{
- const auto userName =
- getCurrentState<RoomMemberEvent>(
- u->id())->newDisplayName().value_or(QString());
+ const auto userName = currentState.queryOr(u->id(),
+ &RoomMemberEvent::newDisplayName,
+ QString());
qCDebug(MEMBERS) << "removeMemberFromMap(), username" << userName
<< "for user" << u->id();
@@ -1679,10 +1666,13 @@ Room::Private::moveEventsToTimeline(RoomEventsRange events,
QString Room::memberName(const QString& mxId) const
{
// See https://github.com/matrix-org/matrix-doc/issues/1375
- const auto rme = getCurrentState<RoomMemberEvent>(mxId);
- return rme->newDisplayName() ? *rme->newDisplayName()
- : rme->prevContent() ? rme->prevContent()->displayName.value_or(QString())
- : QString();
+ if (const auto rme = currentState().get<RoomMemberEvent>(mxId)) {
+ if (rme->newDisplayName())
+ return *rme->newDisplayName();
+ if (rme->prevContent() && rme->prevContent()->displayName)
+ return *rme->prevContent()->displayName;
+ }
+ return {};
}
QString Room::roomMembername(const User* u) const
@@ -1737,10 +1727,13 @@ QString Room::htmlSafeMemberName(const QString& userId) const
QUrl Room::memberAvatarUrl(const QString &mxId) const
{
// See https://github.com/matrix-org/matrix-doc/issues/1375
- const auto rme = getCurrentState<RoomMemberEvent>(mxId);
- return rme->newAvatarUrl() ? *rme->newAvatarUrl()
- : rme->prevContent() ? rme->prevContent()->avatarUrl.value_or(QUrl())
- : QUrl();
+ if (const auto rme = currentState().get<RoomMemberEvent>(mxId)) {
+ if (rme->newAvatarUrl())
+ return *rme->newAvatarUrl();
+ if (rme->prevContent() && rme->prevContent()->avatarUrl)
+ return *rme->prevContent()->avatarUrl;
+ }
+ return {};
}
Room::Changes Room::Private::updateStatsFromSyncData(const SyncRoomData& data,
@@ -2489,12 +2482,14 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction)
auto oldEvent = ti.replaceEvent(makeRedacted(*ti, redaction));
qCDebug(EVENTS) << "Redacted" << oldEvent->id() << "with" << redaction.id();
if (oldEvent->isStateEvent()) {
- const StateEventKey evtKey { oldEvent->matrixType(),
- oldEvent->stateKey() };
- Q_ASSERT(currentState.contains(evtKey));
- if (currentState.value(evtKey) == oldEvent.get()) {
- Q_ASSERT(ti.index() >= 0); // Historical states can't be in
- // currentState
+ // Check whether the old event was a part of current state; if it was,
+ // update the current state to the redacted event object.
+ const auto currentStateEvt =
+ currentState.get(oldEvent->matrixType(), oldEvent->stateKey());
+ Q_ASSERT(currentStateEvt);
+ if (currentStateEvt == oldEvent.get()) {
+ // Historical states can't be in currentState
+ Q_ASSERT(ti.index() >= 0);
qCDebug(STATE).nospace()
<< "Redacting state " << oldEvent->matrixType() << "/"
<< oldEvent->stateKey();
@@ -2514,6 +2509,7 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction)
}
q->onRedaction(*oldEvent, *ti);
emit q->replacedEvent(ti.event(), rawPtr(oldEvent));
+ // By now, all references to oldEvent must have been updated to ti.event()
return true;
}
@@ -2754,7 +2750,7 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events)
for (const auto& eptr : events) {
const auto& e = *eptr;
if (e.isStateEvent()
- && !currentState.contains({ e.matrixType(), e.stateKey() })) {
+ && !currentState.contains(e.matrixType(), e.stateKey())) {
changes |= q->processStateEvent(e);
}
}
@@ -2791,9 +2787,7 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
return Change::None;
// Find a value (create an empty one if necessary) and get a reference
- // to it. Can't use getCurrentState<>() because it (creates and) returns
- // a stub if a value is not found, and what's needed here is a "real" event
- // or nullptr.
+ // to it, anticipating a change further in the function.
auto& curStateEvent = d->currentState[{ e.matrixType(), e.stateKey() }];
// Prepare for the state change
// clang-format off