From 9f798e76ede3672d91276b1be7dd20de5459c9df Mon Sep 17 00:00:00 2001 From: Alexander Bantyev Date: Thu, 17 Jun 2021 22:27:37 +0300 Subject: Allow editing unsent messages As of 0db4d71ec2483c7ac5a7b536737fee8fc53a76d7 (Prevent edits of unsent messages), messages that are edits of (or replies to) unsent messages were not allowed. This change was made because otherwise the edits were discarded due to use of txnid rather than mxid in the "m.relates_to" object. Remove this restriction and fix the issue by replacing txnid with mxid in all related events when the message is sent (and we obtain mxid from the server). --- src/timeline/EventStore.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src/timeline/EventStore.cpp') diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 4a9f0fff..3667433b 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -185,6 +185,33 @@ EventStore::EventStore(std::string room_id, QObject *) [this](std::string txn_id, std::string event_id) { nhlog::ui()->debug("sent {}", txn_id); + // Replace the event_id in pending edits/replies/redactions with the actual + // event_id of this event + for (auto related_event_id : cache::client()->relatedEvents(room_id_, txn_id)) { + if (cache::client()->getEvent(room_id_, related_event_id)) { + auto related_event = + cache::client()->getEvent(room_id_, related_event_id).value(); + auto relations = mtx::accessors::relations(related_event.data); + + for (mtx::common::Relation &rel : relations.relations) { + if (rel.event_id == txn_id) + rel.event_id = event_id; + } + + mtx::accessors::set_relations(related_event.data, relations); + + cache::client()->replaceEvent( + room_id_, related_event_id, related_event); + + auto id = idToIndex(event_id); + + events_by_id_.remove({room_id_, related_event_id}); + events_.remove({room_id_, toInternalIdx(*id)}); + + emit dataChanged(*id, *id); + } + } + http::client()->read_event( room_id_, event_id, [this, event_id](mtx::http::RequestErr err) { if (err) { @@ -193,6 +220,11 @@ EventStore::EventStore(std::string room_id, QObject *) } }); + auto id = idToIndex(event_id); + + if (id) + emit dataChanged(id.value(), id.value()); + cache::client()->removePendingStatus(room_id_, txn_id); this->current_txn = ""; this->current_txn_error_count = 0; -- cgit 1.5.1 From f8d2564e462abbaf4d33f089d1fb8af7d5100234 Mon Sep 17 00:00:00 2001 From: Alexander Bantyev Date: Fri, 18 Jun 2021 20:25:44 +0300 Subject: fixup! Allow editing unsent messages --- src/timeline/EventStore.cpp | 25 ++++++++++++++++++------- src/timeline/TimelineModel.cpp | 3 +++ 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src/timeline/EventStore.cpp') diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 3667433b..956698da 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -193,6 +193,19 @@ EventStore::EventStore(std::string room_id, QObject *) cache::client()->getEvent(room_id_, related_event_id).value(); auto relations = mtx::accessors::relations(related_event.data); + // Replace the blockquote in fallback reply + auto related_text = + std::get_if>( + &related_event.data); + if (related_text && relations.reply_to() == txn_id) { + size_t index = + related_text->content.formatted_body.find(txn_id); + if (index != std::string::npos) { + related_text->content.formatted_body.replace( + index, event_id.length(), event_id); + } + } + for (mtx::common::Relation &rel : relations.relations) { if (rel.event_id == txn_id) rel.event_id = event_id; @@ -203,12 +216,10 @@ EventStore::EventStore(std::string room_id, QObject *) cache::client()->replaceEvent( room_id_, related_event_id, related_event); - auto id = idToIndex(event_id); + auto idx = idToIndex(related_event_id); events_by_id_.remove({room_id_, related_event_id}); - events_.remove({room_id_, toInternalIdx(*id)}); - - emit dataChanged(*id, *id); + events_.remove({room_id_, toInternalIdx(*idx)}); } } @@ -220,10 +231,10 @@ EventStore::EventStore(std::string room_id, QObject *) } }); - auto id = idToIndex(event_id); + auto idx = idToIndex(event_id); - if (id) - emit dataChanged(id.value(), id.value()); + if (idx) + emit dataChanged(*idx, *idx); cache::client()->removePendingStatus(room_id_, txn_id); this->current_txn = ""; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index e2e5551b..321179b4 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -383,6 +383,9 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj edit_ = QString::fromStdString(event_id); emit editChanged(edit_); } + if (reply_.toStdString() == txn_id) { + reply_ = QString::fromStdString(event_id); + } }); showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent); -- cgit 1.5.1 From 358a39e6d2a5db9181a6dac1cb000ac8b85e15f2 Mon Sep 17 00:00:00 2001 From: Alexander Bantyev Date: Sat, 19 Jun 2021 23:26:21 +0300 Subject: fixup! Allow editing unsent messages --- src/timeline/EventStore.cpp | 6 +++++- src/timeline/TimelineModel.cpp | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/timeline/EventStore.cpp') diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 956698da..04f7ef76 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -186,7 +186,11 @@ EventStore::EventStore(std::string room_id, QObject *) nhlog::ui()->debug("sent {}", txn_id); // Replace the event_id in pending edits/replies/redactions with the actual - // event_id of this event + // event_id of this event. This allows one to edit and reply to events that are + // currently pending. + + // FIXME (introduced by balsoft): this doesn't work for encrypted events, but + // allegedly it's hard to fix so I'll leave my first contribution at that for (auto related_event_id : cache::client()->relatedEvents(room_id_, txn_id)) { if (cache::client()->getEvent(room_id_, related_event_id)) { auto related_event = diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 4bff15eb..99547b15 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -375,6 +375,8 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) { this->updateFlowEventId(event_id); }); + // When a message is sent, check if the current edit/reply relates to that message, + // and update the event_id so that it points to the sent message and not the pending one. connect(&events, &EventStore::messageSent, this, -- cgit 1.5.1 From d30446a8b39c70f87fad34b0c1958236c9f227cc Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 19 Jun 2021 01:46:23 +0200 Subject: Don't spam key requests directly after startup --- src/timeline/EventStore.cpp | 15 +++++++++++++++ src/timeline/EventStore.h | 2 ++ src/timeline/TimelineModel.cpp | 6 ++++++ 3 files changed, 23 insertions(+) (limited to 'src/timeline/EventStore.cpp') diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 04f7ef76..9a91ff79 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -675,6 +675,9 @@ EventStore::decryptEvent(const IdIndex &idx, index.room_id, index.session_id, e.sender); + // we may not want to request keys during initial sync and such + if (suppressKeyRequests) + break; // TODO: Check if this actually works and look in key backup auto copy = e; copy.room_id = room_id_; @@ -816,6 +819,18 @@ EventStore::decryptEvent(const IdIndex &idx, return asCacheEntry(std::move(decryptionResult.event.value())); } +void +EventStore::enableKeyRequests(bool suppressKeyRequests_) +{ + if (!suppressKeyRequests_) { + for (const auto &key : decryptedEvents_.keys()) + if (key.room == this->room_id_) + decryptedEvents_.remove(key); + suppressKeyRequests = false; + } else + suppressKeyRequests = true; +} + mtx::events::collections::TimelineEvents * EventStore::get(std::string id, std::string_view related_to, bool decrypt, bool resolve_edits) { diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h index d9bb86cb..7c404102 100644 --- a/src/timeline/EventStore.h +++ b/src/timeline/EventStore.h @@ -115,6 +115,7 @@ public slots: void addPending(mtx::events::collections::TimelineEvents event); void receivedSessionKey(const std::string &session_id); void clearTimeline(); + void enableKeyRequests(bool suppressKeyRequests_); private: std::vector edits(const std::string &event_id); @@ -142,4 +143,5 @@ private: std::string current_txn; int current_txn_error_count = 0; bool noMoreMessages = false; + bool suppressKeyRequests = true; }; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 13919e6d..067f219a 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -379,6 +379,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) { this->updateFlowEventId(event_id); }); + // When a message is sent, check if the current edit/reply relates to that message, // and update the event_id so that it points to the sent message and not the pending one. connect(&events, @@ -395,6 +396,11 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj } }); + connect(manager_, + &TimelineViewManager::initialSyncChanged, + &events, + &EventStore::enableKeyRequests); + showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent); } -- cgit 1.5.1