From a605e4486f4b9d90d668d6d1844ba5f0d58bbc26 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Mon, 4 Dec 2017 18:41:19 +0200 Subject: [PATCH] Migrate to matrix-structs for event and response parsing --- .ci/linux/gtest.sh | 19 - .ci/linux/run-tests.sh | 7 - .travis.yml | 3 - CMakeLists.txt | 58 +- Makefile | 9 +- include/ChatPage.h | 71 +- include/MatrixClient.h | 15 +- include/RoomState.h | 96 ++- include/Sync.h | 131 ---- include/TextInputWidget.h | 3 - include/events/AliasesEventContent.h | 42 -- include/events/AvatarEventContent.h | 46 -- include/events/CanonicalAliasEventContent.h | 48 -- include/events/CreateEventContent.h | 47 -- include/events/Event.h | 183 ----- .../events/HistoryVisibilityEventContent.h | 49 -- include/events/JoinRulesEventContent.h | 61 -- include/events/MemberEventContent.h | 68 -- include/events/MessageEvent.h | 64 -- include/events/MessageEventContent.h | 74 -- include/events/NameEventContent.h | 45 -- include/events/PowerLevelsEventContent.h | 73 -- include/events/RoomEvent.h | 116 --- include/events/StateEvent.h | 88 --- include/events/TopicEventContent.h | 46 -- include/events/messages/Audio.h | 50 -- include/events/messages/Emote.h | 34 - include/events/messages/File.h | 55 -- include/events/messages/Image.h | 54 -- include/events/messages/Location.h | 50 -- include/events/messages/Notice.h | 34 - include/events/messages/Text.h | 34 - include/events/messages/Video.h | 55 -- include/timeline/TimelineItem.h | 43 +- include/timeline/TimelineView.h | 86 +-- include/timeline/TimelineViewManager.h | 10 +- include/timeline/widgets/AudioItem.h | 9 +- include/timeline/widgets/FileItem.h | 11 +- include/timeline/widgets/ImageItem.h | 11 +- include/timeline/widgets/VideoItem.h | 9 +- libs/matrix-structs | 2 +- src/Cache.cc | 65 +- src/ChatPage.cc | 280 +++---- src/MatrixClient.cc | 56 +- src/RoomList.cc | 1 - src/RoomState.cc | 316 +++----- src/Sync.cc | 307 -------- src/events/AliasesEventContent.cc | 55 -- src/events/AvatarEventContent.cc | 50 -- src/events/CanonicalAliasEventContent.cc | 45 -- src/events/CreateEventContent.cc | 45 -- src/events/Event.cc | 106 --- src/events/HistoryVisibilityEventContent.cc | 64 -- src/events/JoinRulesEventContent.cc | 63 -- src/events/MemberEventContent.cc | 84 --- src/events/MessageEventContent.cc | 74 -- src/events/NameEventContent.cc | 45 -- src/events/PowerLevelsEventContent.cc | 114 --- src/events/TopicEventContent.cc | 45 -- src/events/messages/Audio.cc | 40 - src/events/messages/Emote.cc | 27 - src/events/messages/File.cc | 50 -- src/events/messages/Image.cc | 52 -- src/events/messages/Location.cc | 47 -- src/events/messages/Notice.cc | 27 - src/events/messages/Text.cc | 27 - src/events/messages/Video.cc | 53 -- src/timeline/TimelineItem.cc | 79 +- src/timeline/TimelineView.cc | 200 +++-- src/timeline/TimelineViewManager.cc | 29 +- src/timeline/widgets/AudioItem.cc | 15 +- src/timeline/widgets/FileItem.cc | 15 +- src/timeline/widgets/ImageItem.cc | 13 +- src/timeline/widgets/VideoItem.cc | 11 +- tests/event_collection.cc | 111 --- tests/events.cc | 707 ------------------ tests/message_events.cc | 287 ------- 77 files changed, 650 insertions(+), 4964 deletions(-) delete mode 100755 .ci/linux/gtest.sh delete mode 100755 .ci/linux/run-tests.sh delete mode 100644 include/Sync.h delete mode 100644 include/events/AliasesEventContent.h delete mode 100644 include/events/AvatarEventContent.h delete mode 100644 include/events/CanonicalAliasEventContent.h delete mode 100644 include/events/CreateEventContent.h delete mode 100644 include/events/Event.h delete mode 100644 include/events/HistoryVisibilityEventContent.h delete mode 100644 include/events/JoinRulesEventContent.h delete mode 100644 include/events/MemberEventContent.h delete mode 100644 include/events/MessageEvent.h delete mode 100644 include/events/MessageEventContent.h delete mode 100644 include/events/NameEventContent.h delete mode 100644 include/events/PowerLevelsEventContent.h delete mode 100644 include/events/RoomEvent.h delete mode 100644 include/events/StateEvent.h delete mode 100644 include/events/TopicEventContent.h delete mode 100644 include/events/messages/Audio.h delete mode 100644 include/events/messages/Emote.h delete mode 100644 include/events/messages/File.h delete mode 100644 include/events/messages/Image.h delete mode 100644 include/events/messages/Location.h delete mode 100644 include/events/messages/Notice.h delete mode 100644 include/events/messages/Text.h delete mode 100644 include/events/messages/Video.h delete mode 100644 src/Sync.cc delete mode 100644 src/events/AliasesEventContent.cc delete mode 100644 src/events/AvatarEventContent.cc delete mode 100644 src/events/CanonicalAliasEventContent.cc delete mode 100644 src/events/CreateEventContent.cc delete mode 100644 src/events/Event.cc delete mode 100644 src/events/HistoryVisibilityEventContent.cc delete mode 100644 src/events/JoinRulesEventContent.cc delete mode 100644 src/events/MemberEventContent.cc delete mode 100644 src/events/MessageEventContent.cc delete mode 100644 src/events/NameEventContent.cc delete mode 100644 src/events/PowerLevelsEventContent.cc delete mode 100644 src/events/TopicEventContent.cc delete mode 100644 src/events/messages/Audio.cc delete mode 100644 src/events/messages/Emote.cc delete mode 100644 src/events/messages/File.cc delete mode 100644 src/events/messages/Image.cc delete mode 100644 src/events/messages/Location.cc delete mode 100644 src/events/messages/Notice.cc delete mode 100644 src/events/messages/Text.cc delete mode 100644 src/events/messages/Video.cc delete mode 100644 tests/event_collection.cc delete mode 100644 tests/events.cc delete mode 100644 tests/message_events.cc diff --git a/.ci/linux/gtest.sh b/.ci/linux/gtest.sh deleted file mode 100755 index 8dd7084..0000000 --- a/.ci/linux/gtest.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -set -evx - -sudo apt-get -qq update -sudo apt-get install -y libgtest-dev -wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz -tar xf release-1.8.0.tar.gz -cd googletest-release-1.8.0 - -cmake -DBUILD_SHARED_LIBS=ON . -make -sudo cp -a googletest/include/gtest /usr/include -sudo cp -a googlemock/gtest/*.so /usr/lib/ - -sudo ldconfig -v | grep gtest - -cd $TRAVIS_BUILD_DIR - diff --git a/.ci/linux/run-tests.sh b/.ci/linux/run-tests.sh deleted file mode 100755 index dc9e303..0000000 --- a/.ci/linux/run-tests.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -evx - -cmake -DBUILD_TESTS=ON -H. -Bbuild && cmake --build build - -cd build && GTEST_COLOR=1 ctest --verbose diff --git a/.travis.yml b/.travis.yml index c0f0ed1..ba45a88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ matrix: compiler: gcc env: - COMPILER=g++-6 - - RUN_TESTS=1 addons: apt: sources: ['ubuntu-toolchain-r-test'] @@ -30,7 +29,6 @@ matrix: before_install: - export CXX=${COMPILER} - - if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/gtest.sh; fi install: - if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install qt5 lmdb clang-format; fi @@ -45,7 +43,6 @@ script: - make -C build -j2 - if [ $TRAVIS_OS_NAME == osx ]; then make lint; fi - if [ $TRAVIS_OS_NAME == osx ]; then ./.ci/macos/deploy.sh; fi - - if [ $RUN_TESTS == 1 ]; then ./.ci/linux/run-tests.sh; fi - if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/deploy.sh; fi deploy: diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d518fe..69efeed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 3.1) -option(BUILD_TESTS "Build all tests" OFF) option(APPVEYOR_BUILD "Build on appveyor" OFF) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) @@ -122,6 +121,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") -Werror \ -pipe \ -pedantic \ + -ferror-limit=3 \ -Wunreachable-code") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") @@ -200,7 +200,6 @@ set(SRC_FILES src/RoomState.cc src/SideBarActions.cc src/Splitter.cc - src/Sync.cc src/TextInputWidget.cc src/TopRoomBar.cc src/TrayIcon.cc @@ -211,35 +210,8 @@ set(SRC_FILES src/main.cc ) -set(MATRIX_EVENTS - src/events/Event.cc - - src/events/AliasesEventContent.cc - src/events/AvatarEventContent.cc - src/events/CanonicalAliasEventContent.cc - src/events/CreateEventContent.cc - src/events/HistoryVisibilityEventContent.cc - src/events/JoinRulesEventContent.cc - src/events/MemberEventContent.cc - src/events/MessageEventContent.cc - src/events/NameEventContent.cc - src/events/PowerLevelsEventContent.cc - src/events/TopicEventContent.cc - - src/events/messages/Audio.cc - src/events/messages/Emote.cc - src/events/messages/File.cc - src/events/messages/Image.cc - src/events/messages/Location.cc - src/events/messages/Notice.cc - src/events/messages/Text.cc - src/events/messages/Video.cc -) - include_directories(include) include_directories(include/ui) -include_directories(include/events) -include_directories(include/events/messages) include_directories(libs/lmdbxx) include_directories(${LMDB_INCLUDE_DIR}) @@ -324,35 +296,9 @@ file(APPEND ${_qrc} " ") qt5_add_resources(LANG_QRC ${_qrc}) qt5_add_resources(QRC resources/res.qrc) -# -# Matrix events library. -# -add_library(matrix_events ${MATRIX_EVENTS} src/Deserializable.cc) -target_link_libraries(matrix_events Qt5::Core) - add_subdirectory(libs/matrix-structs) -if (BUILD_TESTS) - enable_testing() - - find_package(GTest REQUIRED) - include_directories(${GTEST_INCLUDE_DIRS}) - - add_executable(events_test tests/events.cc) - target_link_libraries(events_test matrix_events ${GTEST_BOTH_LIBRARIES}) - - add_executable(event_collection_test tests/event_collection.cc) - target_link_libraries(event_collection_test matrix_events ${GTEST_BOTH_LIBRARIES}) - - add_executable(message_events tests/message_events.cc) - target_link_libraries(message_events matrix_events ${GTEST_BOTH_LIBRARIES}) - - add_test(MatrixEvents events_test) - add_test(MatrixEventCollection event_collection_test) - add_test(MatrixMessageEvents message_events) -endif() - -set(COMMON_LIBS matrix_events matrix_structs Qt5::Widgets Qt5::Network Qt5::Concurrent) +set(COMMON_LIBS matrix_structs Qt5::Widgets Qt5::Network Qt5::Concurrent) if(APPVEYOR_BUILD) set(NHEKO_LIBS ${COMMON_LIBS} lmdb) diff --git a/Makefile b/Makefile index 1a23d6b..fbbbed9 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,12 @@ debug: - @cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug + @cmake -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug @cmake --build build release-debug: - @cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo + @cmake -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo @cmake --build build -test: - @cmake -DBUILD_TESTS=ON -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo - @cmake --build build - @cd build && GTEST_COLOR=1 ctest --verbose - linux-appimage: @./.ci/linux/deploy.sh diff --git a/include/ChatPage.h b/include/ChatPage.h index 01f6c5d..94c54f0 100644 --- a/include/ChatPage.h +++ b/include/ChatPage.h @@ -24,9 +24,7 @@ #include #include -#include "MemberEventContent.h" -#include "MessageEvent.h" -#include "StateEvent.h" +#include class Cache; class MatrixClient; @@ -37,14 +35,11 @@ class RoomSettings; class RoomState; class SideBarActions; class Splitter; -class SyncResponse; class TextInputWidget; class TimelineViewManager; class TopRoomBar; class TypingDisplay; class UserInfoWidget; -class JoinedRoom; -class LeftRoom; constexpr int CONSENSUS_TIMEOUT = 1000; constexpr int SHOW_CONTENT_TIMEOUT = 3000; @@ -76,8 +71,8 @@ private slots: void updateTopBarAvatar(const QString &roomid, const QPixmap &img); void updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name); void setOwnAvatar(const QPixmap &img); - void initialSyncCompleted(const SyncResponse &response); - void syncCompleted(const SyncResponse &response); + void initialSyncCompleted(const mtx::responses::Sync &response); + void syncCompleted(const mtx::responses::Sync &response); void syncFailed(const QString &msg); void changeTopRoomInfo(const QString &room_id); void logout(); @@ -87,26 +82,34 @@ private slots: private: using UserID = QString; using RoomStates = QMap; - using JoinedRooms = QMap; - using LeftRooms = QMap; - using Membership = matrix::events::StateEvent; - using Memberships = QMap; + using Membership = mtx::events::StateEvent; + using Memberships = std::map; + + using JoinedRooms = std::map; + using LeftRooms = std::map; void removeLeftRooms(const LeftRooms &rooms); void updateJoinedRooms(const JoinedRooms &rooms); - Memberships getMemberships(const QJsonArray &events) const; RoomStates generateMembershipDifference(const JoinedRooms &rooms, const RoomStates &states) const; - void updateTypingUsers(const QString &roomid, const QList &user_ids); - void updateUserMetadata(const QJsonArray &events); - void updateUserDisplayName(const Membership &event); - void updateUserAvatarUrl(const Membership &event); + void updateTypingUsers(const QString &roomid, const std::vector &user_ids); + + using MemberEvent = mtx::events::StateEvent; + void updateUserDisplayName(const MemberEvent &event); + void updateUserAvatarUrl(const MemberEvent &event); + void loadStateFromCache(); void deleteConfigs(); void resetUI(); + template + Memberships getMemberships(const std::vector &events) const; + + template + void updateUserMetadata(const std::vector &collection); + QHBoxLayout *topLayout_; Splitter *splitter; @@ -153,3 +156,37 @@ private: // return to the login page. int initialSyncFailures = 0; }; + +template +void +ChatPage::updateUserMetadata(const std::vector &collection) +{ + using Member = mtx::events::StateEvent; + + for (auto &event : collection) { + if (mpark::holds_alternative(event)) { + auto member = mpark::get(event); + + updateUserAvatarUrl(member); + updateUserDisplayName(member); + } + } +} + +template +std::map> +ChatPage::getMemberships(const std::vector &collection) const +{ + std::map> memberships; + + using Member = mtx::events::StateEvent; + + for (auto &event : collection) { + if (mpark::holds_alternative(event)) { + auto member = mpark::get(event); + memberships.emplace(member.state_key, member); + } + } + + return memberships; +} diff --git a/include/MatrixClient.h b/include/MatrixClient.h index 722a861..397ba11 100644 --- a/include/MatrixClient.h +++ b/include/MatrixClient.h @@ -20,12 +20,7 @@ #include #include #include - -#include "MessageEvent.h" - -class SyncResponse; -class Profile; -class RoomMessages; +#include /* * MatrixClient provides the high level API to communicate with @@ -40,7 +35,7 @@ public: // Client API. void initialSync() noexcept; void sync() noexcept; - void sendRoomMessage(matrix::events::MessageEventType ty, + void sendRoomMessage(mtx::events::MessageType ty, int txnId, const QString &roomid, const QString &msg, @@ -107,15 +102,15 @@ signals: // Returned profile data for the user's account. void getOwnProfileResponse(const QUrl &avatar_url, const QString &display_name); - void initialSyncCompleted(const SyncResponse &response); + void initialSyncCompleted(const mtx::responses::Sync &response); void initialSyncFailed(const QString &msg); - void syncCompleted(const SyncResponse &response); + void syncCompleted(const mtx::responses::Sync &response); void syncFailed(const QString &msg); void joinFailed(const QString &msg); void messageSent(const QString &event_id, const QString &roomid, const int txn_id); void messageSendFailed(const QString &roomid, const int txn_id); void emoteSent(const QString &event_id, const QString &roomid, const int txn_id); - void messagesRetrieved(const QString &room_id, const RoomMessages &msgs); + void messagesRetrieved(const QString &room_id, const mtx::responses::Messages &msgs); void joinedRoom(const QString &room_id); void leftRoom(const QString &room_id); diff --git a/include/RoomState.h b/include/RoomState.h index db1cdc6..0e91410 100644 --- a/include/RoomState.h +++ b/include/RoomState.h @@ -21,28 +21,14 @@ #include #include -#include "AliasesEventContent.h" -#include "AvatarEventContent.h" -#include "CanonicalAliasEventContent.h" -#include "CreateEventContent.h" -#include "HistoryVisibilityEventContent.h" -#include "JoinRulesEventContent.h" -#include "MemberEventContent.h" -#include "NameEventContent.h" -#include "PowerLevelsEventContent.h" -#include "TopicEventContent.h" - -#include "Event.h" -#include "RoomEvent.h" -#include "StateEvent.h" - -namespace events = matrix::events; +#include class RoomState { public: RoomState(); - RoomState(const QJsonArray &events); + RoomState(const mtx::responses::Timeline &timeline); + RoomState(const mtx::responses::State &state); // Calculate room data that are not immediatly accessible. Like room name and // avatar. @@ -50,32 +36,37 @@ public: // e.g If the room is 1-on-1 name and avatar should be extracted from a user. void resolveName(); void resolveAvatar(); - void parse(const QJsonObject &object); + void parse(const nlohmann::json &object); QUrl getAvatar() const { return avatar_; }; QString getName() const { return name_; }; - QString getTopic() const { return topic.content().topic().simplified(); }; + QString getTopic() const + { + return QString::fromStdString(topic.content.topic).simplified(); + }; void removeLeaveMemberships(); void update(const RoomState &state); - void updateFromEvents(const QJsonArray &events); - QJsonObject serialize() const; + template + void updateFromEvents(const std::vector &collection); + + std::string serialize() const; // The latest state events. - events::StateEvent aliases; - events::StateEvent avatar; - events::StateEvent canonical_alias; - events::StateEvent create; - events::StateEvent history_visibility; - events::StateEvent join_rules; - events::StateEvent name; - events::StateEvent power_levels; - events::StateEvent topic; + mtx::events::StateEvent aliases; + mtx::events::StateEvent avatar; + mtx::events::StateEvent canonical_alias; + mtx::events::StateEvent create; + mtx::events::StateEvent history_visibility; + mtx::events::StateEvent join_rules; + mtx::events::StateEvent name; + mtx::events::StateEvent power_levels; + mtx::events::StateEvent topic; // Contains the m.room.member events for all the joined users. - using UserID = QString; - QMap> memberships; + using UserID = std::string; + std::map> memberships; private: QUrl avatar_; @@ -85,3 +76,44 @@ private: // avatar event this should be empty. QString userAvatar_; }; + +template +void +RoomState::updateFromEvents(const std::vector &collection) +{ + using Aliases = mtx::events::StateEvent; + using Avatar = mtx::events::StateEvent; + using CanonicalAlias = mtx::events::StateEvent; + using Create = mtx::events::StateEvent; + using HistoryVisibility = mtx::events::StateEvent; + using JoinRules = mtx::events::StateEvent; + using Member = mtx::events::StateEvent; + using Name = mtx::events::StateEvent; + using PowerLevels = mtx::events::StateEvent; + using Topic = mtx::events::StateEvent; + + for (const auto &event : collection) { + if (mpark::holds_alternative(event)) { + this->aliases = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->avatar = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->canonical_alias = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->create = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->history_visibility = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->join_rules = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->name = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + auto membership = mpark::get(event); + this->memberships.emplace(membership.state_key, membership); + } else if (mpark::holds_alternative(event)) { + this->power_levels = mpark::get(event); + } else if (mpark::holds_alternative(event)) { + this->topic = mpark::get(event); + } + } +} diff --git a/include/Sync.h b/include/Sync.h deleted file mode 100644 index d59a57d..0000000 --- a/include/Sync.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Deserializable.h" - -class Event : public Deserializable -{ -public: - QJsonObject content() const { return content_; }; - QJsonObject unsigned_content() const { return unsigned_; }; - - QString sender() const { return sender_; }; - QString state_key() const { return state_key_; }; - QString type() const { return type_; }; - QString eventId() const { return event_id_; }; - - uint64_t timestamp() const { return origin_server_ts_; }; - - void deserialize(const QJsonValue &data) override; - -private: - QJsonObject content_; - QJsonObject unsigned_; - - QString sender_; - QString state_key_; - QString type_; - QString event_id_; - - uint64_t origin_server_ts_; -}; - -class State : public Deserializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonArray events() const { return events_; }; - -private: - QJsonArray events_; -}; - -class Timeline : public Deserializable -{ -public: - QJsonArray events() const { return events_; }; - QString previousBatch() const { return prev_batch_; }; - bool limited() const { return limited_; }; - - void deserialize(const QJsonValue &data) override; - -private: - QJsonArray events_; - QString prev_batch_; - bool limited_; -}; - -// TODO: Add support for account_data, undread_notifications -class JoinedRoom : public Deserializable -{ -public: - State state() const { return state_; }; - Timeline timeline() const { return timeline_; }; - QList typingUserIDs() const { return typingUserIDs_; }; - - void deserialize(const QJsonValue &data) override; - -private: - State state_; - Timeline timeline_; - QList typingUserIDs_; - /* AccountData account_data_; */ - /* UnreadNotifications unread_notifications_; */ -}; - -class LeftRoom : public Deserializable -{ -public: - State state() const { return state_; }; - Timeline timeline() const { return timeline_; }; - - void deserialize(const QJsonValue &data) override; - -private: - State state_; - Timeline timeline_; -}; - -// TODO: Add support for invited and left rooms. -class Rooms : public Deserializable -{ -public: - QMap join() const { return join_; }; - QMap leave() const { return leave_; }; - void deserialize(const QJsonValue &data) override; - -private: - QMap join_; - QMap leave_; -}; - -class SyncResponse : public Deserializable -{ -public: - void deserialize(const QJsonDocument &data) override; - QString nextBatch() const { return next_batch_; }; - Rooms rooms() const { return rooms_; }; - -private: - QString next_batch_; - Rooms rooms_; -}; diff --git a/include/TextInputWidget.h b/include/TextInputWidget.h index b208d3f..df309e2 100644 --- a/include/TextInputWidget.h +++ b/include/TextInputWidget.h @@ -25,13 +25,10 @@ #include #include "FlatButton.h" -#include "Image.h" #include "LoadingIndicator.h" #include "emoji/PickButton.h" -namespace msgs = matrix::events::messages; - class FilteredTextEdit : public QTextEdit { Q_OBJECT diff --git a/include/events/AliasesEventContent.h b/include/events/AliasesEventContent.h deleted file mode 100644 index 7784fad..0000000 --- a/include/events/AliasesEventContent.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -class AliasesEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QList aliases() const { return aliases_; }; - -private: - QList aliases_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/AvatarEventContent.h b/include/events/AvatarEventContent.h deleted file mode 100644 index 55284aa..0000000 --- a/include/events/AvatarEventContent.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -/* - * A picture that is associated with the room. - */ - -class AvatarEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QUrl url() const { return url_; }; - -private: - QUrl url_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/CanonicalAliasEventContent.h b/include/events/CanonicalAliasEventContent.h deleted file mode 100644 index 6322c00..0000000 --- a/include/events/CanonicalAliasEventContent.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "CanonicalAliasEventContent.h" -#include "Deserializable.h" - -namespace matrix { -namespace events { -/* - * This event is used to inform the room about which alias should be considered - * the canonical one. This could be for display purposes or as suggestion to - * users which alias to use to advertise the room. - */ - -class CanonicalAliasEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QString alias() const { return alias_; }; - -private: - QString alias_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/CreateEventContent.h b/include/events/CreateEventContent.h deleted file mode 100644 index 0a47860..0000000 --- a/include/events/CreateEventContent.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -/* - * This is the first event in a room and cannot be changed. It acts as the root - * of all other events. - */ - -class CreateEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QString creator() const { return creator_; }; - -private: - // The user_id of the room creator. This is set by the homeserver. - QString creator_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/Event.h b/include/events/Event.h deleted file mode 100644 index f6620a2..0000000 --- a/include/events/Event.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -enum class EventType -{ - /// m.room.aliases - RoomAliases, - /// m.room.avatar - RoomAvatar, - /// m.room.canonical_alias - RoomCanonicalAlias, - /// m.room.create - RoomCreate, - /// m.room.history_visibility - RoomHistoryVisibility, - /// m.room.join_rules - RoomJoinRules, - /// m.room.member - RoomMember, - /// m.room.message - RoomMessage, - /// m.room.name - RoomName, - /// m.room.power_levels - RoomPowerLevels, - /// m.room.topic - RoomTopic, - // Unsupported event - Unsupported, -}; - -EventType -extractEventType(const QJsonObject &data); - -bool -isMessageEvent(EventType type); -bool -isStateEvent(EventType type); - -class UnsignedData - : public Deserializable - , public Serializable -{ -public: - double age() const { return age_; } - QString transactionId() const { return transaction_id_; } - - bool isEmpty() const { return age_ <= 0 && transaction_id_.isEmpty(); } - - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - -private: - double age_ = 0; - QString transaction_id_; -}; - -template -class Event - : public Deserializable - , public Serializable -{ -public: - Content content() const; - EventType eventType() const; - UnsignedData unsignedData() const { return unsignedData_; } - - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - -private: - Content content_; - EventType type_; - UnsignedData unsignedData_; -}; - -template -inline Content -Event::content() const -{ - return content_; -} - -template -inline EventType -Event::eventType() const -{ - return type_; -} - -template -void -Event::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("Event is not a JSON object"); - - auto object = data.toObject(); - - content_.deserialize(object.value("content")); - type_ = extractEventType(object); - - if (object.contains("unsigned")) - unsignedData_.deserialize(object.value("unsigned")); -} - -template -QJsonObject -Event::serialize() const -{ - QJsonObject object; - - switch (type_) { - case EventType::RoomAliases: - object["type"] = "m.room.aliases"; - break; - case EventType::RoomAvatar: - object["type"] = "m.room.avatar"; - break; - case EventType::RoomCanonicalAlias: - object["type"] = "m.room.canonical_alias"; - break; - case EventType::RoomCreate: - object["type"] = "m.room.create"; - break; - case EventType::RoomHistoryVisibility: - object["type"] = "m.room.history_visibility"; - break; - case EventType::RoomJoinRules: - object["type"] = "m.room.join_rules"; - break; - case EventType::RoomMember: - object["type"] = "m.room.member"; - break; - case EventType::RoomMessage: - object["type"] = "m.room.message"; - break; - case EventType::RoomName: - object["type"] = "m.room.name"; - break; - case EventType::RoomPowerLevels: - object["type"] = "m.room.power_levels"; - break; - case EventType::RoomTopic: - object["type"] = "m.room.topic"; - break; - case EventType::Unsupported: - qWarning() << "Unsupported type to serialize"; - break; - } - - object["content"] = content_.serialize(); - - if (!unsignedData_.isEmpty()) - object["unsigned"] = unsignedData_.serialize(); - - return object; -} -} // namespace events -} // namespace matrix diff --git a/include/events/HistoryVisibilityEventContent.h b/include/events/HistoryVisibilityEventContent.h deleted file mode 100644 index 1c39ae0..0000000 --- a/include/events/HistoryVisibilityEventContent.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -enum class HistoryVisibility -{ - Invited, - Joined, - Shared, - WorldReadable, -}; - -class HistoryVisibilityEventContent - : public Deserializable - , public Serializable -{ -public: - HistoryVisibility historyVisibility() const { return history_visibility_; }; - - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - -private: - HistoryVisibility history_visibility_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/JoinRulesEventContent.h b/include/events/JoinRulesEventContent.h deleted file mode 100644 index 4ed9e65..0000000 --- a/include/events/JoinRulesEventContent.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -enum class JoinRule -{ - // A user who wishes to join the room must first receive - // an invite to the room from someone already inside of the room. - Invite, - - // Reserved but not yet implemented by the Matrix specification. - Knock, - - // Reserved but not yet implemented by the Matrix specification. - Private, - - /// Anyone can join the room without any prior action. - Public, -}; - -/* - * Describes how users are allowed to join the room. - */ - -class JoinRulesEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - JoinRule joinRule() const { return join_rule_; }; - -private: - JoinRule join_rule_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/MemberEventContent.h b/include/events/MemberEventContent.h deleted file mode 100644 index 8b7b157..0000000 --- a/include/events/MemberEventContent.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -enum class Membership -{ - // The user is banned. - Ban, - - // The user has been invited. - Invite, - - // The user has joined. - Join, - - // The user has requested to join. - Knock, - - // The user has left. - Leave, -}; - -/* - * The current membership state of a user in the room. - */ - -class MemberEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QUrl avatarUrl() const { return avatar_url_; }; - QString displayName() const { return display_name_; }; - Membership membershipState() const { return membership_state_; }; - -private: - QUrl avatar_url_; - QString display_name_; - Membership membership_state_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/MessageEvent.h b/include/events/MessageEvent.h deleted file mode 100644 index 08cd926..0000000 --- a/include/events/MessageEvent.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "MessageEventContent.h" -#include "RoomEvent.h" - -namespace matrix { -namespace events { -template -class MessageEvent : public RoomEvent -{ -public: - MsgContent msgContent() const; - - void deserialize(const QJsonValue &data) override; - -private: - MsgContent msg_content_; -}; - -template -inline MsgContent -MessageEvent::msgContent() const -{ - return msg_content_; -} - -template -void -MessageEvent::deserialize(const QJsonValue &data) -{ - RoomEvent::deserialize(data); - - msg_content_.deserialize(data.toObject().value("content").toObject()); -} - -namespace messages { -struct ThumbnailInfo -{ - int h; - int w; - int size = 0; - - QString mimetype; -}; -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/MessageEventContent.h b/include/events/MessageEventContent.h deleted file mode 100644 index aa08c06..0000000 --- a/include/events/MessageEventContent.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -enum class MessageEventType -{ - // m.audio - Audio, - - // m.emote - Emote, - - // m.file - File, - - // m.image - Image, - - // m.location - Location, - - // m.notice - Notice, - - // m.text - Text, - - // m.video - Video, - - // Unrecognized message type - Unknown, -}; - -MessageEventType -extractMessageEventType(const QJsonObject &data); - -class MessageEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QString body() const { return body_; }; - -private: - QString body_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/NameEventContent.h b/include/events/NameEventContent.h deleted file mode 100644 index 378f689..0000000 --- a/include/events/NameEventContent.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -/* - * A human-friendly room name designed to be displayed to the end-user. - */ - -class NameEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QString name() const { return name_; }; - -private: - QString name_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/PowerLevelsEventContent.h b/include/events/PowerLevelsEventContent.h deleted file mode 100644 index 6399887..0000000 --- a/include/events/PowerLevelsEventContent.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -enum class PowerLevels -{ - User = 0, - Moderator = 50, - Admin = 100, -}; - -/* - * Defines the power levels (privileges) of users in the room. - */ - -class PowerLevelsEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - int banLevel() const { return ban_; }; - int inviteLevel() const { return invite_; }; - int kickLevel() const { return kick_; }; - int redactLevel() const { return redact_; }; - - int eventsDefaultLevel() const { return events_default_; }; - int stateDefaultLevel() const { return state_default_; }; - int usersDefaultLevel() const { return users_default_; }; - - int eventLevel(QString event_type) const; - int userLevel(QString user_id) const; - -private: - int ban_ = static_cast(PowerLevels::Moderator); - int invite_ = static_cast(PowerLevels::Moderator); - int kick_ = static_cast(PowerLevels::Moderator); - int redact_ = static_cast(PowerLevels::Moderator); - - int events_default_ = static_cast(PowerLevels::User); - int state_default_ = static_cast(PowerLevels::Moderator); - int users_default_ = static_cast(PowerLevels::User); - - QMap events_; - QMap users_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/RoomEvent.h b/include/events/RoomEvent.h deleted file mode 100644 index d80951c..0000000 --- a/include/events/RoomEvent.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "Event.h" - -namespace matrix { -namespace events { -template -class RoomEvent : public Event -{ -public: - QString eventId() const; - QString roomId() const; - QString sender() const; - uint64_t timestamp() const; - - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - -private: - QString event_id_; - QString room_id_; - QString sender_; - - uint64_t origin_server_ts_; -}; - -template -inline QString -RoomEvent::eventId() const -{ - return event_id_; -} - -template -inline QString -RoomEvent::roomId() const -{ - return room_id_; -} - -template -inline QString -RoomEvent::sender() const -{ - return sender_; -} - -template -inline uint64_t -RoomEvent::timestamp() const -{ - return origin_server_ts_; -} - -template -void -RoomEvent::deserialize(const QJsonValue &data) -{ - Event::deserialize(data); - - auto object = data.toObject(); - - if (!object.contains("event_id")) - throw DeserializationException("event_id key is missing"); - - if (!object.contains("origin_server_ts")) - throw DeserializationException("origin_server_ts key is missing"); - - // FIXME: Synapse doesn't include room id?! - /* if (!object.contains("room_id")) */ - /* throw DeserializationException("room_id key is missing"); */ - - if (!object.contains("sender")) - throw DeserializationException("sender key is missing"); - - event_id_ = object.value("event_id").toString(); - room_id_ = object.value("room_id").toString(); - sender_ = object.value("sender").toString(); - origin_server_ts_ = object.value("origin_server_ts").toDouble(); -} - -template -QJsonObject -RoomEvent::serialize() const -{ - QJsonObject object = Event::serialize(); - - object["event_id"] = event_id_; - object["room_id"] = room_id_; - object["sender"] = sender_; - object["origin_server_ts"] = QJsonValue(static_cast(origin_server_ts_)); - - return object; -} -} // namespace events -} // namespace matrix diff --git a/include/events/StateEvent.h b/include/events/StateEvent.h deleted file mode 100644 index 19342a4..0000000 --- a/include/events/StateEvent.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "RoomEvent.h" - -namespace matrix { -namespace events { -template -class StateEvent : public RoomEvent -{ -public: - QString stateKey() const; - Content previousContent() const; - - void deserialize(const QJsonValue &data); - QJsonObject serialize() const; - -private: - QString state_key_; - Content prev_content_; -}; - -template -inline QString -StateEvent::stateKey() const -{ - return state_key_; -} - -template -inline Content -StateEvent::previousContent() const -{ - return prev_content_; -} - -template -void -StateEvent::deserialize(const QJsonValue &data) -{ - RoomEvent::deserialize(data); - - auto object = data.toObject(); - - if (!object.contains("state_key")) - throw DeserializationException("state_key key is missing"); - - state_key_ = object.value("state_key").toString(); - - if (object.contains("prev_content")) - prev_content_.deserialize(object.value("prev_content")); -} - -template -QJsonObject -StateEvent::serialize() const -{ - QJsonObject object = RoomEvent::serialize(); - - object["state_key"] = state_key_; - - auto prev = prev_content_.serialize(); - - if (!prev.isEmpty()) - object["prev_content"] = prev; - - return object; -} -} // namespace events -} // namespace matrix diff --git a/include/events/TopicEventContent.h b/include/events/TopicEventContent.h deleted file mode 100644 index 67e2120..0000000 --- a/include/events/TopicEventContent.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -/* - * A topic is a short message detailing what is currently being discussed in the - * room. - */ - -class TopicEventContent - : public Deserializable - , public Serializable -{ -public: - void deserialize(const QJsonValue &data) override; - QJsonObject serialize() const override; - - QString topic() const { return topic_; }; - -private: - QString topic_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Audio.h b/include/events/messages/Audio.h deleted file mode 100644 index b5666d9..0000000 --- a/include/events/messages/Audio.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -namespace messages { -struct AudioInfo -{ - uint64_t duration; - int size = 0; - - QString mimetype; -}; - -class Audio : public Deserializable -{ -public: - QString url() const { return url_; }; - AudioInfo info() const { return info_; }; - - void deserialize(const QJsonObject &object) override; - -private: - QString url_; - AudioInfo info_; -}; - -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Emote.h b/include/events/messages/Emote.h deleted file mode 100644 index a11b7c8..0000000 --- a/include/events/messages/Emote.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -namespace messages { -class Emote : public Deserializable -{ -public: - void deserialize(const QJsonObject &obj) override; -}; -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/File.h b/include/events/messages/File.h deleted file mode 100644 index 9064a55..0000000 --- a/include/events/messages/File.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" -#include "MessageEvent.h" - -namespace matrix { -namespace events { -namespace messages { -struct FileInfo -{ - int size = 0; - - QString mimetype; - QString thumbnail_url; - ThumbnailInfo thumbnail_info; -}; - -class File : public Deserializable -{ -public: - QString url() const { return url_; }; - QString filename() const { return filename_; }; - FileInfo info() const { return info_; }; - - void deserialize(const QJsonObject &object) override; - -private: - QString url_; - QString filename_; - - FileInfo info_; -}; - -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Image.h b/include/events/messages/Image.h deleted file mode 100644 index 03c7a36..0000000 --- a/include/events/messages/Image.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" -#include "MessageEvent.h" - -namespace matrix { -namespace events { -namespace messages { -struct ImageInfo -{ - int h; - int w; - int size = 0; - - QString mimetype; - QString thumbnail_url; - ThumbnailInfo thumbnail_info; -}; - -class Image : public Deserializable -{ -public: - QString url() const { return url_; }; - ImageInfo info() const { return info_; }; - - void deserialize(const QJsonObject &object) override; - -private: - QString url_; - ImageInfo info_; -}; - -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Location.h b/include/events/messages/Location.h deleted file mode 100644 index 27722b3..0000000 --- a/include/events/messages/Location.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" -#include "MessageEvent.h" - -namespace matrix { -namespace events { -namespace messages { -struct LocationInfo -{ - QString thumbnail_url; - ThumbnailInfo thumbnail_info; -}; - -class Location : public Deserializable -{ -public: - QString geoUri() const { return geo_uri_; }; - LocationInfo info() const { return info_; }; - - void deserialize(const QJsonObject &object) override; - -private: - QString geo_uri_; - - LocationInfo info_; -}; - -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Notice.h b/include/events/messages/Notice.h deleted file mode 100644 index 66f4386..0000000 --- a/include/events/messages/Notice.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -namespace messages { -class Notice : public Deserializable -{ -public: - void deserialize(const QJsonObject &obj) override; -}; -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Text.h b/include/events/messages/Text.h deleted file mode 100644 index c3182dc..0000000 --- a/include/events/messages/Text.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" - -namespace matrix { -namespace events { -namespace messages { -class Text : public Deserializable -{ -public: - void deserialize(const QJsonObject &obj) override; -}; -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/events/messages/Video.h b/include/events/messages/Video.h deleted file mode 100644 index 6aeaf4d..0000000 --- a/include/events/messages/Video.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "Deserializable.h" -#include "MessageEvent.h" - -namespace matrix { -namespace events { -namespace messages { -struct VideoInfo -{ - int h; - int w; - int size = 0; - int duration; - - QString mimetype; - QString thumbnail_url; - ThumbnailInfo thumbnail_info; -}; - -class Video : public Deserializable -{ -public: - QString url() const { return url_; }; - VideoInfo info() const { return info_; }; - - void deserialize(const QJsonObject &object) override; - -private: - QString url_; - VideoInfo info_; -}; - -} // namespace messages -} // namespace events -} // namespace matrix diff --git a/include/timeline/TimelineItem.h b/include/timeline/TimelineItem.h index e04cbea..17b110f 100644 --- a/include/timeline/TimelineItem.h +++ b/include/timeline/TimelineItem.h @@ -25,16 +25,7 @@ #include #include -#include "Audio.h" -#include "Emote.h" -#include "File.h" -#include "Image.h" -#include "Notice.h" -#include "Text.h" -#include "Video.h" - #include "AvatarProvider.h" -#include "MessageEvent.h" #include "RoomInfoListItem.h" #include "TimelineViewManager.h" @@ -44,26 +35,23 @@ class VideoItem; class FileItem; class Avatar; -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - class TimelineItem : public QWidget { Q_OBJECT public: - TimelineItem(const events::MessageEvent &e, + TimelineItem(const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent = 0); - TimelineItem(const events::MessageEvent &e, + TimelineItem(const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent = 0); - TimelineItem(const events::MessageEvent &e, + TimelineItem(const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent = 0); // For local messages. // m.text & m.emote - TimelineItem(events::MessageEventType ty, + TimelineItem(mtx::events::MessageType ty, const QString &userid, QString body, bool withSender, @@ -75,19 +63,19 @@ public: TimelineItem(VideoItem *item, const QString &userid, bool withSender, QWidget *parent = 0); TimelineItem(ImageItem *img, - const events::MessageEvent &e, + const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent); TimelineItem(FileItem *file, - const events::MessageEvent &e, + const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent); TimelineItem(AudioItem *audio, - const events::MessageEvent &e, + const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent); TimelineItem(VideoItem *video, - const events::MessageEvent &e, + const mtx::events::RoomEvent &e, bool with_sender, QWidget *parent); @@ -185,16 +173,17 @@ TimelineItem::setupWidgetLayout(Widget *widget, { init(); - event_id_ = event.eventId(); + event_id_ = QString::fromStdString(event.event_id); + const auto sender = QString::fromStdString(event.sender); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - auto displayName = TimelineViewManager::displayName(event.sender()); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); + auto displayName = TimelineViewManager::displayName(sender); QSettings settings; - descriptionMsg_ = {event.sender() == settings.value("auth/user_id") ? "You" : displayName, - event.sender(), + descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName, + sender, msgDescription, - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))}; + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))}; generateTimestamp(timestamp); @@ -209,7 +198,7 @@ TimelineItem::setupWidgetLayout(Widget *widget, mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); + AvatarProvider::resolve(sender, this); } else { setupSimpleLayout(); } diff --git a/include/timeline/TimelineView.h b/include/timeline/TimelineView.h index 5262d20..52bf016 100644 --- a/include/timeline/TimelineView.h +++ b/include/timeline/TimelineView.h @@ -27,39 +27,27 @@ #include #include -#include "Audio.h" -#include "Emote.h" -#include "File.h" -#include "Image.h" -#include "Notice.h" -#include "Text.h" -#include "Video.h" +#include #include "MatrixClient.h" -#include "MessageEvent.h" #include "TimelineItem.h" class FloatingButton; -class RoomMessages; class ScrollBar; -class Timeline; struct DescInfo; -namespace msgs = matrix::events::messages; -namespace events = matrix::events; - // Contains info about a message shown in the history view // but not yet confirmed by the homeserver through sync. struct PendingMessage { - matrix::events::MessageEventType ty; + mtx::events::MessageType ty; int txn_id; QString body; QString filename; QString event_id; TimelineItem *widget; - PendingMessage(matrix::events::MessageEventType ty, + PendingMessage(mtx::events::MessageType ty, int txn_id, QString body, QString filename, @@ -86,7 +74,7 @@ class TimelineView : public QWidget Q_OBJECT public: - TimelineView(const Timeline &timeline, + TimelineView(const mtx::responses::Timeline &timeline, QSharedPointer client, const QString &room_id, QWidget *parent = 0); @@ -95,10 +83,10 @@ public: QWidget *parent = 0); // Add new events at the end of the timeline. - int addEvents(const Timeline &timeline); - void addUserMessage(matrix::events::MessageEventType ty, const QString &msg); + int addEvents(const mtx::responses::Timeline &timeline); + void addUserMessage(mtx::events::MessageType ty, const QString &msg); - template + template void addUserMessage(const QString &url, const QString &filename); void updatePendingMessage(int txn_id, QString event_id); void scrollDown(); @@ -109,7 +97,7 @@ public slots: void fetchHistory(); // Add old events at the top of the timeline. - void addBackwardsEvents(const QString &room_id, const RoomMessages &msgs); + void addBackwardsEvents(const QString &room_id, const mtx::responses::Messages &msgs); // Whether or not the initial batch has been loaded. bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; } @@ -135,13 +123,14 @@ private: void notifyForLastEvent(); void readLastEvent() const; QString getLastEventId() const; + QString getEventSender(const mtx::events::collections::TimelineEvents &event) const; template - TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); + TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction); // TODO: Remove this eventually. template - TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); + TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction); // For events with custom display widgets. template @@ -164,7 +153,8 @@ private: void handleNewUserMessage(PendingMessage msg); // Return nullptr if the event couldn't be parsed. - TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction); + TimelineItem *parseMessageEvent(const mtx::events::collections::TimelineEvents &event, + TimelineDirection direction); QVBoxLayout *top_layout_; QVBoxLayout *scroll_layout_; @@ -207,7 +197,7 @@ private: QSharedPointer client_; }; -template +template void TimelineView::addUserMessage(const QString &url, const QString &filename) { @@ -252,62 +242,50 @@ TimelineView::createTimelineItem(const Event &event, bool withSender) template TimelineItem * -TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction) +TimelineView::processMessageEvent(const Event &event, TimelineDirection direction) { - Event event; - - try { - event.deserialize(data); - } catch (const DeserializationException &e) { - qWarning() << e.what() << data; - return nullptr; - } + const auto event_id = QString::fromStdString(event.event_id); + const auto sender = QString::fromStdString(event.sender); - if (isDuplicate(event.eventId())) + if (isDuplicate(event_id)) return nullptr; - eventIds_[event.eventId()] = true; + eventIds_[event_id] = true; - QString txnid = event.unsignedData().transactionId(); - if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) { + const QString txnid = QString::fromStdString(event.unsigned_data.transaction_id); + if (!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) { removePendingMessage(txnid); return nullptr; } - auto with_sender = isSenderRendered(event.sender(), direction); + auto with_sender = isSenderRendered(sender, direction); - updateLastSender(event.sender(), direction); + updateLastSender(sender, direction); return createTimelineItem(event, with_sender); } template TimelineItem * -TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction) +TimelineView::processMessageEvent(const Event &event, TimelineDirection direction) { - Event event; - - try { - event.deserialize(data); - } catch (const DeserializationException &e) { - qWarning() << e.what() << data; - return nullptr; - } + const auto event_id = QString::fromStdString(event.event_id); + const auto sender = QString::fromStdString(event.sender); - if (isDuplicate(event.eventId())) + if (isDuplicate(event_id)) return nullptr; - eventIds_[event.eventId()] = true; + eventIds_[event_id] = true; - QString txnid = event.unsignedData().transactionId(); - if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) { + const QString txnid = QString::fromStdString(event.unsigned_data.transaction_id); + if (!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) { removePendingMessage(txnid); return nullptr; } - auto with_sender = isSenderRendered(event.sender(), direction); + auto with_sender = isSenderRendered(sender, direction); - updateLastSender(event.sender(), direction); + updateLastSender(sender, direction); return createTimelineItem(event, with_sender); } diff --git a/include/timeline/TimelineViewManager.h b/include/timeline/TimelineViewManager.h index edb44ec..2c32da1 100644 --- a/include/timeline/TimelineViewManager.h +++ b/include/timeline/TimelineViewManager.h @@ -21,12 +21,10 @@ #include #include -#include "MessageEvent.h" +#include -class JoinedRoom; class MatrixClient; class RoomInfoListItem; -class Rooms; class TimelineView; struct DescInfo; @@ -39,14 +37,14 @@ public: ~TimelineViewManager(); // Initialize with timeline events. - void initialize(const Rooms &rooms); + void initialize(const mtx::responses::Rooms &rooms); // Empty initialization. void initialize(const QList &rooms); - void addRoom(const JoinedRoom &room, const QString &room_id); + void addRoom(const mtx::responses::JoinedRoom &room, const QString &room_id); void addRoom(const QString &room_id); - void sync(const Rooms &rooms); + void sync(const mtx::responses::Rooms &rooms); void clearAll(); // Check if all the timelines have been loaded. diff --git a/include/timeline/widgets/AudioItem.h b/include/timeline/widgets/AudioItem.h index 1104996..f8e7cc0 100644 --- a/include/timeline/widgets/AudioItem.h +++ b/include/timeline/widgets/AudioItem.h @@ -24,12 +24,9 @@ #include #include -#include "Audio.h" #include "MatrixClient.h" -#include "MessageEvent.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include class AudioItem : public QWidget { @@ -46,7 +43,7 @@ class AudioItem : public QWidget public: AudioItem(QSharedPointer client, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, QWidget *parent = nullptr); AudioItem(QSharedPointer client, @@ -94,7 +91,7 @@ private: QString readableFileSize_; QString filenameToSave_; - events::MessageEvent event_; + mtx::events::RoomEvent event_; QSharedPointer client_; QMediaPlayer *player_; diff --git a/include/timeline/widgets/FileItem.h b/include/timeline/widgets/FileItem.h index 47e8186..fd0b024 100644 --- a/include/timeline/widgets/FileItem.h +++ b/include/timeline/widgets/FileItem.h @@ -23,12 +23,9 @@ #include #include -#include "File.h" -#include "MatrixClient.h" -#include "MessageEvent.h" +#include -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include "MatrixClient.h" class FileItem : public QWidget { @@ -40,7 +37,7 @@ class FileItem : public QWidget public: FileItem(QSharedPointer client, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, QWidget *parent = nullptr); FileItem(QSharedPointer client, @@ -75,7 +72,7 @@ private: QString readableFileSize_; QString filenameToSave_; - events::MessageEvent event_; + mtx::events::RoomEvent event_; QSharedPointer client_; QIcon icon_; diff --git a/include/timeline/widgets/ImageItem.h b/include/timeline/widgets/ImageItem.h index c4f6998..931c17d 100644 --- a/include/timeline/widgets/ImageItem.h +++ b/include/timeline/widgets/ImageItem.h @@ -22,19 +22,16 @@ #include #include -#include "Image.h" -#include "MatrixClient.h" -#include "MessageEvent.h" +#include -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include "MatrixClient.h" class ImageItem : public QWidget { Q_OBJECT public: ImageItem(QSharedPointer client, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, QWidget *parent = nullptr); ImageItem(QSharedPointer client, @@ -72,7 +69,7 @@ private: int bottom_height_ = 30; - events::MessageEvent event_; + mtx::events::RoomEvent event_; QSharedPointer client_; }; diff --git a/include/timeline/widgets/VideoItem.h b/include/timeline/widgets/VideoItem.h index aa2a5da..88ff21e 100644 --- a/include/timeline/widgets/VideoItem.h +++ b/include/timeline/widgets/VideoItem.h @@ -23,11 +23,8 @@ #include #include "MatrixClient.h" -#include "MessageEvent.h" -#include "Video.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include class VideoItem : public QWidget { @@ -35,7 +32,7 @@ class VideoItem : public QWidget public: VideoItem(QSharedPointer client, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, QWidget *parent = nullptr); VideoItem(QSharedPointer client, @@ -53,6 +50,6 @@ private: QLabel *label_; - events::MessageEvent event_; + mtx::events::RoomEvent event_; QSharedPointer client_; }; diff --git a/libs/matrix-structs b/libs/matrix-structs index 190f297..ea10ea8 160000 --- a/libs/matrix-structs +++ b/libs/matrix-structs @@ -1 +1 @@ -Subproject commit 190f297478153930780a119268b908076599c8db +Subproject commit ea10ea843bccebf54b7b4ebdf1be92a3624597b4 diff --git a/src/Cache.cc b/src/Cache.cc index dc2c8a9..087dd4b 100644 --- a/src/Cache.cc +++ b/src/Cache.cc @@ -22,11 +22,8 @@ #include #include "Cache.h" -#include "MemberEventContent.h" #include "RoomState.h" -namespace events = matrix::events; - static const lmdb::val NEXT_BATCH_KEY("next_batch"); static const lmdb::val transactionID("transaction_id"); @@ -122,13 +119,10 @@ Cache::setState(const QString &nextBatchToken, const QMap &s void Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &state) { - auto stateEvents = QJsonDocument(state.serialize()).toBinaryData(); + auto stateEvents = state.serialize(); auto id = roomid.toUtf8(); - lmdb::dbi_put(txn, - roomDb_, - lmdb::val(id.data(), id.size()), - lmdb::val(stateEvents.data(), stateEvents.size())); + lmdb::dbi_put(txn, roomDb_, lmdb::val(id.data(), id.size()), lmdb::val(stateEvents)); for (const auto &membership : state.memberships) { lmdb::dbi membersDb = @@ -136,31 +130,29 @@ Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &s // The user_id this membership event relates to, is used // as the index on the membership database. - auto key = membership.stateKey().toUtf8(); - auto memberEvent = QJsonDocument(membership.serialize()).toBinaryData(); + auto key = membership.second.state_key; + + // Serialize membership event. + nlohmann::json data = membership.second; + std::string memberEvent = data.dump(); - switch (membership.content().membershipState()) { + switch (membership.second.content.membership) { // We add or update (e.g invite -> join) a new user to the membership // list. - case events::Membership::Invite: - case events::Membership::Join: { - lmdb::dbi_put(txn, - membersDb, - lmdb::val(key.data(), key.size()), - lmdb::val(memberEvent.data(), memberEvent.size())); + case mtx::events::state::Membership::Invite: + case mtx::events::state::Membership::Join: { + lmdb::dbi_put(txn, membersDb, lmdb::val(key), lmdb::val(memberEvent)); break; } // We remove the user from the membership list. - case events::Membership::Leave: - case events::Membership::Ban: { - lmdb::dbi_del(txn, - membersDb, - lmdb::val(key.data(), key.size()), - lmdb::val(memberEvent.data(), memberEvent.size())); + case mtx::events::state::Membership::Leave: + case mtx::events::state::Membership::Ban: { + lmdb::dbi_del(txn, membersDb, lmdb::val(key), lmdb::val(memberEvent)); break; } - case events::Membership::Knock: { - qWarning() << "Skipping knock membership" << roomid << key; + case mtx::events::state::Membership::Knock: { + qWarning() + << "Skipping knock membership" << roomid << QString::fromStdString(key); break; } } @@ -194,14 +186,13 @@ Cache::states() // Retrieve all the room names. while (cursor.get(room, stateData, MDB_NEXT)) { auto roomid = QString::fromUtf8(room.data(), room.size()); - auto json = - QJsonDocument::fromBinaryData(QByteArray(stateData.data(), stateData.size())); + auto json = nlohmann::json::parse(stateData); RoomState state; - state.parse(json.object()); + state.parse(json); auto memberDb = lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE); - QMap> members; + std::map> members; auto memberCursor = lmdb::cursor::open(txn, memberDb); @@ -209,17 +200,15 @@ Cache::states() std::string memberContent; while (memberCursor.get(memberId, memberContent, MDB_NEXT)) { - auto userid = QString::fromUtf8(memberId.data(), memberId.size()); - auto data = QJsonDocument::fromBinaryData( - QByteArray(memberContent.data(), memberContent.size())); + auto userid = QString::fromStdString(memberId); try { - events::StateEvent member; - member.deserialize(data.object()); - members.insert(userid, member); - } catch (const DeserializationException &e) { - qWarning() << e.what(); - qWarning() << "Fault while parsing member event" << data.object(); + auto data = nlohmann::json::parse(memberContent); + mtx::events::StateEvent member = data; + members.emplace(memberId, member); + } catch (std::exception &e) { + qWarning() << "Fault while parsing member event" << e.what() + << QString::fromStdString(memberContent); continue; } } diff --git a/src/ChatPage.cc b/src/ChatPage.cc index bbed735..ab5aa26 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc @@ -32,7 +32,6 @@ #include "RoomState.h" #include "SideBarActions.h" #include "Splitter.h" -#include "Sync.h" #include "TextInputWidget.h" #include "Theme.h" #include "TopRoomBar.h" @@ -44,8 +43,6 @@ constexpr int MAX_INITIAL_SYNC_FAILURES = 5; constexpr int SYNC_RETRY_TIMEOUT = 10000; -namespace events = matrix::events; - ChatPage::ChatPage(QSharedPointer client, QWidget *parent) : QWidget(parent) , client_(client) @@ -219,15 +216,13 @@ ChatPage::ChatPage(QSharedPointer client, QWidget *parent) view_manager_->queueAudioMessage(roomid, filename, url); }); - connect(client_.data(), - SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)), - this, - SLOT(updateTopBarAvatar(const QString &, const QPixmap &))); + connect( + client_.data(), &MatrixClient::roomAvatarRetrieved, this, &ChatPage::updateTopBarAvatar); connect(client_.data(), - SIGNAL(initialSyncCompleted(const SyncResponse &)), + &MatrixClient::initialSyncCompleted, this, - SLOT(initialSyncCompleted(const SyncResponse &))); + &ChatPage::initialSyncCompleted); connect(client_.data(), &MatrixClient::initialSyncFailed, this, [=](const QString &msg) { if (client_->getHomeServer().isEmpty()) { deleteConfigs(); @@ -251,29 +246,17 @@ ChatPage::ChatPage(QSharedPointer client, QWidget *parent) client_->initialSync(); }); - connect(client_.data(), - SIGNAL(syncCompleted(const SyncResponse &)), - this, - SLOT(syncCompleted(const SyncResponse &))); - connect(client_.data(), - SIGNAL(syncFailed(const QString &)), - this, - SLOT(syncFailed(const QString &))); + connect(client_.data(), &MatrixClient::syncCompleted, this, &ChatPage::syncCompleted); + connect(client_.data(), &MatrixClient::syncFailed, this, &ChatPage::syncFailed); connect(client_.data(), &MatrixClient::getOwnProfileResponse, this, &ChatPage::updateOwnProfileInfo); - connect(client_.data(), - SIGNAL(ownAvatarRetrieved(const QPixmap &)), - this, - SLOT(setOwnAvatar(const QPixmap &))); + connect(client_.data(), &MatrixClient::ownAvatarRetrieved, this, &ChatPage::setOwnAvatar); connect(client_.data(), &MatrixClient::joinedRoom, this, [=]() { emit showNotification("You joined the room."); }); - connect(client_.data(), - SIGNAL(leftRoom(const QString &)), - this, - SLOT(removeRoom(const QString &))); + connect(client_.data(), &MatrixClient::leftRoom, this, &ChatPage::removeRoom); showContentTimer_ = new QTimer(this); showContentTimer_->setSingleShot(true); @@ -383,32 +366,34 @@ ChatPage::syncFailed(const QString &msg) } void -ChatPage::syncCompleted(const SyncResponse &response) +ChatPage::syncCompleted(const mtx::responses::Sync &response) { - updateJoinedRooms(response.rooms().join()); - removeLeftRooms(response.rooms().leave()); + updateJoinedRooms(response.rooms.join); + removeLeftRooms(response.rooms.leave); - auto stateDiff = generateMembershipDifference(response.rooms().join(), state_manager_); - QtConcurrent::run(cache_.data(), &Cache::setState, response.nextBatch(), stateDiff); + const auto nextBatchToken = QString::fromStdString(response.next_batch); + + auto stateDiff = generateMembershipDifference(response.rooms.join, state_manager_); + QtConcurrent::run(cache_.data(), &Cache::setState, nextBatchToken, stateDiff); room_list_->sync(state_manager_, settingsManager_); - view_manager_->sync(response.rooms()); + view_manager_->sync(response.rooms); - client_->setNextBatchToken(response.nextBatch()); + client_->setNextBatchToken(nextBatchToken); client_->sync(); } void -ChatPage::initialSyncCompleted(const SyncResponse &response) +ChatPage::initialSyncCompleted(const mtx::responses::Sync &response) { - auto joined = response.rooms().join(); + auto joined = response.rooms.join; - for (auto it = joined.constBegin(); it != joined.constEnd(); ++it) { + for (auto it = joined.cbegin(); it != joined.cend(); ++it) { RoomState room_state; // Build the current state from the timeline and state events. - room_state.updateFromEvents(it.value().state().events()); - room_state.updateFromEvents(it.value().timeline().events()); + room_state.updateFromEvents(it->second.state.events); + room_state.updateFromEvents(it->second.timeline.events); // Remove redundant memberships. room_state.removeLeaveMemberships(); @@ -417,27 +402,32 @@ ChatPage::initialSyncCompleted(const SyncResponse &response) room_state.resolveName(); room_state.resolveAvatar(); - state_manager_.insert(it.key(), room_state); - settingsManager_.insert(it.key(), - QSharedPointer(new RoomSettings(it.key()))); + const auto room_id = QString::fromStdString(it->first); + + state_manager_.insert(room_id, room_state); + settingsManager_.insert(room_id, + QSharedPointer(new RoomSettings(room_id))); for (const auto membership : room_state.memberships) { - updateUserDisplayName(membership); - updateUserAvatarUrl(membership); + updateUserDisplayName(membership.second); + updateUserAvatarUrl(membership.second); } QApplication::processEvents(); } - QtConcurrent::run(cache_.data(), &Cache::setState, response.nextBatch(), state_manager_); + QtConcurrent::run(cache_.data(), + &Cache::setState, + QString::fromStdString(response.next_batch), + state_manager_); // Populate timelines with messages. - view_manager_->initialize(response.rooms()); + view_manager_->initialize(response.rooms); // Initialize room list. room_list_->setInitialRooms(settingsManager_, state_manager_); - client_->setNextBatchToken(response.nextBatch()); + client_->setNextBatchToken(QString::fromStdString(response.next_batch)); client_->sync(); emit contentLoaded(); @@ -527,8 +517,8 @@ ChatPage::loadStateFromCache() // Resolve user avatars. for (const auto membership : room_state.memberships) { - updateUserDisplayName(membership); - updateUserAvatarUrl(membership); + updateUserDisplayName(membership.second); + updateUserAvatarUrl(membership.second); } } @@ -579,7 +569,8 @@ ChatPage::showQuickSwitcher() QMap rooms; for (auto it = state_manager_.constBegin(); it != state_manager_.constEnd(); ++it) { - QString deambiguator = it.value().canonical_alias.content().alias(); + QString deambiguator = + QString::fromStdString(it.value().canonical_alias.content.alias); if (deambiguator == "") deambiguator = it.key(); rooms.insert(it.value().getName() + " (" + deambiguator + ")", it.key()); @@ -623,7 +614,7 @@ ChatPage::removeRoom(const QString &room_id) } void -ChatPage::updateTypingUsers(const QString &roomid, const QList &user_ids) +ChatPage::updateTypingUsers(const QString &roomid, const std::vector &user_ids) { QStringList users; @@ -631,9 +622,12 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList &user_id QString user_id = settings.value("auth/user_id").toString(); for (const auto uid : user_ids) { - if (uid == user_id) + auto user = QString::fromStdString(uid); + + if (user == user_id) continue; - users.append(TimelineViewManager::displayName(uid)); + + users.append(TimelineViewManager::displayName(user)); } users.sort(); @@ -646,186 +640,118 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList &user_id } void -ChatPage::updateUserMetadata(const QJsonArray &events) -{ - events::EventType ty; - - for (const auto &event : events) { - try { - ty = events::extractEventType(event.toObject()); - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - continue; - } - - if (!events::isStateEvent(ty)) - continue; - - try { - switch (ty) { - case events::EventType::RoomMember: { - events::StateEvent member; - member.deserialize(event); - - updateUserAvatarUrl(member); - updateUserDisplayName(member); - - break; - } - default: { - continue; - } - } - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - continue; - } - } -} - -void -ChatPage::updateUserAvatarUrl(const events::StateEvent &membership) +ChatPage::updateUserAvatarUrl(const mtx::events::StateEvent &membership) { - auto uid = membership.sender(); - auto url = membership.content().avatarUrl(); + auto uid = QString::fromStdString(membership.sender); + auto url = QString::fromStdString(membership.content.avatar_url); - if (!url.toString().isEmpty()) + if (!url.isEmpty()) AvatarProvider::setAvatarUrl(uid, url); } void -ChatPage::updateUserDisplayName(const events::StateEvent &membership) +ChatPage::updateUserDisplayName( + const mtx::events::StateEvent &membership) { - auto displayName = membership.content().displayName(); + auto displayName = QString::fromStdString(membership.content.display_name); + auto stateKey = QString::fromStdString(membership.state_key); if (!displayName.isEmpty()) - TimelineViewManager::DISPLAY_NAMES.insert(membership.stateKey(), displayName); + TimelineViewManager::DISPLAY_NAMES.insert(stateKey, displayName); } void -ChatPage::removeLeftRooms(const QMap &rooms) +ChatPage::removeLeftRooms(const std::map &rooms) { - for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) { - if (state_manager_.contains(it.key())) - removeRoom(it.key()); + for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) { + const auto room_id = QString::fromStdString(it->first); + + if (state_manager_.contains(room_id)) + removeRoom(room_id); } } void -ChatPage::updateJoinedRooms(const QMap &rooms) +ChatPage::updateJoinedRooms(const std::map &rooms) { - for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) { - updateTypingUsers(it.key(), it.value().typingUserIDs()); + for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) { + const auto roomid = QString::fromStdString(it->first); + + updateTypingUsers(roomid, it->second.ephemeral.typing); - const auto newStateEvents = it.value().state().events(); - const auto newTimelineEvents = it.value().timeline().events(); + const auto newStateEvents = it->second.state; + const auto newTimelineEvents = it->second.timeline; // Merge the new updates for rooms that we are tracking. - if (state_manager_.contains(it.key())) { - auto oldState = &state_manager_[it.key()]; - oldState->updateFromEvents(newStateEvents); - oldState->updateFromEvents(newTimelineEvents); + if (state_manager_.contains(roomid)) { + auto oldState = &state_manager_[roomid]; + oldState->updateFromEvents(newStateEvents.events); + oldState->updateFromEvents(newTimelineEvents.events); oldState->resolveName(); oldState->resolveAvatar(); } else { // Build the current state from the timeline and state events. RoomState room_state; - room_state.updateFromEvents(newStateEvents); - room_state.updateFromEvents(newTimelineEvents); + room_state.updateFromEvents(newStateEvents.events); + room_state.updateFromEvents(newTimelineEvents.events); // Resolve room name and avatar. e.g in case of one-to-one chats. room_state.resolveName(); room_state.resolveAvatar(); - state_manager_.insert(it.key(), room_state); + state_manager_.insert(roomid, room_state); settingsManager_.insert( - it.key(), QSharedPointer(new RoomSettings(it.key()))); + roomid, QSharedPointer(new RoomSettings(roomid))); - view_manager_->addRoom(it.value(), it.key()); + view_manager_->addRoom(it->second, roomid); } - updateUserMetadata(newStateEvents); - updateUserMetadata(newTimelineEvents); + updateUserMetadata(newStateEvents.events); + updateUserMetadata(newTimelineEvents.events); - if (it.key() == current_room_) - changeTopRoomInfo(it.key()); + if (roomid == current_room_) + changeTopRoomInfo(roomid); QApplication::processEvents(); } } QMap -ChatPage::generateMembershipDifference(const QMap &rooms, - const QMap &states) const +ChatPage::generateMembershipDifference( + const std::map &rooms, + const QMap &states) const { QMap stateDiff; - for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) { - if (!states.contains(it.key())) + for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) { + const auto room_id = QString::fromStdString(it->first); + + if (!states.contains(room_id)) continue; - auto events = it.value().state().events(); + auto all_memberships = getMemberships(it->second.state.events); + auto timelineMemberships = getMemberships(it->second.timeline.events); - for (auto event : it.value().timeline().events()) - events.append(event); + // We have to process first the state events and then the timeline. + for (auto mm = timelineMemberships.cbegin(); mm != timelineMemberships.cend(); ++mm) + all_memberships.emplace(mm->first, mm->second); RoomState local; - local.aliases = states[it.key()].aliases; - local.avatar = states[it.key()].avatar; - local.canonical_alias = states[it.key()].canonical_alias; - local.history_visibility = states[it.key()].history_visibility; - local.join_rules = states[it.key()].join_rules; - local.name = states[it.key()].name; - local.power_levels = states[it.key()].power_levels; - local.topic = states[it.key()].topic; - local.memberships = getMemberships(events); - - stateDiff.insert(it.key(), local); + local.aliases = states[room_id].aliases; + local.avatar = states[room_id].avatar; + local.canonical_alias = states[room_id].canonical_alias; + local.history_visibility = states[room_id].history_visibility; + local.join_rules = states[room_id].join_rules; + local.name = states[room_id].name; + local.power_levels = states[room_id].power_levels; + local.topic = states[room_id].topic; + local.memberships = all_memberships; + + stateDiff.insert(room_id, local); } return stateDiff; } -using Memberships = QMap>; - -Memberships -ChatPage::getMemberships(const QJsonArray &events) const -{ - Memberships memberships; - - events::EventType ty; - - for (const auto &event : events) { - try { - ty = events::extractEventType(event.toObject()); - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - continue; - } - - if (!events::isStateEvent(ty)) - continue; - - try { - switch (ty) { - case events::EventType::RoomMember: { - events::StateEvent member; - member.deserialize(event); - memberships.insert(member.stateKey(), member); - break; - } - default: { - continue; - } - } - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - continue; - } - } - - return memberships; -} - ChatPage::~ChatPage() {} diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc index e4dcb55..3a987d2 100644 --- a/src/MatrixClient.cc +++ b/src/MatrixClient.cc @@ -30,12 +30,7 @@ #include "Login.h" #include "MatrixClient.h" -#include "MessageEvent.h" #include "Register.h" -#include "RoomMessages.h" -#include "Sync.h" - -#include "mtx.hpp" MatrixClient::MatrixClient(QString server, QObject *parent) : QNetworkAccessManager(parent) @@ -239,26 +234,17 @@ MatrixClient::sync() noexcept return; } - auto data = reply->readAll(); - - if (data.isEmpty()) - return; - - auto json = QJsonDocument::fromJson(data); - - SyncResponse response; - try { - response.deserialize(json); + mtx::responses::Sync response = nlohmann::json::parse(reply->readAll()); emit syncCompleted(response); - } catch (DeserializationException &e) { + } catch (std::exception &e) { qWarning() << "Sync malformed response" << e.what(); } }); } void -MatrixClient::sendRoomMessage(matrix::events::MessageEventType ty, +MatrixClient::sendRoomMessage(mtx::events::MessageType ty, int txnId, const QString &roomid, const QString &msg, @@ -283,19 +269,19 @@ MatrixClient::sendRoomMessage(matrix::events::MessageEventType ty, QJsonObject info = {{"size", fileinfo.size()}, {"mimetype", mime.name()}}; switch (ty) { - case matrix::events::MessageEventType::Text: + case mtx::events::MessageType::Text: body = {{"msgtype", "m.text"}, {"body", msg}}; break; - case matrix::events::MessageEventType::Emote: + case mtx::events::MessageType::Emote: body = {{"msgtype", "m.emote"}, {"body", msg}}; break; - case matrix::events::MessageEventType::Image: + case mtx::events::MessageType::Image: body = {{"msgtype", "m.image"}, {"body", msg}, {"url", url}, {"info", info}}; break; - case matrix::events::MessageEventType::File: + case mtx::events::MessageType::File: body = {{"msgtype", "m.file"}, {"body", msg}, {"url", url}, {"info", info}}; break; - case matrix::events::MessageEventType::Audio: + case mtx::events::MessageType::Audio: body = {{"msgtype", "m.audio"}, {"body", msg}, {"url", url}, {"info", info}}; break; default: @@ -371,23 +357,14 @@ MatrixClient::initialSync() noexcept return; } - auto data = reply->readAll(); - - if (data.isEmpty()) - return; - - auto json = QJsonDocument::fromJson(data); - - SyncResponse response; - try { - response.deserialize(json); + mtx::responses::Sync response = nlohmann::json::parse(reply->readAll()); + emit initialSyncCompleted(response); } catch (DeserializationException &e) { qWarning() << "Sync malformed response" << e.what(); return; } - emit initialSyncCompleted(response); }); } @@ -686,18 +663,15 @@ MatrixClient::messages(const QString &roomid, const QString &from_token, int lim return; } - auto data = reply->readAll(); - - RoomMessages msgs; - try { - msgs.deserialize(QJsonDocument::fromJson(data)); - } catch (const DeserializationException &e) { + mtx::responses::Messages messages = + nlohmann::json::parse(reply->readAll().data()); + + emit messagesRetrieved(roomid, messages); + } catch (std::exception &e) { qWarning() << "Room messages from" << roomid << e.what(); return; } - - emit messagesRetrieved(roomid, msgs); }); } diff --git a/src/RoomList.cc b/src/RoomList.cc index 23c0c5a..a892e40 100644 --- a/src/RoomList.cc +++ b/src/RoomList.cc @@ -25,7 +25,6 @@ #include "RoomList.h" #include "RoomSettings.h" #include "RoomState.h" -#include "Sync.h" RoomList::RoomList(QSharedPointer client, QWidget *parent) : QWidget(parent) diff --git a/src/RoomState.cc b/src/RoomState.cc index 2b8bcdb..2bfea17 100644 --- a/src/RoomState.cc +++ b/src/RoomState.cc @@ -15,15 +15,19 @@ * along with this program. If not, see . */ +#include #include +#include #include #include "RoomState.h" -namespace events = matrix::events; - RoomState::RoomState() {} -RoomState::RoomState(const QJsonArray &events) { updateFromEvents(events); } +RoomState::RoomState(const mtx::responses::Timeline &timeline) +{ + updateFromEvents(timeline.events); +} +RoomState::RoomState(const mtx::responses::State &state) { updateFromEvents(state.events); } void RoomState::resolveName() @@ -31,19 +35,19 @@ RoomState::resolveName() name_ = "Empty Room"; userAvatar_.clear(); - if (!name.content().name().isEmpty()) { - name_ = name.content().name().simplified(); + if (!name.content.name.empty()) { + name_ = QString::fromStdString(name.content.name).simplified(); return; } - if (!canonical_alias.content().alias().isEmpty()) { - name_ = canonical_alias.content().alias().simplified(); + if (!canonical_alias.content.alias.empty()) { + name_ = QString::fromStdString(canonical_alias.content.alias).simplified(); return; } // FIXME: Doesn't follow the spec guidelines. - if (aliases.content().aliases().size() != 0) { - name_ = aliases.content().aliases()[0].simplified(); + if (aliases.content.aliases.size() != 0) { + name_ = QString::fromStdString(aliases.content.aliases[0]).simplified(); return; } @@ -52,16 +56,20 @@ RoomState::resolveName() // TODO: Display names should be sorted alphabetically. for (const auto membership : memberships) { - if (membership.stateKey() == user_id) + const auto stateKey = QString::fromStdString(membership.second.state_key); + + if (stateKey == user_id) continue; - if (membership.content().membershipState() == events::Membership::Join) { - userAvatar_ = membership.stateKey(); + if (membership.second.content.membership == mtx::events::state::Membership::Join) { + userAvatar_ = stateKey; + auto displayName = + QString::fromStdString(membership.second.content.display_name); - if (membership.content().displayName().isEmpty()) - name_ = membership.stateKey(); + if (displayName.isEmpty()) + name_ = stateKey; else - name_ = membership.content().displayName(); + name_ = displayName; break; } @@ -76,12 +84,13 @@ void RoomState::resolveAvatar() { if (userAvatar_.isEmpty()) { - avatar_ = avatar.content().url(); + avatar_ = QString::fromStdString(avatar.content.url); return; } - if (memberships.contains(userAvatar_)) { - avatar_ = memberships[userAvatar_].content().avatarUrl(); + if (memberships.count(userAvatar_.toStdString()) != 0) { + avatar_ = + QString::fromStdString(memberships[userAvatar_.toStdString()].content.avatar_url); } else { qWarning() << "Setting room avatar from unknown user id" << userAvatar_; } @@ -91,8 +100,8 @@ RoomState::resolveAvatar() void RoomState::removeLeaveMemberships() { - for (auto it = memberships.begin(); it != memberships.end();) { - if (it.value().content().membershipState() == events::Membership::Leave) { + for (auto it = memberships.cbegin(); it != memberships.cend();) { + if (it->second.content.membership == mtx::events::state::Membership::Leave) { it = memberships.erase(it); } else { ++it; @@ -106,49 +115,51 @@ RoomState::update(const RoomState &state) bool needsNameCalculation = false; bool needsAvatarCalculation = false; - if (aliases.eventId() != state.aliases.eventId()) { + if (aliases.event_id != state.aliases.event_id) aliases = state.aliases; - } - if (avatar.eventId() != state.avatar.eventId()) { + if (avatar.event_id != state.avatar.event_id) { avatar = state.avatar; needsAvatarCalculation = true; } - if (canonical_alias.eventId() != state.canonical_alias.eventId()) { + if (canonical_alias.event_id != state.canonical_alias.event_id) { canonical_alias = state.canonical_alias; needsNameCalculation = true; } - if (create.eventId() != state.create.eventId()) + if (create.event_id != state.create.event_id) create = state.create; - if (history_visibility.eventId() != state.history_visibility.eventId()) + + if (history_visibility.event_id != state.history_visibility.event_id) history_visibility = state.history_visibility; - if (join_rules.eventId() != state.join_rules.eventId()) + + if (join_rules.event_id != state.join_rules.event_id) join_rules = state.join_rules; - if (name.eventId() != state.name.eventId()) { + if (name.event_id != state.name.event_id) { name = state.name; needsNameCalculation = true; } - if (power_levels.eventId() != state.power_levels.eventId()) + if (power_levels.event_id != state.power_levels.event_id) power_levels = state.power_levels; - if (topic.eventId() != state.topic.eventId()) + + if (topic.event_id != state.topic.event_id) topic = state.topic; - for (auto it = state.memberships.constBegin(); it != state.memberships.constEnd(); ++it) { - auto membershipState = it.value().content().membershipState(); + for (auto it = state.memberships.cbegin(); it != state.memberships.cend(); ++it) { + auto membershipState = it->second.content.membership; - if (it.key() == userAvatar_) { + if (it->first == userAvatar_.toStdString()) { needsNameCalculation = true; needsAvatarCalculation = true; } - if (membershipState == events::Membership::Leave) - this->memberships.remove(it.key()); + if (membershipState == mtx::events::state::Membership::Leave) + this->memberships.erase(this->memberships.find(it->first)); else - this->memberships.insert(it.key(), it.value()); + this->memberships.emplace(it->first, it->second); } if (needsNameCalculation) @@ -158,235 +169,126 @@ RoomState::update(const RoomState &state) resolveAvatar(); } -QJsonObject +std::string RoomState::serialize() const { - QJsonObject obj; + nlohmann::json obj; - if (!aliases.eventId().isEmpty()) - obj["aliases"] = aliases.serialize(); + if (!aliases.event_id.empty()) + obj["aliases"] = aliases; - if (!avatar.eventId().isEmpty()) - obj["avatar"] = avatar.serialize(); + if (!avatar.event_id.empty()) + obj["avatar"] = avatar; - if (!canonical_alias.eventId().isEmpty()) - obj["canonical_alias"] = canonical_alias.serialize(); + if (!canonical_alias.event_id.empty()) + obj["canonical_alias"] = canonical_alias; - if (!create.eventId().isEmpty()) - obj["create"] = create.serialize(); + if (!create.event_id.empty()) + obj["create"] = create; - if (!history_visibility.eventId().isEmpty()) - obj["history_visibility"] = history_visibility.serialize(); + if (!history_visibility.event_id.empty()) + obj["history_visibility"] = history_visibility; - if (!join_rules.eventId().isEmpty()) - obj["join_rules"] = join_rules.serialize(); + if (!join_rules.event_id.empty()) + obj["join_rules"] = join_rules; - if (!name.eventId().isEmpty()) - obj["name"] = name.serialize(); + if (!name.event_id.empty()) + obj["name"] = name; - if (!power_levels.eventId().isEmpty()) - obj["power_levels"] = power_levels.serialize(); + if (!power_levels.event_id.empty()) + obj["power_levels"] = power_levels; - if (!topic.eventId().isEmpty()) - obj["topic"] = topic.serialize(); + if (!topic.event_id.empty()) + obj["topic"] = topic; - return obj; + return obj.dump(); } void -RoomState::parse(const QJsonObject &object) +RoomState::parse(const nlohmann::json &object) { - // FIXME: Make this less versbose. - - if (object.contains("aliases")) { - events::StateEvent event; - + if (object.count("aliases") != 0) { try { - event.deserialize(object["aliases"]); - aliases = event; - } catch (const DeserializationException &e) { + aliases = object.at("aliases") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - aliases" << e.what(); } } - if (object.contains("avatar")) { - events::StateEvent event; - + if (object.count("avatar") != 0) { try { - event.deserialize(object["avatar"]); - avatar = event; - } catch (const DeserializationException &e) { + avatar = object.at("avatar") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - avatar" << e.what(); } } - if (object.contains("canonical_alias")) { - events::StateEvent event; - + if (object.count("canonical_alias") != 0) { try { - event.deserialize(object["canonical_alias"]); - canonical_alias = event; - } catch (const DeserializationException &e) { + canonical_alias = + object.at("canonical_alias") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - canonical_alias" << e.what(); } } - if (object.contains("create")) { - events::StateEvent event; - + if (object.count("create") != 0) { try { - event.deserialize(object["create"]); - create = event; - } catch (const DeserializationException &e) { + create = object.at("create") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - create" << e.what(); } } - if (object.contains("history_visibility")) { - events::StateEvent event; - + if (object.count("history_visibility") != 0) { try { - event.deserialize(object["history_visibility"]); - history_visibility = event; - } catch (const DeserializationException &e) { + history_visibility = + object.at("history_visibility") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - history_visibility" << e.what(); } } - if (object.contains("join_rules")) { - events::StateEvent event; - + if (object.count("join_rules") != 0) { try { - event.deserialize(object["join_rules"]); - join_rules = event; - } catch (const DeserializationException &e) { + join_rules = + object.at("join_rules") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - join_rules" << e.what(); } } - if (object.contains("name")) { - events::StateEvent event; - + if (object.count("name") != 0) { try { - event.deserialize(object["name"]); - name = event; - } catch (const DeserializationException &e) { + name = object.at("name") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - name" << e.what(); } } - if (object.contains("power_levels")) { - events::StateEvent event; - + if (object.count("power_levels") != 0) { try { - event.deserialize(object["power_levels"]); - power_levels = event; - } catch (const DeserializationException &e) { + power_levels = + object.at("power_levels") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - power_levels" << e.what(); } } - if (object.contains("topic")) { - events::StateEvent event; - + if (object.count("topic") != 0) { try { - event.deserialize(object["topic"]); - topic = event; - } catch (const DeserializationException &e) { + topic = object.at("topic") + .get>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - topic" << e.what(); } } } - -void -RoomState::updateFromEvents(const QJsonArray &events) -{ - events::EventType ty; - - for (const auto &event : events) { - try { - ty = events::extractEventType(event.toObject()); - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - continue; - } - - if (!events::isStateEvent(ty)) - continue; - - try { - switch (ty) { - case events::EventType::RoomAliases: { - events::StateEvent aliases; - aliases.deserialize(event); - this->aliases = aliases; - break; - } - case events::EventType::RoomAvatar: { - events::StateEvent avatar; - avatar.deserialize(event); - this->avatar = avatar; - break; - } - case events::EventType::RoomCanonicalAlias: { - events::StateEvent - canonical_alias; - canonical_alias.deserialize(event); - this->canonical_alias = canonical_alias; - break; - } - case events::EventType::RoomCreate: { - events::StateEvent create; - create.deserialize(event); - this->create = create; - break; - } - case events::EventType::RoomHistoryVisibility: { - events::StateEvent - history_visibility; - history_visibility.deserialize(event); - this->history_visibility = history_visibility; - break; - } - case events::EventType::RoomJoinRules: { - events::StateEvent join_rules; - join_rules.deserialize(event); - this->join_rules = join_rules; - break; - } - case events::EventType::RoomName: { - events::StateEvent name; - name.deserialize(event); - this->name = name; - break; - } - case events::EventType::RoomMember: { - events::StateEvent member; - member.deserialize(event); - - this->memberships.insert(member.stateKey(), member); - - break; - } - case events::EventType::RoomPowerLevels: { - events::StateEvent power_levels; - power_levels.deserialize(event); - this->power_levels = power_levels; - break; - } - case events::EventType::RoomTopic: { - events::StateEvent topic; - topic.deserialize(event); - this->topic = topic; - break; - } - default: { - continue; - } - } - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - continue; - } - } -} diff --git a/src/Sync.cc b/src/Sync.cc deleted file mode 100644 index 416fa0c..0000000 --- a/src/Sync.cc +++ /dev/null @@ -1,307 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "Sync.h" - -void -SyncResponse::deserialize(const QJsonDocument &data) -{ - if (!data.isObject()) - throw DeserializationException("Sync response is not a JSON object"); - - QJsonObject object = data.object(); - - if (!object.contains("next_batch")) - throw DeserializationException("Sync: missing next_batch parameter"); - - if (object.contains("rooms")) { - if (!object.value("rooms").isObject()) { - throw DeserializationException("Sync: rooms is not a JSON object"); - } - rooms_.deserialize(object.value("rooms")); - } - - if (object.contains("presence")) { - if (!object.value("presence").isObject()) { - throw DeserializationException("Sync: presence is not a JSON object"); - } - // TODO: implement presence handling - } - - if (object.contains("account_data")) { - if (!object.value("account_data").isObject()) { - throw DeserializationException("Sync: account_data is not a JSON object"); - } - // TODO: implement account_data handling - } - - if (object.contains("to_device")) { - if (!object.value("to_device").isObject()) { - throw DeserializationException("Sync: to_device is not a JSON object"); - } - // TODO: implement to_device handling - } - - // for device_lists updates (for e2e) - if (object.contains("device_lists")) { - if (!object.value("device_lists").isObject()) { - throw DeserializationException("Sync: device_lists is not a JSON object"); - } - // TODO: implement device_lists handling - } - - next_batch_ = object.value("next_batch").toString(); -} - -void -Rooms::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("Rooms value is not a JSON object"); - - QJsonObject object = data.toObject(); - - if (object.contains("join")) { - if (!object.value("join").isObject()) - throw DeserializationException("rooms/join must be a JSON object"); - - auto join = object.value("join").toObject(); - - for (auto it = join.constBegin(); it != join.constEnd(); ++it) { - JoinedRoom tmp_room; - try { - tmp_room.deserialize(it.value()); - join_.insert(it.key(), tmp_room); - } catch (DeserializationException &e) { - qWarning() << e.what(); - qWarning() << "Skipping malformed object for room" << it.key(); - } - } - } - - if (object.contains("invite")) { - if (!object.value("invite").isObject()) { - throw DeserializationException("rooms/invite must be a JSON object"); - } - // TODO: Implement invite handling - } - - if (object.contains("leave")) { - if (!object.value("leave").isObject()) { - throw DeserializationException("rooms/leave must be a JSON object"); - } - auto leave = object.value("leave").toObject(); - - for (auto it = leave.constBegin(); it != leave.constEnd(); ++it) { - LeftRoom tmp_room; - - try { - tmp_room.deserialize(it.value()); - leave_.insert(it.key(), tmp_room); - } catch (DeserializationException &e) { - qWarning() << e.what(); - qWarning() << "Skipping malformed object for room" << it.key(); - } - } - } -} - -void -JoinedRoom::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("JoinedRoom is not a JSON object"); - - QJsonObject object = data.toObject(); - - if (object.contains("state")) { - if (!object.value("state").isObject()) { - throw DeserializationException("join/state should be an object"); - } - - QJsonObject state = object.value("state").toObject(); - - if (state.contains("events")) { - if (!state.value("events").isArray()) { - throw DeserializationException( - "join/state/events should be an array"); - } - - state_.deserialize(state.value("events")); - } - } - - if (object.contains("timeline")) { - if (!object.value("timeline").isObject()) - throw DeserializationException("join/timeline should be an object"); - timeline_.deserialize(object.value("timeline")); - } - - if (object.contains("ephemeral")) { - if (!object.value("ephemeral").isObject()) - throw DeserializationException("join/ephemeral should be an object"); - - QJsonObject ephemeral = object.value("ephemeral").toObject(); - - if (ephemeral.contains("events")) { - if (!ephemeral.value("events").isArray()) - qWarning() << "join/ephemeral/events should be an array"; - - auto ephemeralEvents = ephemeral.value("events").toArray(); - - for (const auto e : ephemeralEvents) { - auto obj = e.toObject(); - - if (obj.contains("type") && obj.value("type") == "m.typing") { - auto ids = obj.value("content") - .toObject() - .value("user_ids") - .toArray(); - - for (const auto uid : ids) - typingUserIDs_.push_back(uid.toString()); - } - } - } - } - - if (object.contains("account_data")) { - if (!object.value("account_data").isObject()) - throw DeserializationException("join/account_data is not a JSON object"); - // TODO: Implement account_data handling - } - - if (object.contains("unread_notifications")) { - if (!object.value("unread_notifications").isObject()) { - throw DeserializationException( - "join/unread_notifications is not a JSON object"); - } - - QJsonObject unreadNotifications = object.value("unread_notifications").toObject(); - - if (unreadNotifications.contains("highlight_count")) { - // TODO: Implement unread_notifications handling - } - if (unreadNotifications.contains("notification_count")) { - // TODO: Implement unread_notifications handling - } - } -} - -void -LeftRoom::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("LeftRoom is not a JSON object"); - - QJsonObject object = data.toObject(); - - if (!object.contains("state")) - throw DeserializationException("leave/state is missing"); - - if (!object.contains("timeline")) - throw DeserializationException("leave/timeline is missing"); - - if (!object.value("state").isObject()) - throw DeserializationException("leave/state should be an object"); - - QJsonObject state = object.value("state").toObject(); - - if (!state.contains("events")) - throw DeserializationException("leave/state/events is missing"); - - state_.deserialize(state.value("events")); - timeline_.deserialize(object.value("timeline")); -} - -void -Event::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("Event is not a JSON object"); - - QJsonObject object = data.toObject(); - - if (!object.contains("content")) - throw DeserializationException("event/content is missing"); - - if (!object.contains("unsigned")) - throw DeserializationException("event/content is missing"); - - if (!object.contains("sender")) - throw DeserializationException("event/sender is missing"); - - if (!object.contains("event_id")) - throw DeserializationException("event/event_id is missing"); - - // TODO: Make this optional - /* if (!object.contains("state_key")) */ - /* throw DeserializationException("event/state_key is missing"); */ - - if (!object.contains("type")) - throw DeserializationException("event/type is missing"); - - if (!object.contains("origin_server_ts")) - throw DeserializationException("event/origin_server_ts is missing"); - - content_ = object.value("content").toObject(); - unsigned_ = object.value("unsigned").toObject(); - - sender_ = object.value("sender").toString(); - state_key_ = object.value("state_key").toString(); - type_ = object.value("type").toString(); - event_id_ = object.value("event_id").toString(); - - origin_server_ts_ = object.value("origin_server_ts").toDouble(); -} - -void -State::deserialize(const QJsonValue &data) -{ - if (!data.isArray()) - throw DeserializationException("State is not a JSON array"); - - events_ = data.toArray(); -} - -void -Timeline::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("Timeline is not a JSON object"); - - auto object = data.toObject(); - - if (!object.contains("events")) - throw DeserializationException("timeline/events is missing"); - - if (!object.contains("prev_batch")) - throw DeserializationException("timeline/prev_batch is missing"); - - if (!object.contains("limited")) - throw DeserializationException("timeline/limited is missing"); - - prev_batch_ = object.value("prev_batch").toString(); - limited_ = object.value("limited").toBool(); - - if (!object.value("events").isArray()) - throw DeserializationException("timeline/events is not a JSON array"); - - events_ = object.value("events").toArray(); -} diff --git a/src/events/AliasesEventContent.cc b/src/events/AliasesEventContent.cc deleted file mode 100644 index 87acbad..0000000 --- a/src/events/AliasesEventContent.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "AliasesEventContent.h" - -using namespace matrix::events; - -void -AliasesEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("AliasesEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("aliases") == QJsonValue::Undefined) - throw DeserializationException("aliases key is missing"); - - auto aliases = object.value("aliases").toArray(); - - for (const auto &alias : aliases) - aliases_.push_back(alias.toString()); -} - -QJsonObject -AliasesEventContent::serialize() const -{ - QJsonObject object; - - QJsonArray aliases; - - for (const auto &alias : aliases_) - aliases.push_back(alias); - - if (aliases.size() > 0) - object["aliases"] = aliases; - - return object; -} diff --git a/src/events/AvatarEventContent.cc b/src/events/AvatarEventContent.cc deleted file mode 100644 index fc58ad5..0000000 --- a/src/events/AvatarEventContent.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "AvatarEventContent.h" - -using namespace matrix::events; - -void -AvatarEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("AvatarEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("url") == QJsonValue::Undefined) - throw DeserializationException("url key is missing"); - - url_ = QUrl(object.value("url").toString()); - - if (!url_.isValid()) - qWarning() << "Invalid avatar url" << url_; -} - -QJsonObject -AvatarEventContent::serialize() const -{ - QJsonObject object; - - if (!url_.isEmpty()) - object["url"] = url_.toString(); - - return object; -} diff --git a/src/events/CanonicalAliasEventContent.cc b/src/events/CanonicalAliasEventContent.cc deleted file mode 100644 index 189a0cb..0000000 --- a/src/events/CanonicalAliasEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "CanonicalAliasEventContent.h" - -using namespace matrix::events; - -void -CanonicalAliasEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("CanonicalAliasEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("alias") == QJsonValue::Undefined) - throw DeserializationException("alias key is missing"); - - alias_ = object.value("alias").toString(); -} - -QJsonObject -CanonicalAliasEventContent::serialize() const -{ - QJsonObject object; - - if (!alias_.isEmpty()) - object["alias"] = alias_; - - return object; -} diff --git a/src/events/CreateEventContent.cc b/src/events/CreateEventContent.cc deleted file mode 100644 index f28099c..0000000 --- a/src/events/CreateEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "CreateEventContent.h" - -using namespace matrix::events; - -void -CreateEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("CreateEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("creator") == QJsonValue::Undefined) - throw DeserializationException("creator key is missing"); - - creator_ = object.value("creator").toString(); -} - -QJsonObject -CreateEventContent::serialize() const -{ - QJsonObject object; - - if (!creator_.isEmpty()) - object["creator"] = creator_; - - return object; -} diff --git a/src/events/Event.cc b/src/events/Event.cc deleted file mode 100644 index 7e5bd1d..0000000 --- a/src/events/Event.cc +++ /dev/null @@ -1,106 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "events/Event.h" - -#include "AliasesEventContent.h" -#include "AvatarEventContent.h" -#include "CanonicalAliasEventContent.h" -#include "CreateEventContent.h" -#include "Deserializable.h" -#include "HistoryVisibilityEventContent.h" -#include "JoinRulesEventContent.h" -#include "MemberEventContent.h" -#include "NameEventContent.h" -#include "PowerLevelsEventContent.h" -#include "TopicEventContent.h" - -matrix::events::EventType -matrix::events::extractEventType(const QJsonObject &object) -{ - if (!object.contains("type")) - throw DeserializationException("Missing event type"); - - auto type = object.value("type").toString(); - - if (type == "m.room.aliases") - return EventType::RoomAliases; - else if (type == "m.room.avatar") - return EventType::RoomAvatar; - else if (type == "m.room.canonical_alias") - return EventType::RoomCanonicalAlias; - else if (type == "m.room.create") - return EventType::RoomCreate; - else if (type == "m.room.history_visibility") - return EventType::RoomHistoryVisibility; - else if (type == "m.room.join_rules") - return EventType::RoomJoinRules; - else if (type == "m.room.member") - return EventType::RoomMember; - else if (type == "m.room.message") - return EventType::RoomMessage; - else if (type == "m.room.name") - return EventType::RoomName; - else if (type == "m.room.power_levels") - return EventType::RoomPowerLevels; - else if (type == "m.room.topic") - return EventType::RoomTopic; - else - return EventType::Unsupported; -} - -bool -matrix::events::isStateEvent(EventType type) -{ - return type == EventType::RoomAliases || type == EventType::RoomAvatar || - type == EventType::RoomCanonicalAlias || type == EventType::RoomCreate || - type == EventType::RoomHistoryVisibility || type == EventType::RoomJoinRules || - type == EventType::RoomMember || type == EventType::RoomName || - type == EventType::RoomPowerLevels || type == EventType::RoomTopic; -} - -bool -matrix::events::isMessageEvent(EventType type) -{ - return type == EventType::RoomMessage; -} - -void -matrix::events::UnsignedData::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("UnsignedData is not a JSON object"); - - auto object = data.toObject(); - - transaction_id_ = object.value("transaction_id").toString(); - age_ = object.value("age").toDouble(); -} - -QJsonObject -matrix::events::UnsignedData::serialize() const -{ - QJsonObject object; - - if (!transaction_id_.isEmpty()) - object["transaction_id"] = transaction_id_; - - if (age_ > 0) - object["age"] = age_; - - return object; -} diff --git a/src/events/HistoryVisibilityEventContent.cc b/src/events/HistoryVisibilityEventContent.cc deleted file mode 100644 index 7c0a149..0000000 --- a/src/events/HistoryVisibilityEventContent.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "HistoryVisibilityEventContent.h" - -using namespace matrix::events; - -void -HistoryVisibilityEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException( - "HistoryVisibilityEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("history_visibility") == QJsonValue::Undefined) - throw DeserializationException("history_visibility key is missing"); - - auto value = object.value("history_visibility").toString(); - - if (value == "invited") - history_visibility_ = HistoryVisibility::Invited; - else if (value == "joined") - history_visibility_ = HistoryVisibility::Joined; - else if (value == "shared") - history_visibility_ = HistoryVisibility::Shared; - else if (value == "world_readable") - history_visibility_ = HistoryVisibility::WorldReadable; - else - throw DeserializationException( - QString("Unknown history_visibility value: %1").arg(value).toUtf8().constData()); -} - -QJsonObject -HistoryVisibilityEventContent::serialize() const -{ - QJsonObject object; - - if (history_visibility_ == HistoryVisibility::Invited) - object["history_visibility"] = "invited"; - else if (history_visibility_ == HistoryVisibility::Joined) - object["history_visibility"] = "joined"; - else if (history_visibility_ == HistoryVisibility::Shared) - object["history_visibility"] = "shared"; - else if (history_visibility_ == HistoryVisibility::WorldReadable) - object["history_visibility"] = "world_readable"; - - return object; -} diff --git a/src/events/JoinRulesEventContent.cc b/src/events/JoinRulesEventContent.cc deleted file mode 100644 index 4f5cf6e..0000000 --- a/src/events/JoinRulesEventContent.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "JoinRulesEventContent.h" - -using namespace matrix::events; - -void -JoinRulesEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("JoinRulesEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("join_rule") == QJsonValue::Undefined) - throw DeserializationException("join_rule key is missing"); - - auto value = object.value("join_rule").toString(); - - if (value == "invite") - join_rule_ = JoinRule::Invite; - else if (value == "knock") - join_rule_ = JoinRule::Knock; - else if (value == "private") - join_rule_ = JoinRule::Private; - else if (value == "public") - join_rule_ = JoinRule::Public; - else - throw DeserializationException( - QString("Unknown join_rule value: %1").arg(value).toUtf8().constData()); -} - -QJsonObject -JoinRulesEventContent::serialize() const -{ - QJsonObject object; - - if (join_rule_ == JoinRule::Invite) - object["join_rule"] = "invite"; - else if (join_rule_ == JoinRule::Knock) - object["join_rule"] = "knock"; - else if (join_rule_ == JoinRule::Private) - object["join_rule"] = "private"; - else if (join_rule_ == JoinRule::Public) - object["join_rule"] = "public"; - - return object; -} diff --git a/src/events/MemberEventContent.cc b/src/events/MemberEventContent.cc deleted file mode 100644 index f80130e..0000000 --- a/src/events/MemberEventContent.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "MemberEventContent.h" - -using namespace matrix::events; - -void -MemberEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("MemberEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (!object.contains("membership")) - throw DeserializationException("membership key is missing"); - - auto value = object.value("membership").toString(); - - if (value == "ban") - membership_state_ = Membership::Ban; - else if (value == "invite") - membership_state_ = Membership::Invite; - else if (value == "join") - membership_state_ = Membership::Join; - else if (value == "knock") - membership_state_ = Membership::Knock; - else if (value == "leave") - membership_state_ = Membership::Leave; - else - throw DeserializationException( - QString("Unknown membership value: %1").arg(value).toUtf8().constData()); - - if (object.contains("avatar_url")) - avatar_url_ = QUrl(object.value("avatar_url").toString()); - - if (!avatar_url_.toString().isEmpty() && !avatar_url_.isValid()) - qWarning() << "Invalid avatar url" << avatar_url_; - - if (object.contains("displayname")) - display_name_ = object.value("displayname").toString(); -} - -QJsonObject -MemberEventContent::serialize() const -{ - QJsonObject object; - - if (membership_state_ == Membership::Ban) - object["membership"] = "ban"; - else if (membership_state_ == Membership::Invite) - object["membership"] = "invite"; - else if (membership_state_ == Membership::Join) - object["membership"] = "join"; - else if (membership_state_ == Membership::Knock) - object["membership"] = "knock"; - else if (membership_state_ == Membership::Leave) - object["membership"] = "leave"; - - if (!avatar_url_.isEmpty()) - object["avatar_url"] = avatar_url_.toString(); - - if (!display_name_.isEmpty()) - object["displayname"] = display_name_; - - return object; -} diff --git a/src/events/MessageEventContent.cc b/src/events/MessageEventContent.cc deleted file mode 100644 index fcf25da..0000000 --- a/src/events/MessageEventContent.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "MessageEventContent.h" - -using namespace matrix::events; - -MessageEventType -matrix::events::extractMessageEventType(const QJsonObject &data) -{ - if (!data.contains("content")) - return MessageEventType::Unknown; - - auto content = data.value("content").toObject(); - auto msgtype = content.value("msgtype").toString(); - - if (msgtype == "m.audio") - return MessageEventType::Audio; - else if (msgtype == "m.emote") - return MessageEventType::Emote; - else if (msgtype == "m.file") - return MessageEventType::File; - else if (msgtype == "m.image") - return MessageEventType::Image; - else if (msgtype == "m.location") - return MessageEventType::Location; - else if (msgtype == "m.notice") - return MessageEventType::Notice; - else if (msgtype == "m.text") - return MessageEventType::Text; - else if (msgtype == "m.video") - return MessageEventType::Video; - else - return MessageEventType::Unknown; -} - -void -MessageEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("MessageEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (!object.contains("body")) - throw DeserializationException("body key is missing"); - - body_ = object.value("body").toString(); -} - -QJsonObject -MessageEventContent::serialize() const -{ - // TODO: Add for all the message contents. - QJsonObject object; - - return object; -} diff --git a/src/events/NameEventContent.cc b/src/events/NameEventContent.cc deleted file mode 100644 index 45759cf..0000000 --- a/src/events/NameEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "NameEventContent.h" - -using namespace matrix::events; - -void -NameEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("NameEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("name") == QJsonValue::Undefined) - throw DeserializationException("name key is missing"); - - name_ = object.value("name").toString(); -} - -QJsonObject -NameEventContent::serialize() const -{ - QJsonObject object; - - if (!name_.isEmpty()) - object["name"] = name_; - - return object; -} diff --git a/src/events/PowerLevelsEventContent.cc b/src/events/PowerLevelsEventContent.cc deleted file mode 100644 index c796f81..0000000 --- a/src/events/PowerLevelsEventContent.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "Deserializable.h" -#include "PowerLevelsEventContent.h" - -using namespace matrix::events; - -void -PowerLevelsEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("PowerLevelsEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("ban") != QJsonValue::Undefined) - ban_ = object.value("ban").toInt(); - - if (object.value("invite") != QJsonValue::Undefined) - invite_ = object.value("invite").toInt(); - - if (object.value("kick") != QJsonValue::Undefined) - kick_ = object.value("kick").toInt(); - - if (object.value("redact") != QJsonValue::Undefined) - redact_ = object.value("redact").toInt(); - - if (object.value("events_default") != QJsonValue::Undefined) - events_default_ = object.value("events_default").toInt(); - - if (object.value("state_default") != QJsonValue::Undefined) - state_default_ = object.value("state_default").toInt(); - - if (object.value("users_default") != QJsonValue::Undefined) - users_default_ = object.value("users_default").toInt(); - - if (object.value("users").isObject()) { - auto users = object.value("users").toObject(); - - for (auto it = users.constBegin(); it != users.constEnd(); ++it) - users_.insert(it.key(), it.value().toInt()); - } - - if (object.value("events").isObject()) { - auto events = object.value("events").toObject(); - - for (auto it = events.constBegin(); it != events.constEnd(); ++it) - events_.insert(it.key(), it.value().toInt()); - } -} - -QJsonObject -PowerLevelsEventContent::serialize() const -{ - QJsonObject object; - - object["ban"] = ban_; - object["invite"] = invite_; - object["kick"] = kick_; - object["redact"] = redact_; - - object["events_default"] = events_default_; - object["users_default"] = users_default_; - object["state_default"] = state_default_; - - QJsonObject users; - QJsonObject events; - - for (auto it = users_.constBegin(); it != users_.constEnd(); ++it) - users.insert(it.key(), it.value()); - - for (auto it = events_.constBegin(); it != events_.constEnd(); ++it) - events.insert(it.key(), it.value()); - - object["users"] = users; - object["events"] = events; - - return object; -} - -int -PowerLevelsEventContent::eventLevel(QString event_type) const -{ - if (events_.contains(event_type)) - return events_[event_type]; - - return events_default_; -} - -int -PowerLevelsEventContent::userLevel(QString userid) const -{ - if (users_.contains(userid)) - return users_[userid]; - - return users_default_; -} diff --git a/src/events/TopicEventContent.cc b/src/events/TopicEventContent.cc deleted file mode 100644 index 89602de..0000000 --- a/src/events/TopicEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "TopicEventContent.h" - -using namespace matrix::events; - -void -TopicEventContent::deserialize(const QJsonValue &data) -{ - if (!data.isObject()) - throw DeserializationException("TopicEventContent is not a JSON object"); - - auto object = data.toObject(); - - if (object.value("topic") == QJsonValue::Undefined) - throw DeserializationException("topic key is missing"); - - topic_ = object.value("topic").toString(); -} - -QJsonObject -TopicEventContent::serialize() const -{ - QJsonObject object; - - if (!topic_.isEmpty()) - object["topic"] = topic_; - - return object; -} diff --git a/src/events/messages/Audio.cc b/src/events/messages/Audio.cc deleted file mode 100644 index 6b8f8c7..0000000 --- a/src/events/messages/Audio.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Audio.h" - -using namespace matrix::events::messages; - -void -Audio::deserialize(const QJsonObject &object) -{ - if (!object.contains("url")) - throw DeserializationException("url key is missing"); - - url_ = object.value("url").toString(); - - if (object.value("msgtype") != "m.audio") - throw DeserializationException("invalid msgtype for audio"); - - if (object.contains("info")) { - auto info = object.value("info").toObject(); - - info_.duration = info.value("duration").toInt(); - info_.mimetype = info.value("mimetype").toString(); - info_.size = info.value("size").toInt(); - } -} diff --git a/src/events/messages/Emote.cc b/src/events/messages/Emote.cc deleted file mode 100644 index 2c9ab82..0000000 --- a/src/events/messages/Emote.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Emote.h" - -using namespace matrix::events::messages; - -void -Emote::deserialize(const QJsonObject &object) -{ - if (object.value("msgtype") != "m.emote") - throw DeserializationException("invalid msgtype for emote"); -} diff --git a/src/events/messages/File.cc b/src/events/messages/File.cc deleted file mode 100644 index 28bce44..0000000 --- a/src/events/messages/File.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "File.h" - -using namespace matrix::events::messages; - -void -File::deserialize(const QJsonObject &object) -{ - if (!object.contains("url")) - throw DeserializationException("messages::File url key is missing"); - - if (object.value("msgtype") != "m.file") - throw DeserializationException("invalid msgtype for file"); - - url_ = object.value("url").toString(); - filename_ = object.value("filename").toString(); - - if (object.contains("info")) { - auto file_info = object.value("info").toObject(); - - info_.size = file_info.value("size").toInt(); - info_.mimetype = file_info.value("mimetype").toString(); - info_.thumbnail_url = file_info.value("thumbnail_url").toString(); - - if (file_info.contains("thumbnail_info")) { - auto thumbinfo = file_info.value("thumbnail_info").toObject(); - - info_.thumbnail_info.h = thumbinfo.value("h").toInt(); - info_.thumbnail_info.w = thumbinfo.value("w").toInt(); - info_.thumbnail_info.size = thumbinfo.value("size").toInt(); - info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString(); - } - } -} diff --git a/src/events/messages/Image.cc b/src/events/messages/Image.cc deleted file mode 100644 index 9d7c7a3..0000000 --- a/src/events/messages/Image.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Image.h" - -using namespace matrix::events::messages; - -void -Image::deserialize(const QJsonObject &object) -{ - if (!object.contains("url")) - throw DeserializationException("messages::Image url key is missing"); - - url_ = object.value("url").toString(); - - if (object.value("msgtype") != "m.image") - throw DeserializationException("invalid msgtype for image"); - - if (object.contains("info")) { - auto imginfo = object.value("info").toObject(); - - info_.w = imginfo.value("w").toInt(); - info_.h = imginfo.value("h").toInt(); - info_.size = imginfo.value("size").toInt(); - - info_.mimetype = imginfo.value("mimetype").toString(); - info_.thumbnail_url = imginfo.value("thumbnail_url").toString(); - - if (imginfo.contains("thumbnail_info")) { - auto thumbinfo = imginfo.value("thumbnail_info").toObject(); - - info_.thumbnail_info.h = thumbinfo.value("h").toInt(); - info_.thumbnail_info.w = thumbinfo.value("w").toInt(); - info_.thumbnail_info.size = thumbinfo.value("size").toInt(); - info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString(); - } - } -} diff --git a/src/events/messages/Location.cc b/src/events/messages/Location.cc deleted file mode 100644 index ea2b333..0000000 --- a/src/events/messages/Location.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Location.h" - -using namespace matrix::events::messages; - -void -Location::deserialize(const QJsonObject &object) -{ - if (!object.contains("geo_uri")) - throw DeserializationException("messages::Location geo_uri key is missing"); - - if (object.value("msgtype") != "m.location") - throw DeserializationException("invalid msgtype for location"); - - geo_uri_ = object.value("geo_uri").toString(); - - if (object.contains("info")) { - auto location_info = object.value("info").toObject(); - - info_.thumbnail_url = location_info.value("thumbnail_url").toString(); - - if (location_info.contains("thumbnail_info")) { - auto thumbinfo = location_info.value("thumbnail_info").toObject(); - - info_.thumbnail_info.h = thumbinfo.value("h").toInt(); - info_.thumbnail_info.w = thumbinfo.value("w").toInt(); - info_.thumbnail_info.size = thumbinfo.value("size").toInt(); - info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString(); - } - } -} diff --git a/src/events/messages/Notice.cc b/src/events/messages/Notice.cc deleted file mode 100644 index 5b809c7..0000000 --- a/src/events/messages/Notice.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Notice.h" - -using namespace matrix::events::messages; - -void -Notice::deserialize(const QJsonObject &object) -{ - if (object.value("msgtype") != "m.notice") - throw DeserializationException("invalid msgtype for notice"); -} diff --git a/src/events/messages/Text.cc b/src/events/messages/Text.cc deleted file mode 100644 index 6797ec0..0000000 --- a/src/events/messages/Text.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Text.h" - -using namespace matrix::events::messages; - -void -Text::deserialize(const QJsonObject &object) -{ - if (object.value("msgtype") != "m.text") - throw DeserializationException("invalid msgtype for text"); -} diff --git a/src/events/messages/Video.cc b/src/events/messages/Video.cc deleted file mode 100644 index 89f9030..0000000 --- a/src/events/messages/Video.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Video.h" - -using namespace matrix::events::messages; - -void -Video::deserialize(const QJsonObject &object) -{ - if (!object.contains("url")) - throw DeserializationException("messages::Video url key is missing"); - - url_ = object.value("url").toString(); - - if (object.value("msgtype") != "m.video") - throw DeserializationException("invalid msgtype for video"); - - if (object.contains("info")) { - auto video_info = object.value("info").toObject(); - - info_.w = video_info.value("w").toInt(); - info_.h = video_info.value("h").toInt(); - info_.size = video_info.value("size").toInt(); - info_.duration = video_info.value("duration").toInt(); - - info_.mimetype = video_info.value("mimetype").toString(); - info_.thumbnail_url = video_info.value("thumbnail_url").toString(); - - if (video_info.contains("thumbnail_info")) { - auto thumbinfo = video_info.value("thumbnail_info").toObject(); - - info_.thumbnail_info.h = thumbinfo.value("h").toInt(); - info_.thumbnail_info.w = thumbinfo.value("w").toInt(); - info_.thumbnail_info.size = thumbinfo.value("size").toInt(); - info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString(); - } - } -} diff --git a/src/timeline/TimelineItem.cc b/src/timeline/TimelineItem.cc index 1cbe4b0..39b345b 100644 --- a/src/timeline/TimelineItem.cc +++ b/src/timeline/TimelineItem.cc @@ -21,7 +21,6 @@ #include "Avatar.h" #include "Config.h" -#include "Sync.h" #include "timeline/TimelineItem.h" #include "timeline/widgets/AudioItem.h" @@ -32,9 +31,6 @@ static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)"); static const QString URL_HTML = "\\1"; -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - void TimelineItem::init() { @@ -71,7 +67,7 @@ TimelineItem::init() /* * For messages created locally. */ -TimelineItem::TimelineItem(events::MessageEventType ty, +TimelineItem::TimelineItem(mtx::events::MessageType ty, const QString &userid, QString body, bool withSender, @@ -83,7 +79,7 @@ TimelineItem::TimelineItem(events::MessageEventType ty, auto displayName = TimelineViewManager::displayName(userid); auto timestamp = QDateTime::currentDateTime(); - if (ty == events::MessageEventType::Emote) { + if (ty == mtx::events::MessageType::Emote) { body = QString("* %1 %2").arg(displayName).arg(body); descriptionMsg_ = {"", userid, body, descriptiveTime(timestamp)}; } else { @@ -152,64 +148,65 @@ TimelineItem::TimelineItem(VideoItem *video, } TimelineItem::TimelineItem(ImageItem *image, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout, ImageItem>( + setupWidgetLayout, ImageItem>( image, event, " sent an image", with_sender); } TimelineItem::TimelineItem(FileItem *file, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout, FileItem>( + setupWidgetLayout, FileItem>( file, event, " sent a file", with_sender); } TimelineItem::TimelineItem(AudioItem *audio, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout, AudioItem>( + setupWidgetLayout, AudioItem>( audio, event, " sent an audio clip", with_sender); } TimelineItem::TimelineItem(VideoItem *video, - const events::MessageEvent &event, + const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout, VideoItem>( + setupWidgetLayout, VideoItem>( video, event, " sent a video clip", with_sender); } /* * Used to display remote notice messages. */ -TimelineItem::TimelineItem(const events::MessageEvent &event, +TimelineItem::TimelineItem(const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { init(); - event_id_ = event.eventId(); + event_id_ = QString::fromStdString(event.event_id); + const auto sender = QString::fromStdString(event.sender); - descriptionMsg_ = {TimelineViewManager::displayName(event.sender()), - event.sender(), + descriptionMsg_ = {TimelineViewManager::displayName(sender), + sender, " sent a notification", - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))}; + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))}; - auto body = event.content().body().trimmed().toHtmlEscaped(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); + auto body = QString::fromStdString(event.content.body).trimmed().toHtmlEscaped(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); generateTimestamp(timestamp); @@ -218,14 +215,14 @@ TimelineItem::TimelineItem(const events::MessageEvent &event, body = "" + body + ""; if (with_sender) { - auto displayName = TimelineViewManager::displayName(event.sender()); + auto displayName = TimelineViewManager::displayName(sender); generateBody(displayName, body); setupAvatarLayout(displayName); mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); + AvatarProvider::resolve(sender, this); } else { generateBody(body); setupSimpleLayout(); @@ -237,24 +234,25 @@ TimelineItem::TimelineItem(const events::MessageEvent &event, /* * Used to display remote emote messages. */ -TimelineItem::TimelineItem(const events::MessageEvent &event, +TimelineItem::TimelineItem(const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { init(); - event_id_ = event.eventId(); + event_id_ = QString::fromStdString(event.event_id); + const auto sender = QString::fromStdString(event.sender); - auto body = event.content().body().trimmed(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - auto displayName = TimelineViewManager::displayName(event.sender()); + auto body = QString::fromStdString(event.content.body).trimmed(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); + auto displayName = TimelineViewManager::displayName(sender); auto emoteMsg = QString("* %1 %2").arg(displayName).arg(body); descriptionMsg_ = {"", - event.sender(), + sender, emoteMsg, - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))}; + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))}; generateTimestamp(timestamp); emoteMsg = emoteMsg.toHtmlEscaped(); @@ -266,7 +264,7 @@ TimelineItem::TimelineItem(const events::MessageEvent &event, setupAvatarLayout(displayName); mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); + AvatarProvider::resolve(sender, this); } else { generateBody(emoteMsg); setupSimpleLayout(); @@ -278,24 +276,25 @@ TimelineItem::TimelineItem(const events::MessageEvent &event, /* * Used to display remote text messages. */ -TimelineItem::TimelineItem(const events::MessageEvent &event, +TimelineItem::TimelineItem(const mtx::events::RoomEvent &event, bool with_sender, QWidget *parent) : QWidget(parent) { init(); - event_id_ = event.eventId(); + event_id_ = QString::fromStdString(event.event_id); + const auto sender = QString::fromStdString(event.sender); - auto body = event.content().body().trimmed(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - auto displayName = TimelineViewManager::displayName(event.sender()); + auto body = QString::fromStdString(event.content.body).trimmed(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); + auto displayName = TimelineViewManager::displayName(sender); QSettings settings; - descriptionMsg_ = {event.sender() == settings.value("auth/user_id") ? "You" : displayName, - event.sender(), + descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName, + sender, QString(": %1").arg(body), - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))}; + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))}; generateTimestamp(timestamp); @@ -309,7 +308,7 @@ TimelineItem::TimelineItem(const events::MessageEvent &event, mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); + AvatarProvider::resolve(sender, this); } else { generateBody(body); setupSimpleLayout(); diff --git a/src/timeline/TimelineView.cc b/src/timeline/TimelineView.cc index 6b7928d..8e9f5f7 100644 --- a/src/timeline/TimelineView.cc +++ b/src/timeline/TimelineView.cc @@ -22,7 +22,6 @@ #include "FloatingButton.h" #include "RoomMessages.h" #include "ScrollBar.h" -#include "Sync.h" #include "timeline/TimelineView.h" #include "timeline/widgets/AudioItem.h" @@ -30,23 +29,7 @@ #include "timeline/widgets/ImageItem.h" #include "timeline/widgets/VideoItem.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - -static bool -isRedactedEvent(const QJsonObject &event) -{ - if (event.contains("redacted_because")) - return true; - - if (event.contains("unsigned") && - event.value("unsigned").toObject().contains("redacted_because")) - return true; - - return false; -} - -TimelineView::TimelineView(const Timeline &timeline, +TimelineView::TimelineView(const mtx::responses::Timeline &timeline, QSharedPointer client, const QString &room_id, QWidget *parent) @@ -167,12 +150,12 @@ TimelineView::sliderMoved(int position) } void -TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msgs) +TimelineView::addBackwardsEvents(const QString &room_id, const mtx::responses::Messages &msgs) { if (room_id_ != room_id) return; - if (msgs.chunk().count() == 0) { + if (msgs.chunk.size() == 0) { isTimelineFinished = true; return; } @@ -186,12 +169,11 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg // Parse in reverse order to determine where we should not show sender's // name. - auto ii = msgs.chunk().size(); + auto ii = msgs.chunk.size(); while (ii != 0) { --ii; - TimelineItem *item = - parseMessageEvent(msgs.chunk().at(ii).toObject(), TimelineDirection::Top); + TimelineItem *item = parseMessageEvent(msgs.chunk[ii], TimelineDirection::Top); if (item != nullptr) items.push_back(item); @@ -210,11 +192,11 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg QApplication::processEvents(); - prev_batch_token_ = msgs.end(); + prev_batch_token_ = QString::fromStdString(msgs.end); isPaginationInProgress_ = false; // Exclude the top stretch. - if (!msgs.chunk().isEmpty() && scroll_layout_->count() > 1) + if (msgs.chunk.size() != 0 && scroll_layout_->count() > 1) notifyForLastEvent(); // If this batch is the first being rendered (i.e the first and the last @@ -224,63 +206,59 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg } TimelineItem * -TimelineView::parseMessageEvent(const QJsonObject &event, TimelineDirection direction) +TimelineView::parseMessageEvent(const mtx::events::collections::TimelineEvents &event, + TimelineDirection direction) { - events::EventType ty = events::extractEventType(event); - - if (ty == events::EventType::RoomMessage) { - events::MessageEventType msg_type = events::extractMessageEventType(event); - - using Audio = events::MessageEvent; - using Emote = events::MessageEvent; - using File = events::MessageEvent; - using Image = events::MessageEvent; - using Notice = events::MessageEvent; - using Text = events::MessageEvent; - using Video = events::MessageEvent; - - if (msg_type == events::MessageEventType::Audio) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::Emote) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::File) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::Image) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::Notice) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::Text) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::Video) { - return processMessageEvent(event, direction); - } else if (msg_type == events::MessageEventType::Unknown) { - // TODO Handle redacted messages. - // Silenced for now. - if (!isRedactedEvent(event)) - qWarning() << "Unknown message type" << event; - - return nullptr; - } + namespace msg = mtx::events::msg; + using AudioEvent = mtx::events::RoomEvent; + using EmoteEvent = mtx::events::RoomEvent; + using FileEvent = mtx::events::RoomEvent; + using ImageEvent = mtx::events::RoomEvent; + using NoticeEvent = mtx::events::RoomEvent; + using TextEvent = mtx::events::RoomEvent; + using VideoEvent = mtx::events::RoomEvent; + + if (mpark::holds_alternative>(event)) { + auto audio = mpark::get>(event); + return processMessageEvent(audio, direction); + } else if (mpark::holds_alternative>(event)) { + auto emote = mpark::get>(event); + return processMessageEvent(emote, direction); + } else if (mpark::holds_alternative>(event)) { + auto file = mpark::get>(event); + return processMessageEvent(file, direction); + } else if (mpark::holds_alternative>(event)) { + auto image = mpark::get>(event); + return processMessageEvent(image, direction); + } else if (mpark::holds_alternative>(event)) { + auto notice = mpark::get>(event); + return processMessageEvent(notice, direction); + } else if (mpark::holds_alternative>(event)) { + auto text = mpark::get>(event); + return processMessageEvent(text, direction); + } else if (mpark::holds_alternative>(event)) { + auto video = mpark::get>(event); + return processMessageEvent(video, direction); } return nullptr; } int -TimelineView::addEvents(const Timeline &timeline) +TimelineView::addEvents(const mtx::responses::Timeline &timeline) { int message_count = 0; QSettings settings; QString localUser = settings.value("auth/user_id").toString(); - for (const auto &event : timeline.events()) { - TimelineItem *item = parseMessageEvent(event.toObject(), TimelineDirection::Bottom); + for (const auto &event : timeline.events) { + TimelineItem *item = parseMessageEvent(event, TimelineDirection::Bottom); if (item != nullptr) { addTimelineItem(item, TimelineDirection::Bottom); - if (localUser != event.toObject().value("sender").toString()) + if (localUser != getEventSender(event)) message_count += 1; } } @@ -290,15 +268,15 @@ TimelineView::addEvents(const Timeline &timeline) QApplication::processEvents(); if (isInitialSync) { - prev_batch_token_ = timeline.previousBatch(); + prev_batch_token_ = QString::fromStdString(timeline.prev_batch); isInitialSync = false; } // Exclude the top stretch. - if (!timeline.events().isEmpty() && scroll_layout_->count() > 1) + if (timeline.events.size() != 0 && scroll_layout_->count() > 1) notifyForLastEvent(); - if (isActiveWindow() && isVisible() && timeline.events().size() > 0) + if (isActiveWindow() && isVisible() && timeline.events.size() > 0) readLastEvent(); return message_count; @@ -403,7 +381,7 @@ TimelineView::updatePendingMessage(int txn_id, QString event_id) } void -TimelineView::addUserMessage(matrix::events::MessageEventType ty, const QString &body) +TimelineView::addUserMessage(mtx::events::MessageType ty, const QString &body) { QSettings settings; auto user_id = settings.value("auth/user_id").toString(); @@ -439,9 +417,9 @@ TimelineView::sendNextPendingMessage() PendingMessage &m = pending_msgs_.head(); switch (m.ty) { - case matrix::events::MessageEventType::Audio: - case matrix::events::MessageEventType::Image: - case matrix::events::MessageEventType::File: + case mtx::events::MessageType::Audio: + case mtx::events::MessageType::Image: + case mtx::events::MessageType::File: // FIXME: Improve the API client_->sendRoomMessage(m.ty, m.txn_id, @@ -573,3 +551,81 @@ TimelineView::event(QEvent *event) return QWidget::event(event); } + +QString +TimelineView::getEventSender(const mtx::events::collections::TimelineEvents &event) const +{ + using Aliases = mtx::events::StateEvent; + using Avatar = mtx::events::StateEvent; + using CanonicalAlias = mtx::events::StateEvent; + using Create = mtx::events::StateEvent; + using HistoryVisibility = mtx::events::StateEvent; + using JoinRules = mtx::events::StateEvent; + using Member = mtx::events::StateEvent; + using Name = mtx::events::StateEvent; + using PowerLevels = mtx::events::StateEvent; + using Topic = mtx::events::StateEvent; + + using Audio = mtx::events::RoomEvent; + using Emote = mtx::events::RoomEvent; + using File = mtx::events::RoomEvent; + using Image = mtx::events::RoomEvent; + using Notice = mtx::events::RoomEvent; + using Text = mtx::events::RoomEvent; + using Video = mtx::events::RoomEvent; + + if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative(event)) { + auto msg = mpark::get(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative