summary refs log tree commit diff
diff options
context:
space:
mode:
authorCH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>2020-08-09 08:35:15 +0530
committerCH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>2020-08-09 08:35:15 +0530
commit2e20049b3695d0aa7ca09db079bcc39c0485d098 (patch)
tree664dfdabdd940f217fac4d55c55e9f47358036ee
parentAdd Room Verification Messages (diff)
downloadnheko-2e20049b3695d0aa7ca09db079bcc39c0485d098.tar.xz
[WIP] Room-Verification Messages
-rw-r--r--resources/qml/Reactions.qml7
-rw-r--r--resources/qml/TimelineRow.qml2
-rw-r--r--resources/qml/TimelineView.qml5
-rw-r--r--resources/qml/UserProfile.qml15
-rw-r--r--resources/qml/device-verification/DeviceVerification.qml4
-rw-r--r--src/ChatPage.cpp11
-rw-r--r--src/DeviceVerificationFlow.cpp197
-rw-r--r--src/DeviceVerificationFlow.h2
-rw-r--r--src/EventAccessors.cpp11
-rw-r--r--src/timeline/EventStore.cpp221
-rw-r--r--src/timeline/EventStore.h8
-rw-r--r--src/timeline/TimelineModel.cpp333
-rw-r--r--src/timeline/TimelineModel.h16
-rw-r--r--src/ui/UserProfile.cpp56
-rw-r--r--src/ui/UserProfile.h6
15 files changed, 401 insertions, 493 deletions
diff --git a/resources/qml/Reactions.qml b/resources/qml/Reactions.qml
index 11109d7f..9fc30f61 100644
--- a/resources/qml/Reactions.qml
+++ b/resources/qml/Reactions.qml
@@ -35,13 +35,8 @@ Flow {
 			ToolTip.text: modelData.users
 
 			onClicked: {
-<<<<<<< HEAD
 				console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + modelData.selfReactedEvent)
-				timelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key)
-=======
-				console.debug("Picked " + model.key + "in response to " + reactionFlow.eventId + " in room " + reactionFlow.roomId + ". selfReactedEvent: " + model.selfReactedEvent)
-				TimelineManager.reactToMessage(reactionFlow.roomId, reactionFlow.eventId, model.key, model.selfReactedEvent)
->>>>>>> Fix presence indicator
+				TimelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key)
 			}
 
 
diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml
index db58eb22..b464b76c 100644
--- a/resources/qml/TimelineRow.qml
+++ b/resources/qml/TimelineRow.qml
@@ -48,7 +48,7 @@ Item {
 			// fancy reply, if this is a reply
 			Reply {
 				visible: model.replyTo
-				modelData: chat.model.getDump(model.replyTo)
+				modelData: chat.model.getDump(model.replyTo,model.id)
 				userColor: TimelineManager.userColor(modelData.userId, colors.window)
 			}
 
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index c6fc3851..86b78a1e 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -388,13 +388,8 @@ Page {
 						anchors.rightMargin: 20
 						anchors.bottom: parent.bottom
 
-<<<<<<< HEAD
 						modelData: chat.model ? chat.model.getDump(chat.model.reply, chat.model.id) : {}
-						userColor: timelineManager.userColor(modelData.userId, colors.window)
-=======
-						modelData: chat.model ? chat.model.getDump(chat.model.reply) : {}
 						userColor: TimelineManager.userColor(modelData.userId, colors.window)
->>>>>>> Fix presence indicator
 					}
 
 					ImageButton {
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index c7dbc9aa..9b53ff35 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -90,7 +90,12 @@ ApplicationWindow{
 					verticalAlignment: Text.AlignVCenter
 				}
 				onClicked: {
-					profile.verifyUser();
+					var newFlow = profile.createFlow(true);
+					newFlow.userId = profile.userid;
+					newFlow.sender = true;
+					deviceVerificationList.add(newFlow.tranId);
+					var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow,isRequest: true});
+					dialog.show();
 				}
 			}
 
@@ -192,14 +197,16 @@ ApplicationWindow{
 								id: verifyButton
 								text:(model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify"
 								onClicked: {
-									var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
-									{userId : profile.userid, sender: true, deviceId : model.deviceId});
+									var newFlow = profile.createFlow(false);
+									newFlow.userId = profile.userid;
+									newFlow.sender = true;
+									newFlow.deviceId = model.deviceId;
 									if(model.verificationStatus == VerificationStatus.VERIFIED){
 										newFlow.unverify();
 										deviceVerificationList.updateProfile(newFlow.userId);
 									}else{
 										deviceVerificationList.add(newFlow.tranId);
-										var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow});
+										var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow,isRequest:false});
 										dialog.show();
 									}
 								}
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index 8e74d1cb..f40a7b8f 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -100,7 +100,9 @@ ApplicationWindow {
                             horizontalAlignment: Text.AlignHCenter
                             verticalAlignment: Text.AlignVCenter
                         }
-						onClicked: { stack.replace(awaitingVerificationRequestAccept); flow.startVerificationRequest(); }
+						onClicked: { 
+							stack.replace(awaitingVerificationRequestAccept); 
+							isRequest?flow.sendVerificationRequest():flow.startVerificationRequest(); }
 					}
 				}
 			}
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index aba1f75d..b97b6b30 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -562,12 +562,11 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         connect(
           this, &ChatPage::tryInitialSyncCb, this, &ChatPage::tryInitialSync, Qt::QueuedConnection);
         connect(this, &ChatPage::trySyncCb, this, &ChatPage::trySync, Qt::QueuedConnection);
-        connect(
-          this,
-          &ChatPage::tryDelayedSyncCb,
-          this,
-          [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
-          Qt::QueuedConnection);
+        connect(this,
+                &ChatPage::tryDelayedSyncCb,
+                this,
+                [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
+                Qt::QueuedConnection);
 
         connect(this,
                 &ChatPage::newSyncResponse,
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index 0f521f92..5069ff9d 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -22,6 +22,11 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
         this->sas           = olm::client()->sas_init();
         this->isMacVerified = false;
 
+        connect(this->model_,
+                &TimelineModel::updateFlowEventId,
+                this,
+                [this](std::string event_id) { this->relation.in_reply_to.event_id = event_id; });
+
         connect(timeout, &QTimer::timeout, this, [this]() {
                 emit timedout();
                 this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
@@ -222,6 +227,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow
                                 if (msg.transaction_id.value() != this->transaction_id)
                                         return;
                         } else if (msg.relates_to.has_value()) {
+                                // this is just a workaround
+                                this->relation.in_reply_to.event_id =
+                                  msg.relates_to.value().in_reply_to.event_id;
                                 if (msg.relates_to.value().in_reply_to.event_id !=
                                     this->relation.in_reply_to.event_id)
                                         return;
@@ -343,11 +351,8 @@ DeviceVerificationFlow::setType(Type type)
 void
 DeviceVerificationFlow::setSender(bool sender_)
 {
-        this->sender = sender_;
-        if (this->sender == true && this->type == DeviceVerificationFlow::Type::ToDevice)
-                this->transaction_id = http::client()->generate_txn_id();
-        else if (this->sender == true && this->type == DeviceVerificationFlow::Type::RoomMsg)
-                this->relation.in_reply_to.event_id = http::client()->generate_txn_id();
+        this->sender         = sender_;
+        this->transaction_id = http::client()->generate_txn_id();
 }
 
 void
@@ -380,19 +385,16 @@ DeviceVerificationFlow::acceptVerificationRequest()
 
                 body[this->toClient][this->deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationAccept,
-                                   mtx::events::EventType::KeyVerificationAccept>(
-                    this->transaction_id, body, [](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn(
-                                      "failed to accept verification request: {} {}",
-                                      err->matrix_error.error,
-                                      static_cast<int>(err->status_code));
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationAccept>(
+                  this->transaction_id, body, [](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to accept verification request: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 }
 //! responds verification request
@@ -410,18 +412,16 @@ DeviceVerificationFlow::sendVerificationReady()
 
                 body[this->toClient][this->deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationReady,
-                                   mtx::events::EventType::KeyVerificationReady>(
-                    this->transaction_id, body, [](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn("failed to send verification ready: {} {}",
-                                                       err->matrix_error.error,
-                                                       static_cast<int>(err->status_code));
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationReady>(
+                  this->transaction_id, body, [](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to send verification ready: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 }
 //! accepts a verification
@@ -436,18 +436,16 @@ DeviceVerificationFlow::sendVerificationDone()
 
                 body[this->toClient][this->deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationDone,
-                                   mtx::events::EventType::KeyVerificationDone>(
-                    this->transaction_id, body, [](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn("failed to send verification done: {} {}",
-                                                       err->matrix_error.error,
-                                                       static_cast<int>(err->status_code));
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationDone>(
+                  this->transaction_id, body, [](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to send verification done: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 }
 //! starts the verification flow
@@ -470,19 +468,16 @@ DeviceVerificationFlow::startVerificationRequest()
                 this->canonical_json                               = nlohmann::json(req);
                 body[this->toClient][this->deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationStart,
-                                   mtx::events::EventType::KeyVerificationStart>(
-                    this->transaction_id, body, [body](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn(
-                                      "failed to start verification request: {} {}",
-                                      err->matrix_error.error,
-                                      static_cast<int>(err->status_code));
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationStart>(
+                  this->transaction_id, body, [body](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to start verification request: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 }
 //! sends a verification request
@@ -505,17 +500,20 @@ DeviceVerificationFlow::sendVerificationRequest()
 
                 body[this->toClient][this->deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationRequest,
-                                   mtx::events::EventType::KeyVerificationRequest>(
-                    this->transaction_id, body, [](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn("failed to send verification request: {} {}",
-                                                       err->matrix_error.error,
-                                                       static_cast<int>(err->status_code));
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
-                (model_.value())->sendMessage(req);
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationRequest>(
+                  this->transaction_id, body, [](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to send verification request: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
+                req.to      = this->userId.toStdString();
+                req.msgtype = "m.key.verification.request";
+                req.body = "User is requesting to verify keys with you. However, your client does "
+                           "not support this method, so you will need to use the legacy method of "
+                           "key verification.";
+                (model_)->sendMessage(req);
         }
 }
 //! cancels a verification flow
@@ -552,21 +550,18 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
 
                 body[this->toClient][deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationCancel,
-                                   mtx::events::EventType::KeyVerificationCancel>(
-                    this->transaction_id, body, [this](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn(
-                                      "failed to cancel verification request: {} {}",
-                                      err->matrix_error.error,
-                                      static_cast<int>(err->status_code));
-
-                            this->deleteLater();
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationCancel>(
+                  this->transaction_id, body, [this](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to cancel verification request: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+
+                          this->deleteLater();
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 
         // TODO : Handle Blocking user better
@@ -595,18 +590,16 @@ DeviceVerificationFlow::sendVerificationKey()
 
                 body[this->toClient][deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationKey,
-                                   mtx::events::EventType::KeyVerificationKey>(
-                    this->transaction_id, body, [](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn("failed to send verification key: {} {}",
-                                                       err->matrix_error.error,
-                                                       static_cast<int>(err->status_code));
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationKey>(
+                  this->transaction_id, body, [](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to send verification key: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 }
 //! sends the mac of the keys
@@ -639,23 +632,21 @@ DeviceVerificationFlow::sendVerificationMac()
                 req.transaction_id                           = this->transaction_id;
                 body[this->toClient][deviceId.toStdString()] = req;
 
-                http::client()
-                  ->send_to_device<mtx::events::msg::KeyVerificationMac,
-                                   mtx::events::EventType::KeyVerificationMac>(
-                    this->transaction_id, body, [this](mtx::http::RequestErr err) {
-                            if (err)
-                                    nhlog::net()->warn("failed to send verification MAC: {} {}",
-                                                       err->matrix_error.error,
-                                                       static_cast<int>(err->status_code));
-
-                            if (this->isMacVerified == true)
-                                    this->acceptDevice();
-                            else
-                                    this->isMacVerified = true;
-                    });
-        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_.has_value()) {
+                http::client()->send_to_device<mtx::events::msg::KeyVerificationMac>(
+                  this->transaction_id, body, [this](mtx::http::RequestErr err) {
+                          if (err)
+                                  nhlog::net()->warn("failed to send verification MAC: {} {}",
+                                                     err->matrix_error.error,
+                                                     static_cast<int>(err->status_code));
+
+                          if (this->isMacVerified == true)
+                                  this->acceptDevice();
+                          else
+                                  this->isMacVerified = true;
+                  });
+        } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
                 req.relates_to = this->relation;
-                (model_.value())->sendMessage(req);
+                (model_)->sendMessage(req);
         }
 }
 //! Completes the verification flow
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index bec9f1e0..1ad3b1d0 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -126,6 +126,6 @@ private:
         // for room messages
         std::optional<std::string> room_id;
         std::optional<std::string> event_id;
-        std::optional<TimelineModel *> model_;
+        TimelineModel *model_;
         mtx::common::ReplyRelatesTo relation;
 };
diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index 869687f4..24e2f35b 100644
--- a/src/EventAccessors.cpp
+++ b/src/EventAccessors.cpp
@@ -37,8 +37,15 @@ struct EventMsgType
         template<class T>
         mtx::events::MessageType operator()(const mtx::events::Event<T> &e)
         {
-                if constexpr (is_detected<msgtype_t, T>::value)
-                        return mtx::events::getMessageType(e.content.msgtype);
+                if constexpr (is_detected<msgtype_t, T>::value) {
+                        if constexpr (std::is_same_v<std::optional<std::string>,
+                                                     std::remove_cv_t<decltype(e.content.msgtype)>>)
+                                return mtx::events::getMessageType(e.content.msgtype.value());
+                        else if constexpr (std::is_same_v<
+                                             std::string,
+                                             std::remove_cv_t<decltype(e.content.msgtype)>>)
+                                return mtx::events::getMessageType(e.content.msgtype);
+                }
                 return mtx::events::MessageType::Unknown;
         }
 };
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 639cae0f..208b20e2 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -5,6 +5,7 @@
 
 #include "Cache.h"
 #include "Cache_p.h"
+#include "ChatPage.h"
 #include "EventAccessors.h"
 #include "Logging.h"
 #include "MatrixClient.h"
@@ -31,41 +32,38 @@ EventStore::EventStore(std::string room_id, QObject *)
                 this->last  = range->last;
         }
 
-        connect(
-          this,
-          &EventStore::eventFetched,
-          this,
-          [this](std::string id,
-                 std::string relatedTo,
-                 mtx::events::collections::TimelineEvents timeline) {
-                  cache::client()->storeEvent(room_id_, id, {timeline});
-
-                  if (!relatedTo.empty()) {
-                          auto idx = idToIndex(relatedTo);
-                          if (idx)
-                                  emit dataChanged(*idx, *idx);
-                  }
-          },
-          Qt::QueuedConnection);
-
-        connect(
-          this,
-          &EventStore::oldMessagesRetrieved,
-          this,
-          [this](const mtx::responses::Messages &res) {
-                  //
-                  uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res);
-                  if (newFirst == first)
-                          fetchMore();
-                  else {
-                          emit beginInsertRows(toExternalIdx(newFirst),
-                                               toExternalIdx(this->first - 1));
-                          this->first = newFirst;
-                          emit endInsertRows();
-                          emit fetchedMore();
-                  }
-          },
-          Qt::QueuedConnection);
+        connect(this,
+                &EventStore::eventFetched,
+                this,
+                [this](std::string id,
+                       std::string relatedTo,
+                       mtx::events::collections::TimelineEvents timeline) {
+                        cache::client()->storeEvent(room_id_, id, {timeline});
+
+                        if (!relatedTo.empty()) {
+                                auto idx = idToIndex(relatedTo);
+                                if (idx)
+                                        emit dataChanged(*idx, *idx);
+                        }
+                },
+                Qt::QueuedConnection);
+
+        connect(this,
+                &EventStore::oldMessagesRetrieved,
+                this,
+                [this](const mtx::responses::Messages &res) {
+                        uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res);
+                        if (newFirst == first)
+                                fetchMore();
+                        else {
+                                emit beginInsertRows(toExternalIdx(newFirst),
+                                                     toExternalIdx(this->first - 1));
+                                this->first = newFirst;
+                                emit endInsertRows();
+                                emit fetchedMore();
+                        }
+                },
+                Qt::QueuedConnection);
 
         connect(this, &EventStore::processPending, this, [this]() {
                 if (!current_txn.empty()) {
@@ -116,48 +114,46 @@ EventStore::EventStore(std::string room_id, QObject *)
                   event->data);
         });
 
-        connect(
-          this,
-          &EventStore::messageFailed,
-          this,
-          [this](std::string txn_id) {
-                  if (current_txn == txn_id) {
-                          current_txn_error_count++;
-                          if (current_txn_error_count > 10) {
-                                  nhlog::ui()->debug("failing txn id '{}'", txn_id);
-                                  cache::client()->removePendingStatus(room_id_, txn_id);
-                                  current_txn_error_count = 0;
-                          }
-                  }
-                  QTimer::singleShot(1000, this, [this]() {
-                          nhlog::ui()->debug("timeout");
-                          this->current_txn = "";
-                          emit processPending();
-                  });
-          },
-          Qt::QueuedConnection);
-
-        connect(
-          this,
-          &EventStore::messageSent,
-          this,
-          [this](std::string txn_id, std::string event_id) {
-                  nhlog::ui()->debug("sent {}", txn_id);
-
-                  http::client()->read_event(
-                    room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
-                            if (err) {
-                                    nhlog::net()->warn(
-                                      "failed to read_event ({}, {})", room_id_, event_id);
-                            }
-                    });
-
-                  cache::client()->removePendingStatus(room_id_, txn_id);
-                  this->current_txn             = "";
-                  this->current_txn_error_count = 0;
-                  emit processPending();
-          },
-          Qt::QueuedConnection);
+        connect(this,
+                &EventStore::messageFailed,
+                this,
+                [this](std::string txn_id) {
+                        if (current_txn == txn_id) {
+                                current_txn_error_count++;
+                                if (current_txn_error_count > 10) {
+                                        nhlog::ui()->debug("failing txn id '{}'", txn_id);
+                                        cache::client()->removePendingStatus(room_id_, txn_id);
+                                        current_txn_error_count = 0;
+                                }
+                        }
+                        QTimer::singleShot(1000, this, [this]() {
+                                nhlog::ui()->debug("timeout");
+                                this->current_txn = "";
+                                emit processPending();
+                        });
+                },
+                Qt::QueuedConnection);
+
+        connect(this,
+                &EventStore::messageSent,
+                this,
+                [this](std::string txn_id, std::string event_id) {
+                        nhlog::ui()->debug("sent {}", txn_id);
+
+                        http::client()->read_event(
+                          room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
+                                  if (err) {
+                                          nhlog::net()->warn(
+                                            "failed to read_event ({}, {})", room_id_, event_id);
+                                  }
+                          });
+
+                        cache::client()->removePendingStatus(room_id_, txn_id);
+                        this->current_txn             = "";
+                        this->current_txn_error_count = 0;
+                        emit processPending();
+                },
+                Qt::QueuedConnection);
 }
 
 void
@@ -245,6 +241,58 @@ EventStore::handleSync(const mtx::responses::Timeline &events)
                                 emit dataChanged(toExternalIdx(*idx), toExternalIdx(*idx));
                         }
                 }
+
+                // decrypting and checking some encrypted messages
+                if (auto encrypted =
+                      std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
+                        &event)) {
+                        auto event = decryptEvent({room_id_, encrypted->event_id}, *encrypted);
+                        if (std::visit(
+                              [](auto e) { return (e.sender != utils::localUser().toStdString()); },
+                              *event)) {
+                                if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                      mtx::events::msg::KeyVerificationRequest>>(event)) {
+                                        last_verification_request_event = *msg;
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationCancel>>(event)) {
+                                        last_verification_cancel_event = *msg;
+                                        ChatPage::instance()->recievedDeviceVerificationCancel(
+                                          msg->content);
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationAccept>>(event)) {
+                                        ChatPage::instance()->recievedDeviceVerificationAccept(
+                                          msg->content);
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationKey>>(event)) {
+                                        ChatPage::instance()->recievedDeviceVerificationKey(
+                                          msg->content);
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationMac>>(event)) {
+                                        ChatPage::instance()->recievedDeviceVerificationMac(
+                                          msg->content);
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationReady>>(event)) {
+                                        ChatPage::instance()->recievedDeviceVerificationReady(
+                                          msg->content);
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationDone>>(event)) {
+                                        ChatPage::instance()->recievedDeviceVerificationDone(
+                                          msg->content);
+                                } else if (auto msg = std::get_if<mtx::events::RoomEvent<
+                                             mtx::events::msg::KeyVerificationStart>>(event)) {
+                                        ChatPage::instance()->recievedDeviceVerificationStart(
+                                          msg->content, msg->sender);
+                                }
+                        }
+                }
+        }
+
+        if (last_verification_request_event.has_value()) {
+                if (last_verification_request_event.value().origin_server_ts >
+                    last_verification_cancel_event.origin_server_ts) {
+                        emit startDMVerification(last_verification_request_event.value());
+                        last_verification_request_event = {};
+                }
         }
 }
 
@@ -425,7 +473,8 @@ EventStore::decryptEvent(const IdIndex &idx,
                                       e.what());
                 dummy.content.body =
                   tr("-- Decryption Error (failed to retrieve megolm keys from db) --",
-                     "Placeholder, when the message can't be decrypted, because the DB access "
+                     "Placeholder, when the message can't be decrypted, because the DB "
+                     "access "
                      "failed.")
                     .toStdString();
                 return asCacheEntry(std::move(dummy));
@@ -437,7 +486,8 @@ EventStore::decryptEvent(const IdIndex &idx,
                                           e.what());
                 dummy.content.body =
                   tr("-- Decryption Error (%1) --",
-                     "Placeholder, when the message can't be decrypted. In this case, the Olm "
+                     "Placeholder, when the message can't be decrypted. In this case, the "
+                     "Olm "
                      "decrytion returned an error, which is passed as %1.")
                     .arg(e.what())
                     .toStdString();
@@ -470,11 +520,11 @@ EventStore::decryptEvent(const IdIndex &idx,
                 return asCacheEntry(std::move(temp_events[0]));
         }
 
-        dummy.content.body =
-          tr("-- Encrypted Event (Unknown event type) --",
-             "Placeholder, when the message was decrypted, but we couldn't parse it, because "
-             "Nheko/mtxclient don't support that event type yet.")
-            .toStdString();
+        dummy.content.body = tr("-- Encrypted Event (Unknown event type) --",
+                                "Placeholder, when the message was decrypted, but we "
+                                "couldn't parse it, because "
+                                "Nheko/mtxclient don't support that event type yet.")
+                               .toStdString();
         return asCacheEntry(std::move(dummy));
 }
 
@@ -502,7 +552,8 @@ EventStore::get(std::string_view id, std::string_view related_to, bool decrypt)
                                           mtx::http::RequestErr err) {
                                   if (err) {
                                           nhlog::net()->error(
-                                            "Failed to retrieve event with id {}, which was "
+                                            "Failed to retrieve event with id {}, which "
+                                            "was "
                                             "requested to show the replyTo for event {}",
                                             relatedTo,
                                             id);
diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h
index b5c17d10..28d46e90 100644
--- a/src/timeline/EventStore.h
+++ b/src/timeline/EventStore.h
@@ -98,6 +98,8 @@ signals:
         void processPending();
         void messageSent(std::string txn_id, std::string event_id);
         void messageFailed(std::string txn_id);
+        void startDMVerification(
+          mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &msg);
 
 public slots:
         void addPending(mtx::events::collections::TimelineEvents event);
@@ -118,4 +120,10 @@ private:
 
         std::string current_txn;
         int current_txn_error_count = 0;
+
+        // probably not the best way to do
+        std::optional<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest>>
+          last_verification_request_event;
+        mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel>
+          last_verification_cancel_event;
 };
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index adf207ac..809fe382 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -186,12 +186,11 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
   , room_id_(room_id)
   , manager_(manager)
 {
-        connect(
-          this,
-          &TimelineModel::redactionFailed,
-          this,
-          [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
-          Qt::QueuedConnection);
+        connect(this,
+                &TimelineModel::redactionFailed,
+                this,
+                [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
+                Qt::QueuedConnection);
 
         connect(this,
                 &TimelineModel::newMessageToSend,
@@ -200,17 +199,17 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
                 Qt::QueuedConnection);
         connect(this, &TimelineModel::addPendingMessageToStore, &events, &EventStore::addPending);
 
-        connect(
-          &events,
-          &EventStore::dataChanged,
-          this,
-          [this](int from, int to) {
-                  nhlog::ui()->debug(
-                    "data changed {} to {}", events.size() - to - 1, events.size() - from - 1);
-                  emit dataChanged(index(events.size() - to - 1, 0),
-                                   index(events.size() - from - 1, 0));
-          },
-          Qt::QueuedConnection);
+        connect(&events,
+                &EventStore::dataChanged,
+                this,
+                [this](int from, int to) {
+                        nhlog::ui()->debug("data changed {} to {}",
+                                           events.size() - to - 1,
+                                           events.size() - from - 1);
+                        emit dataChanged(index(events.size() - to - 1, 0),
+                                         index(events.size() - from - 1, 0));
+                },
+                Qt::QueuedConnection);
 
         connect(&events, &EventStore::beginInsertRows, this, [this](int from, int to) {
                 int first = events.size() - to;
@@ -232,6 +231,12 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
         connect(&events, &EventStore::newEncryptedImage, this, &TimelineModel::newEncryptedImage);
         connect(
           &events, &EventStore::fetchedMore, this, [this]() { setPaginationInProgress(false); });
+        connect(&events,
+                &EventStore::startDMVerification,
+                this,
+                [this](mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> msg) {
+                        ChatPage::instance()->recievedRoomDeviceVerificationRequest(msg, this);
+                });
 }
 
 QHash<int, QByteArray>
@@ -613,187 +618,6 @@ TimelineModel::updateLastMessage()
         }
 }
 
-std::vector<QString>
-TimelineModel::internalAddEvents(
-  const std::vector<mtx::events::collections::TimelineEvents> &timeline)
-{
-        std::vector<QString> ids;
-        for (auto e : timeline) {
-                QString id = QString::fromStdString(mtx::accessors::event_id(e));
-
-                if (this->events.contains(id)) {
-                        this->events.insert(id, e);
-                        int idx = idToIndex(id);
-                        emit dataChanged(index(idx, 0), index(idx, 0));
-                        continue;
-                }
-
-                QString txid = QString::fromStdString(mtx::accessors::transaction_id(e));
-                if (this->pending.removeOne(txid)) {
-                        this->events.insert(id, e);
-                        this->events.remove(txid);
-                        int idx = idToIndex(txid);
-                        if (idx < 0) {
-                                nhlog::ui()->warn("Received index out of range");
-                                continue;
-                        }
-                        eventOrder[idx] = id;
-                        emit dataChanged(index(idx, 0), index(idx, 0));
-                        continue;
-                }
-
-                if (auto redaction =
-                      std::get_if<mtx::events::RedactionEvent<mtx::events::msg::Redaction>>(&e)) {
-                        QString redacts = QString::fromStdString(redaction->redacts);
-                        auto redacted   = std::find(eventOrder.begin(), eventOrder.end(), redacts);
-
-                        auto event = events.value(redacts);
-                        if (auto reaction =
-                              std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(
-                                &event)) {
-                                QString reactedTo =
-                                  QString::fromStdString(reaction->content.relates_to.event_id);
-                                reactions[reactedTo].removeReaction(*reaction);
-                                int idx = idToIndex(reactedTo);
-                                if (idx >= 0)
-                                        emit dataChanged(index(idx, 0), index(idx, 0));
-                        }
-
-                        if (redacted != eventOrder.end()) {
-                                auto redactedEvent = std::visit(
-                                  [](const auto &ev)
-                                    -> mtx::events::RoomEvent<mtx::events::msg::Redacted> {
-                                          mtx::events::RoomEvent<mtx::events::msg::Redacted>
-                                            replacement                = {};
-                                          replacement.event_id         = ev.event_id;
-                                          replacement.room_id          = ev.room_id;
-                                          replacement.sender           = ev.sender;
-                                          replacement.origin_server_ts = ev.origin_server_ts;
-                                          replacement.type             = ev.type;
-                                          return replacement;
-                                  },
-                                  e);
-                                events.insert(redacts, redactedEvent);
-
-                                int row = (int)std::distance(eventOrder.begin(), redacted);
-                                emit dataChanged(index(row, 0), index(row, 0));
-                        }
-
-                        continue; // don't insert redaction into timeline
-                }
-
-                if (auto reaction =
-                      std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(&e)) {
-                        QString reactedTo =
-                          QString::fromStdString(reaction->content.relates_to.event_id);
-                        events.insert(id, e);
-
-                        // remove local echo
-                        if (!txid.isEmpty()) {
-                                auto rCopy     = *reaction;
-                                rCopy.event_id = txid.toStdString();
-                                reactions[reactedTo].removeReaction(rCopy);
-                        }
-
-                        reactions[reactedTo].addReaction(room_id_.toStdString(), *reaction);
-                        int idx = idToIndex(reactedTo);
-                        if (idx >= 0)
-                                emit dataChanged(index(idx, 0), index(idx, 0));
-                        continue; // don't insert reaction into timeline
-                }
-
-                if (auto event =
-                      std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(&e)) {
-                        auto e_      = decryptEvent(*event).event;
-                        auto encInfo = mtx::accessors::file(e_);
-
-                        if (encInfo)
-                                emit newEncryptedImage(encInfo.value());
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest>>(
-                              &e_)) {
-                                last_verification_request_event = *msg;
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel>>(
-                              &e_)) {
-                                last_verification_cancel_event = *msg;
-                                ChatPage::instance()->recievedDeviceVerificationCancel(
-                                  msg->content);
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept>>(
-                              &e_)) {
-                                ChatPage::instance()->recievedDeviceVerificationAccept(
-                                  msg->content);
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey>>(&e_)) {
-                                ChatPage::instance()->recievedDeviceVerificationKey(msg->content);
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac>>(&e_)) {
-                                ChatPage::instance()->recievedDeviceVerificationMac(msg->content);
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady>>(
-                              &e_)) {
-                                ChatPage::instance()->recievedDeviceVerificationReady(msg->content);
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone>>(&e_)) {
-                                ChatPage::instance()->recievedDeviceVerificationDone(msg->content);
-                        }
-
-                        if (auto msg = std::get_if<
-                              mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart>>(
-                              &e_)) {
-                                ChatPage::instance()->recievedDeviceVerificationStart(msg->content,
-                                                                                      msg->sender);
-                        }
-                }
-
-                this->events.insert(id, e);
-                ids.push_back(id);
-
-                auto replyTo  = mtx::accessors::in_reply_to_event(e);
-                auto qReplyTo = QString::fromStdString(replyTo);
-                if (!replyTo.empty() && !events.contains(qReplyTo)) {
-                        http::client()->get_event(
-                          this->room_id_.toStdString(),
-                          replyTo,
-                          [this, id, replyTo](
-                            const mtx::events::collections::TimelineEvents &timeline,
-                            mtx::http::RequestErr err) {
-                                  if (err) {
-                                          nhlog::net()->error(
-                                            "Failed to retrieve event with id {}, which was "
-                                            "requested to show the replyTo for event {}",
-                                            replyTo,
-                                            id.toStdString());
-                                          return;
-                                  }
-                                  emit eventFetched(id, timeline);
-                          });
-                }
-        }
-
-        if (last_verification_request_event.origin_server_ts >
-            last_verification_cancel_event.origin_server_ts) {
-                ChatPage::instance()->recievedRoomDeviceVerificationRequest(
-                  last_verification_request_event, this);
-        }
-
-        return ids;
-}
-
 void
 TimelineModel::setCurrentIndex(int index)
 {
@@ -979,15 +803,18 @@ TimelineModel::markEventsAsRead(const std::vector<QString> &event_ids)
         }
 }
 
+template<typename T>
 void
-TimelineModel::sendEncryptedMessage(const std::string txn_id, nlohmann::json content)
+TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg)
 {
         const auto room_id = room_id_.toStdString();
 
         using namespace mtx::events;
         using namespace mtx::identifiers;
 
-        json doc = {{"type", "m.room.message"}, {"content", content}, {"room_id", room_id}};
+        json doc = {
+          {"type", to_string(msg.type)}, {"content", json(msg.content)}, {"room_id", room_id}};
+        std::cout << doc.dump(2) << std::endl;
 
         try {
                 // Check if we have already an outbound megolm session then we can use.
@@ -995,7 +822,7 @@ TimelineModel::sendEncryptedMessage(const std::string txn_id, nlohmann::json con
                         mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> event;
                         event.content =
                           olm::encrypt_group_message(room_id, http::client()->device_id(), doc);
-                        event.event_id         = txn_id;
+                        event.event_id         = msg.event_id;
                         event.room_id          = room_id;
                         event.sender           = http::client()->user_id().to_string();
                         event.type             = mtx::events::EventType::RoomEncrypted;
@@ -1030,25 +857,26 @@ TimelineModel::sendEncryptedMessage(const std::string txn_id, nlohmann::json con
                 const auto members = cache::roomMembers(room_id);
                 nhlog::ui()->info("retrieved {} members for {}", members.size(), room_id);
 
-                auto keeper = std::make_shared<StateKeeper>([room_id, doc, txn_id, this]() {
-                        try {
-                                mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> event;
-                                event.content = olm::encrypt_group_message(
-                                  room_id, http::client()->device_id(), doc);
-                                event.event_id         = txn_id;
-                                event.room_id          = room_id;
-                                event.sender           = http::client()->user_id().to_string();
-                                event.type             = mtx::events::EventType::RoomEncrypted;
-                                event.origin_server_ts = QDateTime::currentMSecsSinceEpoch();
-
-                                emit this->addPendingMessageToStore(event);
-                        } catch (const lmdb::error &e) {
-                                nhlog::db()->critical("failed to save megolm outbound session: {}",
-                                                      e.what());
-                                emit ChatPage::instance()->showNotification(
-                                  tr("Failed to encrypt event, sending aborted!"));
-                        }
-                });
+                auto keeper =
+                  std::make_shared<StateKeeper>([room_id, doc, txn_id = msg.event_id, this]() {
+                          try {
+                                  mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> event;
+                                  event.content = olm::encrypt_group_message(
+                                    room_id, http::client()->device_id(), doc);
+                                  event.event_id         = txn_id;
+                                  event.room_id          = room_id;
+                                  event.sender           = http::client()->user_id().to_string();
+                                  event.type             = mtx::events::EventType::RoomEncrypted;
+                                  event.origin_server_ts = QDateTime::currentMSecsSinceEpoch();
+
+                                  emit this->addPendingMessageToStore(event);
+                          } catch (const lmdb::error &e) {
+                                  nhlog::db()->critical(
+                                    "failed to save megolm outbound session: {}", e.what());
+                                  emit ChatPage::instance()->showNotification(
+                                    tr("Failed to encrypt event, sending aborted!"));
+                          }
+                  });
 
                 mtx::requests::QueryKeys req;
                 for (const auto &member : members)
@@ -1056,7 +884,7 @@ TimelineModel::sendEncryptedMessage(const std::string txn_id, nlohmann::json con
 
                 http::client()->query_keys(
                   req,
-                  [keeper = std::move(keeper), megolm_payload, txn_id, this](
+                  [keeper = std::move(keeper), megolm_payload, txn_id = msg.event_id, this](
                     const mtx::responses::QueryKeys &res, mtx::http::RequestErr err) {
                           if (err) {
                                   nhlog::net()->warn("failed to query device keys: {} {}",
@@ -1265,6 +1093,40 @@ struct SendMessageVisitor
           : model_(model)
         {}
 
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &msg)
+        {
+                emit model_->updateFlowEventId(msg.event_id);
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+        void operator()(const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel> &msg)
+        {
+                model_->sendEncryptedMessage(msg);
+        }
+
         // Do-nothing operator for all unhandled events
         template<typename T>
         void operator()(const mtx::events::Event<T> &)
@@ -1280,7 +1142,7 @@ struct SendMessageVisitor
                         if (encInfo)
                                 emit model_->newEncryptedImage(encInfo.value());
 
-                        model_->sendEncryptedMessage(msg.event_id, nlohmann::json(msg.content));
+                        model_->sendEncryptedMessage(msg);
                 } else {
                         emit model_->addPendingMessageToStore(msg);
                 }
@@ -1301,20 +1163,6 @@ struct SendMessageVisitor
 };
 
 void
-TimelineModel::processOnePendingMessage()
-{
-        if (pending.isEmpty())
-                return;
-
-        QString txn_id_qstr = pending.first();
-
-        auto event = events.value(txn_id_qstr);
-        std::cout << "Inside the process one pending message" << std::endl;
-        std::cout << std::visit([](auto &e) { return json(e); }, event).dump(2) << std::endl;
-        std::visit(SendMessageVisitor{txn_id_qstr, this}, event);
-}
-
-void
 TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event)
 {
         std::visit(
@@ -1359,18 +1207,7 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event)
                   event);
         }
 
-        internalAddEvents({event});
-
-        QString txn_id_qstr = QString::fromStdString(mtx::accessors::event_id(event));
-        pending.push_back(txn_id_qstr);
-        if (!std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(&event)) {
-                beginInsertRows(QModelIndex(), 0, 0);
-                this->eventOrder.insert(this->eventOrder.begin(), txn_id_qstr);
-                endInsertRows();
-        }
-        updateLastMessage();
-
-        emit nextPendingMessage();
+        std::visit(SendMessageVisitor{this}, event);
 }
 
 bool
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index 1b6f999e..fb9921d3 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -9,12 +9,8 @@
 #include <mtxclient/http/errors.hpp>
 
 #include "CacheCryptoStructs.h"
-<<<<<<< HEAD
 #include "EventStore.h"
-=======
-#include "ReactionsModel.h"
 #include "ui/UserProfile.h"
->>>>>>> Refactor UserProfile
 
 namespace mtx::http {
 using RequestErr = const std::optional<mtx::http::ClientError> &;
@@ -271,8 +267,13 @@ signals:
 
         void openProfile(UserProfile *profile);
 
+        void newMessageToSend(mtx::events::collections::TimelineEvents event);
+        void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
+        void updateFlowEventId(std::string event_id);
+
 private:
-        void sendEncryptedMessage(const std::string txn_id, nlohmann::json content);
+        template<typename T>
+        void sendEncryptedMessage(mtx::events::RoomEvent<T> msg);
         void handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
                                const std::map<std::string, std::string> &room_key,
                                const std::map<std::string, DevicePublicKeys> &pks,
@@ -297,11 +298,6 @@ private:
         std::vector<QString> typingUsers_;
 
         TimelineViewManager *manager_;
-        // probably not the best way to do
-        mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest>
-          last_verification_request_event;
-        mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel>
-          last_verification_cancel_event;
 
         friend struct SendMessageVisitor;
 };
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 3499384c..1eaa9d27 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -5,13 +5,15 @@
 #include "Logging.h"
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
+#include "timeline/TimelineModel.h"
 
 #include <iostream> // only for debugging
 
-UserProfile::UserProfile(QString roomid, QString userid, QObject *parent)
+UserProfile::UserProfile(QString roomid, QString userid, TimelineModel *parent)
   : QObject(parent)
   , roomid_(roomid)
   , userid_(userid)
+  , model(parent)
 {
         fetchDeviceList(this->userid_);
 }
@@ -185,27 +187,43 @@ UserProfile::startChat()
         emit ChatPage::instance()->createRoom(req);
 }
 
-void
-UserProfile::verifyUser()
+DeviceVerificationFlow *
+UserProfile::createFlow(bool isVerifyUser)
 {
-        std::cout << "Checking if to start to device verification or room message verification"
-                  << std::endl;
-        auto joined_rooms = cache::joinedRooms();
-        auto room_infos   = cache::getRoomInfo(joined_rooms);
-
-        for (std::string room_id : joined_rooms) {
-                if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
-                    cache::isRoomEncrypted(room_id)) {
-                        auto room_members = cache::roomMembers(room_id);
-                        if (std::find(room_members.begin(),
-                                      room_members.end(),
-                                      (this->userid()).toStdString()) != room_members.end()) {
-                                std::cout << "FOUND A ENCRYPTED ROOM WITH THIS USER : " << room_id
+        if (!isVerifyUser)
+                return (new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::ToDevice));
+        else {
+                std::cout << "CHECKING IF IT TO START ROOM_VERIFICATION OR TO_DEVICE VERIFICATION"
+                          << std::endl;
+                auto joined_rooms = cache::joinedRooms();
+                auto room_infos   = cache::getRoomInfo(joined_rooms);
+
+                for (std::string room_id : joined_rooms) {
+                        if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
+                            cache::isRoomEncrypted(room_id)) {
+                                auto room_members = cache::roomMembers(room_id);
+                                if (std::find(room_members.begin(),
+                                              room_members.end(),
+                                              (this->userid()).toStdString()) !=
+                                    room_members.end()) {
+                                        std::cout
+                                          << "FOUND A ENCRYPTED ROOM WITH THIS USER : " << room_id
                                           << std::endl;
-                                return;
+                                        if (this->roomid_.toStdString() == room_id) {
+                                                auto newflow = new DeviceVerificationFlow(
+                                                  this, DeviceVerificationFlow::Type::RoomMsg);
+                                                newflow->setModel(this->model);
+                                                return (std::move(newflow));
+                                        } else {
+                                                std::cout << "FOUND A ENCRYPTED ROOM BUT CURRENTLY "
+                                                             "NOT IN THAT ROOM : "
+                                                          << room_id << std::endl;
+                                        }
+                                }
                         }
                 }
-        }
 
-        std::cout << "DIDN'T FIND A ENCRYPTED ROOM WITH THIS USER" << std::endl;
+                std::cout << "DIDN'T FIND A ENCRYPTED ROOM WITH THIS USER" << std::endl;
+                return (new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::ToDevice));
+        }
 }
\ No newline at end of file
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 3f9cbe6f..3d0d2981 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -20,6 +20,7 @@ Q_ENUM_NS(Status)
 }
 
 class DeviceVerificationFlow;
+class TimelineModel;
 
 class DeviceInfo
 {
@@ -83,7 +84,7 @@ class UserProfile : public QObject
         Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
         Q_PROPERTY(bool isUserVerified READ getUserStatus CONSTANT)
 public:
-        UserProfile(QString roomid, QString userid, QObject *parent = 0);
+        UserProfile(QString roomid, QString userid, TimelineModel *parent = nullptr);
 
         DeviceInfoModel *deviceList();
 
@@ -92,18 +93,19 @@ public:
         QString avatarUrl();
         bool getUserStatus();
 
+        Q_INVOKABLE DeviceVerificationFlow *createFlow(bool isVerifyUser);
         Q_INVOKABLE void fetchDeviceList(const QString &userID);
         Q_INVOKABLE void banUser();
         // Q_INVOKABLE void ignoreUser();
         Q_INVOKABLE void kickUser();
         Q_INVOKABLE void startChat();
-        Q_INVOKABLE void verifyUser();
 
 private:
         QString roomid_, userid_;
         std::optional<std::string> cross_verified;
         DeviceInfoModel deviceList_;
         bool isUserVerified = false;
+        TimelineModel *model;
 
         void callback_fn(const mtx::responses::QueryKeys &res,
                          mtx::http::RequestErr err,