diff options
77 files changed, 649 insertions, 4963 deletions
diff --git a/.ci/linux/gtest.sh b/.ci/linux/gtest.sh deleted file mode 100755 index 8dd7084c..00000000 --- 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 dc9e303c..00000000 --- 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 c0f0ed16..ba45a88b 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 0d518fe6..69efeedd 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} "</qresource> </RCC>") 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 1a23d6b2..fbbbed9b 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 01f6c5d7..94c54f0b 100644 --- a/include/ChatPage.h +++ b/include/ChatPage.h @@ -24,9 +24,7 @@ #include <QTimer> #include <QWidget> -#include "MemberEventContent.h" -#include "MessageEvent.h" -#include "StateEvent.h" +#include <mtx.hpp> 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<UserID, RoomState>; - using JoinedRooms = QMap<UserID, JoinedRoom>; - using LeftRooms = QMap<UserID, LeftRoom>; - using Membership = matrix::events::StateEvent<matrix::events::MemberEventContent>; - using Memberships = QMap<UserID, Membership>; + using Membership = mtx::events::StateEvent<mtx::events::state::Member>; + using Memberships = std::map<std::string, Membership>; + + using JoinedRooms = std::map<std::string, mtx::responses::JoinedRoom>; + using LeftRooms = std::map<std::string, mtx::responses::LeftRoom>; 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<QString> &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<std::string> &user_ids); + + using MemberEvent = mtx::events::StateEvent<mtx::events::state::Member>; + void updateUserDisplayName(const MemberEvent &event); + void updateUserAvatarUrl(const MemberEvent &event); + void loadStateFromCache(); void deleteConfigs(); void resetUI(); + template<class Collection> + Memberships getMemberships(const std::vector<Collection> &events) const; + + template<class Collection> + void updateUserMetadata(const std::vector<Collection> &collection); + QHBoxLayout *topLayout_; Splitter *splitter; @@ -153,3 +156,37 @@ private: // return to the login page. int initialSyncFailures = 0; }; + +template<class Collection> +void +ChatPage::updateUserMetadata(const std::vector<Collection> &collection) +{ + using Member = mtx::events::StateEvent<mtx::events::state::Member>; + + for (auto &event : collection) { + if (mpark::holds_alternative<Member>(event)) { + auto member = mpark::get<Member>(event); + + updateUserAvatarUrl(member); + updateUserDisplayName(member); + } + } +} + +template<class Collection> +std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>> +ChatPage::getMemberships(const std::vector<Collection> &collection) const +{ + std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>> memberships; + + using Member = mtx::events::StateEvent<mtx::events::state::Member>; + + for (auto &event : collection) { + if (mpark::holds_alternative<Member>(event)) { + auto member = mpark::get<Member>(event); + memberships.emplace(member.state_key, member); + } + } + + return memberships; +} diff --git a/include/MatrixClient.h b/include/MatrixClient.h index 722a8611..397ba11d 100644 --- a/include/MatrixClient.h +++ b/include/MatrixClient.h @@ -20,12 +20,7 @@ #include <QFileInfo> #include <QNetworkAccessManager> #include <QUrl> - -#include "MessageEvent.h" - -class SyncResponse; -class Profile; -class RoomMessages; +#include <mtx.hpp> /* * 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 db1cdc68..0e91410c 100644 --- a/include/RoomState.h +++ b/include/RoomState.h @@ -21,28 +21,14 @@ #include <QPixmap> #include <QUrl> -#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 <mtx.hpp> 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<class Collection> + void updateFromEvents(const std::vector<Collection> &collection); + + std::string serialize() const; // The latest state events. - events::StateEvent<events::AliasesEventContent> aliases; - events::StateEvent<events::AvatarEventContent> avatar; - events::StateEvent<events::CanonicalAliasEventContent> canonical_alias; - events::StateEvent<events::CreateEventContent> create; - events::StateEvent<events::HistoryVisibilityEventContent> history_visibility; - events::StateEvent<events::JoinRulesEventContent> join_rules; - events::StateEvent<events::NameEventContent> name; - events::StateEvent<events::PowerLevelsEventContent> power_levels; - events::StateEvent<events::TopicEventContent> topic; + mtx::events::StateEvent<mtx::events::state::Aliases> aliases; + mtx::events::StateEvent<mtx::events::state::Avatar> avatar; + mtx::events::StateEvent<mtx::events::state::CanonicalAlias> canonical_alias; + mtx::events::StateEvent<mtx::events::state::Create> create; + mtx::events::StateEvent<mtx::events::state::HistoryVisibility> history_visibility; + mtx::events::StateEvent<mtx::events::state::JoinRules> join_rules; + mtx::events::StateEvent<mtx::events::state::Name> name; + mtx::events::StateEvent<mtx::events::state::PowerLevels> power_levels; + mtx::events::StateEvent<mtx::events::state::Topic> topic; // Contains the m.room.member events for all the joined users. - using UserID = QString; - QMap<UserID, events::StateEvent<events::MemberEventContent>> memberships; + using UserID = std::string; + std::map<UserID, mtx::events::StateEvent<mtx::events::state::Member>> memberships; private: QUrl avatar_; @@ -85,3 +76,44 @@ private: // avatar event this should be empty. QString userAvatar_; }; + +template<class Collection> +void +RoomState::updateFromEvents(const std::vector<Collection> &collection) +{ + using Aliases = mtx::events::StateEvent<mtx::events::state::Aliases>; + using Avatar = mtx::events::StateEvent<mtx::events::state::Avatar>; + using CanonicalAlias = mtx::events::StateEvent<mtx::events::state::CanonicalAlias>; + using Create = mtx::events::StateEvent<mtx::events::state::Create>; + using HistoryVisibility = mtx::events::StateEvent<mtx::events::state::HistoryVisibility>; + using JoinRules = mtx::events::StateEvent<mtx::events::state::JoinRules>; + using Member = mtx::events::StateEvent<mtx::events::state::Member>; + using Name = mtx::events::StateEvent<mtx::events::state::Name>; + using PowerLevels = mtx::events::StateEvent<mtx::events::state::PowerLevels>; + using Topic = mtx::events::StateEvent<mtx::events::state::Topic>; + + for (const auto &event : collection) { + if (mpark::holds_alternative<Aliases>(event)) { + this->aliases = mpark::get<Aliases>(event); + } else if (mpark::holds_alternative<Avatar>(event)) { + this->avatar = mpark::get<Avatar>(event); + } else if (mpark::holds_alternative<CanonicalAlias>(event)) { + this->canonical_alias = mpark::get<CanonicalAlias>(event); + } else if (mpark::holds_alternative<Create>(event)) { + this->create = mpark::get<Create>(event); + } else if (mpark::holds_alternative<HistoryVisibility>(event)) { + this->history_visibility = mpark::get<HistoryVisibility>(event); + } else if (mpark::holds_alternative<JoinRules>(event)) { + this->join_rules = mpark::get<JoinRules>(event); + } else if (mpark::holds_alternative<Name>(event)) { + this->name = mpark::get<Name>(event); + } else if (mpark::holds_alternative<Member>(event)) { + auto membership = mpark::get<Member>(event); + this->memberships.emplace(membership.state_key, membership); + } else if (mpark::holds_alternative<PowerLevels>(event)) { + this->power_levels = mpark::get<PowerLevels>(event); + } else if (mpark::holds_alternative<Topic>(event)) { + this->topic = mpark::get<Topic>(event); + } + } +} diff --git a/include/Sync.h b/include/Sync.h deleted file mode 100644 index d59a57dc..00000000 --- a/include/Sync.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonArray> -#include <QMap> - -#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<QString> typingUserIDs() const { return typingUserIDs_; }; - - void deserialize(const QJsonValue &data) override; - -private: - State state_; - Timeline timeline_; - QList<QString> 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<QString, JoinedRoom> join() const { return join_; }; - QMap<QString, LeftRoom> leave() const { return leave_; }; - void deserialize(const QJsonValue &data) override; - -private: - QMap<QString, JoinedRoom> join_; - QMap<QString, LeftRoom> 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 b208d3f4..df309e27 100644 --- a/include/TextInputWidget.h +++ b/include/TextInputWidget.h @@ -25,13 +25,10 @@ #include <QWidget> #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 7784fad7..00000000 --- a/include/events/AliasesEventContent.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> -#include <QList> - -#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<QString> aliases() const { return aliases_; }; - -private: - QList<QString> aliases_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/AvatarEventContent.h b/include/events/AvatarEventContent.h deleted file mode 100644 index 55284aa4..00000000 --- a/include/events/AvatarEventContent.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> -#include <QUrl> - -#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 6322c001..00000000 --- a/include/events/CanonicalAliasEventContent.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 0a47860e..00000000 --- a/include/events/CreateEventContent.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 f6620a2c..00000000 --- a/include/events/Event.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QDebug> -#include <QJsonValue> - -#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 Content> -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<class Content> -inline Content -Event<Content>::content() const -{ - return content_; -} - -template<class Content> -inline EventType -Event<Content>::eventType() const -{ - return type_; -} - -template<class Content> -void -Event<Content>::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<class Content> -QJsonObject -Event<Content>::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 1c39ae03..00000000 --- a/include/events/HistoryVisibilityEventContent.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 4ed9e65f..00000000 --- a/include/events/JoinRulesEventContent.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 8b7b1576..00000000 --- a/include/events/MemberEventContent.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> -#include <QUrl> - -#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 08cd926f..00000000 --- a/include/events/MessageEvent.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include "MessageEventContent.h" -#include "RoomEvent.h" - -namespace matrix { -namespace events { -template<class MsgContent> -class MessageEvent : public RoomEvent<MessageEventContent> -{ -public: - MsgContent msgContent() const; - - void deserialize(const QJsonValue &data) override; - -private: - MsgContent msg_content_; -}; - -template<class MsgContent> -inline MsgContent -MessageEvent<MsgContent>::msgContent() const -{ - return msg_content_; -} - -template<class MsgContent> -void -MessageEvent<MsgContent>::deserialize(const QJsonValue &data) -{ - RoomEvent<MessageEventContent>::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 aa08c066..00000000 --- a/include/events/MessageEventContent.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 378f689d..00000000 --- a/include/events/NameEventContent.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 63998871..00000000 --- a/include/events/PowerLevelsEventContent.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> -#include <QMap> - -#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<int>(PowerLevels::Moderator); - int invite_ = static_cast<int>(PowerLevels::Moderator); - int kick_ = static_cast<int>(PowerLevels::Moderator); - int redact_ = static_cast<int>(PowerLevels::Moderator); - - int events_default_ = static_cast<int>(PowerLevels::User); - int state_default_ = static_cast<int>(PowerLevels::Moderator); - int users_default_ = static_cast<int>(PowerLevels::User); - - QMap<QString, int> events_; - QMap<QString, int> users_; -}; - -} // namespace events -} // namespace matrix diff --git a/include/events/RoomEvent.h b/include/events/RoomEvent.h deleted file mode 100644 index d80951c7..00000000 --- a/include/events/RoomEvent.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> -#include <QString> - -#include "Event.h" - -namespace matrix { -namespace events { -template<class Content> -class RoomEvent : public Event<Content> -{ -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<class Content> -inline QString -RoomEvent<Content>::eventId() const -{ - return event_id_; -} - -template<class Content> -inline QString -RoomEvent<Content>::roomId() const -{ - return room_id_; -} - -template<class Content> -inline QString -RoomEvent<Content>::sender() const -{ - return sender_; -} - -template<class Content> -inline uint64_t -RoomEvent<Content>::timestamp() const -{ - return origin_server_ts_; -} - -template<class Content> -void -RoomEvent<Content>::deserialize(const QJsonValue &data) -{ - Event<Content>::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<class Content> -QJsonObject -RoomEvent<Content>::serialize() const -{ - QJsonObject object = Event<Content>::serialize(); - - object["event_id"] = event_id_; - object["room_id"] = room_id_; - object["sender"] = sender_; - object["origin_server_ts"] = QJsonValue(static_cast<qint64>(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 19342a48..00000000 --- a/include/events/StateEvent.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#include "RoomEvent.h" - -namespace matrix { -namespace events { -template<class Content> -class StateEvent : public RoomEvent<Content> -{ -public: - QString stateKey() const; - Content previousContent() const; - - void deserialize(const QJsonValue &data); - QJsonObject serialize() const; - -private: - QString state_key_; - Content prev_content_; -}; - -template<class Content> -inline QString -StateEvent<Content>::stateKey() const -{ - return state_key_; -} - -template<class Content> -inline Content -StateEvent<Content>::previousContent() const -{ - return prev_content_; -} - -template<class Content> -void -StateEvent<Content>::deserialize(const QJsonValue &data) -{ - RoomEvent<Content>::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<class Content> -QJsonObject -StateEvent<Content>::serialize() const -{ - QJsonObject object = RoomEvent<Content>::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 67e21208..00000000 --- a/include/events/TopicEventContent.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonValue> - -#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 b5666d90..00000000 --- a/include/events/messages/Audio.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 a11b7c8d..00000000 --- a/include/events/messages/Emote.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 9064a556..00000000 --- a/include/events/messages/File.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 03c7a368..00000000 --- a/include/events/messages/Image.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 27722b37..00000000 --- a/include/events/messages/Location.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 66f4386d..00000000 --- a/include/events/messages/Notice.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 c3182dc5..00000000 --- a/include/events/messages/Text.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 6aeaf4d5..00000000 --- a/include/events/messages/Video.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QJsonObject> - -#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 e04cbeae..17b110fc 100644 --- a/include/timeline/TimelineItem.h +++ b/include/timeline/TimelineItem.h @@ -25,16 +25,7 @@ #include <QStyle> #include <QStyleOption> -#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<msgs::Notice> &e, + TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice> &e, bool with_sender, QWidget *parent = 0); - TimelineItem(const events::MessageEvent<msgs::Text> &e, + TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text> &e, bool with_sender, QWidget *parent = 0); - TimelineItem(const events::MessageEvent<msgs::Emote> &e, + TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote> &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<msgs::Image> &e, + const mtx::events::RoomEvent<mtx::events::msg::Image> &e, bool with_sender, QWidget *parent); TimelineItem(FileItem *file, - const events::MessageEvent<msgs::File> &e, + const mtx::events::RoomEvent<mtx::events::msg::File> &e, bool with_sender, QWidget *parent); TimelineItem(AudioItem *audio, - const events::MessageEvent<msgs::Audio> &e, + const mtx::events::RoomEvent<mtx::events::msg::Audio> &e, bool with_sender, QWidget *parent); TimelineItem(VideoItem *video, - const events::MessageEvent<msgs::Video> &e, + const mtx::events::RoomEvent<mtx::events::msg::Video> &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 5262d20d..52bf0165 100644 --- a/include/timeline/TimelineView.h +++ b/include/timeline/TimelineView.h @@ -27,39 +27,27 @@ #include <QStyle> #include <QStyleOption> -#include "Audio.h" -#include "Emote.h" -#include "File.h" -#include "Image.h" -#include "Notice.h" -#include "Text.h" -#include "Video.h" +#include <mtx.hpp> #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<MatrixClient> 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<class Widget, events::MessageEventType MsgType> + template<class Widget, mtx::events::MessageType MsgType> 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<class Event, class Widget> - TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); + TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction); // TODO: Remove this eventually. template<class Event> - TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); + TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction); // For events with custom display widgets. template<class Event, class Widget> @@ -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<MatrixClient> client_; }; -template<class Widget, events::MessageEventType MsgType> +template<class Widget, mtx::events::MessageType MsgType> void TimelineView::addUserMessage(const QString &url, const QString &filename) { @@ -252,62 +242,50 @@ TimelineView::createTimelineItem(const Event &event, bool withSender) template<class Event> 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>(event, with_sender); } template<class Event, class Widget> 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, Widget>(event, with_sender); } diff --git a/include/timeline/TimelineViewManager.h b/include/timeline/TimelineViewManager.h index edb44ecd..2c32da16 100644 --- a/include/timeline/TimelineViewManager.h +++ b/include/timeline/TimelineViewManager.h @@ -21,12 +21,10 @@ #include <QSharedPointer> #include <QStackedWidget> -#include "MessageEvent.h" +#include <mtx.hpp> -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<QString> &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 1104996f..f8e7cc07 100644 --- a/include/timeline/widgets/AudioItem.h +++ b/include/timeline/widgets/AudioItem.h @@ -24,12 +24,9 @@ #include <QSharedPointer> #include <QWidget> -#include "Audio.h" #include "MatrixClient.h" -#include "MessageEvent.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include <mtx.hpp> class AudioItem : public QWidget { @@ -46,7 +43,7 @@ class AudioItem : public QWidget public: AudioItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::Audio> &event, + const mtx::events::RoomEvent<mtx::events::msg::Audio> &event, QWidget *parent = nullptr); AudioItem(QSharedPointer<MatrixClient> client, @@ -94,7 +91,7 @@ private: QString readableFileSize_; QString filenameToSave_; - events::MessageEvent<msgs::Audio> event_; + mtx::events::RoomEvent<mtx::events::msg::Audio> event_; QSharedPointer<MatrixClient> client_; QMediaPlayer *player_; diff --git a/include/timeline/widgets/FileItem.h b/include/timeline/widgets/FileItem.h index 47e81867..fd0b0249 100644 --- a/include/timeline/widgets/FileItem.h +++ b/include/timeline/widgets/FileItem.h @@ -23,12 +23,9 @@ #include <QSharedPointer> #include <QWidget> -#include "File.h" -#include "MatrixClient.h" -#include "MessageEvent.h" +#include <mtx.hpp> -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<MatrixClient> client, - const events::MessageEvent<msgs::File> &event, + const mtx::events::RoomEvent<mtx::events::msg::File> &event, QWidget *parent = nullptr); FileItem(QSharedPointer<MatrixClient> client, @@ -75,7 +72,7 @@ private: QString readableFileSize_; QString filenameToSave_; - events::MessageEvent<msgs::File> event_; + mtx::events::RoomEvent<mtx::events::msg::File> event_; QSharedPointer<MatrixClient> client_; QIcon icon_; diff --git a/include/timeline/widgets/ImageItem.h b/include/timeline/widgets/ImageItem.h index c4f6998a..931c17dd 100644 --- a/include/timeline/widgets/ImageItem.h +++ b/include/timeline/widgets/ImageItem.h @@ -22,19 +22,16 @@ #include <QSharedPointer> #include <QWidget> -#include "Image.h" -#include "MatrixClient.h" -#include "MessageEvent.h" +#include <mtx.hpp> -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include "MatrixClient.h" class ImageItem : public QWidget { Q_OBJECT public: ImageItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::Image> &event, + const mtx::events::RoomEvent<mtx::events::msg::Image> &event, QWidget *parent = nullptr); ImageItem(QSharedPointer<MatrixClient> client, @@ -72,7 +69,7 @@ private: int bottom_height_ = 30; - events::MessageEvent<msgs::Image> event_; + mtx::events::RoomEvent<mtx::events::msg::Image> event_; QSharedPointer<MatrixClient> client_; }; diff --git a/include/timeline/widgets/VideoItem.h b/include/timeline/widgets/VideoItem.h index aa2a5da3..88ff21ec 100644 --- a/include/timeline/widgets/VideoItem.h +++ b/include/timeline/widgets/VideoItem.h @@ -23,11 +23,8 @@ #include <QWidget> #include "MatrixClient.h" -#include "MessageEvent.h" -#include "Video.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; +#include <mtx.hpp> class VideoItem : public QWidget { @@ -35,7 +32,7 @@ class VideoItem : public QWidget public: VideoItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::Video> &event, + const mtx::events::RoomEvent<mtx::events::msg::Video> &event, QWidget *parent = nullptr); VideoItem(QSharedPointer<MatrixClient> client, @@ -53,6 +50,6 @@ private: QLabel *label_; - events::MessageEvent<msgs::Video> event_; + mtx::events::RoomEvent<mtx::events::msg::Video> event_; QSharedPointer<MatrixClient> client_; }; diff --git a/libs/matrix-structs b/libs/matrix-structs -Subproject 190f297478153930780a119268b908076599c8d +Subproject ea10ea843bccebf54b7b4ebdf1be92a3624597b diff --git a/src/Cache.cc b/src/Cache.cc index dc2c8a9f..087dd4bc 100644 --- a/src/Cache.cc +++ b/src/Cache.cc @@ -22,11 +22,8 @@ #include <QStandardPaths> #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<QString, RoomState> &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<QString, events::StateEvent<events::MemberEventContent>> members; + std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>> 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<events::MemberEventContent> 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<mtx::events::state::Member> 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 bbed7359..ab5aa263 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<MatrixClient> client, QWidget *parent) : QWidget(parent) , client_(client) @@ -219,15 +216,13 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> 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<MatrixClient> 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<RoomSettings>(new RoomSettings(it.key()))); + const auto room_id = QString::fromStdString(it->first); + + state_manager_.insert(room_id, room_state); + settingsManager_.insert(room_id, + QSharedPointer<RoomSettings>(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<QString, QString> 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<QString> &user_ids) +ChatPage::updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids) { QStringList users; @@ -631,9 +622,12 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &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<QString> &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<events::MemberEventContent> 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<events::MemberEventContent> &membership) +ChatPage::updateUserAvatarUrl(const mtx::events::StateEvent<mtx::events::state::Member> &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<events::MemberEventContent> &membership) +ChatPage::updateUserDisplayName( + const mtx::events::StateEvent<mtx::events::state::Member> &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<QString, LeftRoom> &rooms) +ChatPage::removeLeftRooms(const std::map<std::string, mtx::responses::LeftRoom> &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<QString, JoinedRoom> &rooms) +ChatPage::updateJoinedRooms(const std::map<std::string, mtx::responses::JoinedRoom> &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<RoomSettings>(new RoomSettings(it.key()))); + roomid, QSharedPointer<RoomSettings>(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<QString, RoomState> -ChatPage::generateMembershipDifference(const QMap<QString, JoinedRoom> &rooms, - const QMap<QString, RoomState> &states) const +ChatPage::generateMembershipDifference( + const std::map<std::string, mtx::responses::JoinedRoom> &rooms, + const QMap<QString, RoomState> &states) const { QMap<QString, RoomState> 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<QString, matrix::events::StateEvent<events::MemberEventContent>>; - -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<events::MemberEventContent> 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 e4dcb554..3a987d27 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 23c0c5a7..a892e406 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<MatrixClient> client, QWidget *parent) : QWidget(parent) diff --git a/src/RoomState.cc b/src/RoomState.cc index 2b8bcdba..2bfea173 100644 --- a/src/RoomState.cc +++ b/src/RoomState.cc @@ -15,15 +15,19 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <QDebug> #include <QJsonArray> +#include <QJsonObject> #include <QSettings> #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<events::AliasesEventContent> event; - + if (object.count("aliases") != 0) { try { - event.deserialize(object["aliases"]); - aliases = event; - } catch (const DeserializationException &e) { + aliases = object.at("aliases") + .get<mtx::events::StateEvent<mtx::events::state::Aliases>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - aliases" << e.what(); } } - if (object.contains("avatar")) { - events::StateEvent<events::AvatarEventContent> event; - + if (object.count("avatar") != 0) { try { - event.deserialize(object["avatar"]); - avatar = event; - } catch (const DeserializationException &e) { + avatar = object.at("avatar") + .get<mtx::events::StateEvent<mtx::events::state::Avatar>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - avatar" << e.what(); } } - if (object.contains("canonical_alias")) { - events::StateEvent<events::CanonicalAliasEventContent> 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<mtx::events::StateEvent<mtx::events::state::CanonicalAlias>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - canonical_alias" << e.what(); } } - if (object.contains("create")) { - events::StateEvent<events::CreateEventContent> event; - + if (object.count("create") != 0) { try { - event.deserialize(object["create"]); - create = event; - } catch (const DeserializationException &e) { + create = object.at("create") + .get<mtx::events::StateEvent<mtx::events::state::Create>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - create" << e.what(); } } - if (object.contains("history_visibility")) { - events::StateEvent<events::HistoryVisibilityEventContent> 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<mtx::events::StateEvent<mtx::events::state::HistoryVisibility>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - history_visibility" << e.what(); } } - if (object.contains("join_rules")) { - events::StateEvent<events::JoinRulesEventContent> 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<mtx::events::StateEvent<mtx::events::state::JoinRules>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - join_rules" << e.what(); } } - if (object.contains("name")) { - events::StateEvent<events::NameEventContent> event; - + if (object.count("name") != 0) { try { - event.deserialize(object["name"]); - name = event; - } catch (const DeserializationException &e) { + name = object.at("name") + .get<mtx::events::StateEvent<mtx::events::state::Name>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - name" << e.what(); } } - if (object.contains("power_levels")) { - events::StateEvent<events::PowerLevelsEventContent> 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<mtx::events::StateEvent<mtx::events::state::PowerLevels>>(); + } catch (std::exception &e) { qWarning() << "RoomState::parse - power_levels" << e.what(); } } - if (object.contains("topic")) { - events::StateEvent<events::TopicEventContent> event; - + if (object.count("topic") != 0) { try { - event.deserialize(object["topic"]); - topic = event; - } catch (const DeserializationException &e) { + topic = object.at("topic") + .get<mtx::events::StateEvent<mtx::events::state::Topic>>(); + } 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<events::AliasesEventContent> aliases; - aliases.deserialize(event); - this->aliases = aliases; - break; - } - case events::EventType::RoomAvatar: { - events::StateEvent<events::AvatarEventContent> avatar; - avatar.deserialize(event); - this->avatar = avatar; - break; - } - case events::EventType::RoomCanonicalAlias: { - events::StateEvent<events::CanonicalAliasEventContent> - canonical_alias; - canonical_alias.deserialize(event); - this->canonical_alias = canonical_alias; - break; - } - case events::EventType::RoomCreate: { - events::StateEvent<events::CreateEventContent> create; - create.deserialize(event); - this->create = create; - break; - } - case events::EventType::RoomHistoryVisibility: { - events::StateEvent<events::HistoryVisibilityEventContent> - history_visibility; - history_visibility.deserialize(event); - this->history_visibility = history_visibility; - break; - } - case events::EventType::RoomJoinRules: { - events::StateEvent<events::JoinRulesEventContent> join_rules; - join_rules.deserialize(event); - this->join_rules = join_rules; - break; - } - case events::EventType::RoomName: { - events::StateEvent<events::NameEventContent> name; - name.deserialize(event); - this->name = name; - break; - } - case events::EventType::RoomMember: { - events::StateEvent<events::MemberEventContent> member; - member.deserialize(event); - - this->memberships.insert(member.stateKey(), member); - - break; - } - case events::EventType::RoomPowerLevels: { - events::StateEvent<events::PowerLevelsEventContent> power_levels; - power_levels.deserialize(event); - this->power_levels = power_levels; - break; - } - case events::EventType::RoomTopic: { - events::StateEvent<events::TopicEventContent> 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 416fa0c6..00000000 --- a/src/Sync.cc +++ /dev/null @@ -1,307 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <QDebug> - -#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 87acbade..00000000 --- a/src/events/AliasesEventContent.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <QJsonArray> - -#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 fc58ad5c..00000000 --- a/src/events/AvatarEventContent.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <QDebug> - -#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 189a0cb0..00000000 --- a/src/events/CanonicalAliasEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 f28099c4..00000000 --- a/src/events/CreateEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 7e5bd1db..00000000 --- a/src/events/Event.cc +++ /dev/null @@ -1,106 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 7c0a149c..00000000 --- a/src/events/HistoryVisibilityEventContent.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 4f5cf6ee..00000000 --- a/src/events/JoinRulesEventContent.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 f80130e6..00000000 --- a/src/events/MemberEventContent.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <QDebug> - -#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 fcf25da1..00000000 --- a/src/events/MessageEventContent.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <QDebug> - -#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 45759cf2..00000000 --- a/src/events/NameEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 c796f81f..00000000 --- a/src/events/PowerLevelsEventContent.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <QJsonObject> - -#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 89602ded..00000000 --- a/src/events/TopicEventContent.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 6b8f8c7e..00000000 --- a/src/events/messages/Audio.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 2c9ab823..00000000 --- a/src/events/messages/Emote.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 28bce441..00000000 --- a/src/events/messages/File.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 9d7c7a3b..00000000 --- a/src/events/messages/Image.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 ea2b333a..00000000 --- a/src/events/messages/Location.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 5b809c77..00000000 --- a/src/events/messages/Notice.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 6797ec01..00000000 --- a/src/events/messages/Text.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 89f90304..00000000 --- a/src/events/messages/Video.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -#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 1cbe4b0a..39b345b5 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 = "<a href=\"\\1\">\\1</a>"; -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<msgs::Image> &event, + const mtx::events::RoomEvent<mtx::events::msg::Image> &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout<events::MessageEvent<msgs::Image>, ImageItem>( + setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Image>, ImageItem>( image, event, " sent an image", with_sender); } TimelineItem::TimelineItem(FileItem *file, - const events::MessageEvent<msgs::File> &event, + const mtx::events::RoomEvent<mtx::events::msg::File> &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout<events::MessageEvent<msgs::File>, FileItem>( + setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::File>, FileItem>( file, event, " sent a file", with_sender); } TimelineItem::TimelineItem(AudioItem *audio, - const events::MessageEvent<msgs::Audio> &event, + const mtx::events::RoomEvent<mtx::events::msg::Audio> &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout<events::MessageEvent<msgs::Audio>, AudioItem>( + setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Audio>, AudioItem>( audio, event, " sent an audio clip", with_sender); } TimelineItem::TimelineItem(VideoItem *video, - const events::MessageEvent<msgs::Video> &event, + const mtx::events::RoomEvent<mtx::events::msg::Video> &event, bool with_sender, QWidget *parent) : QWidget(parent) { - setupWidgetLayout<events::MessageEvent<msgs::Video>, VideoItem>( + setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Video>, VideoItem>( video, event, " sent a video clip", with_sender); } /* * Used to display remote notice messages. */ -TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, +TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice> &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<msgs::Notice> &event, body = "<i>" + body + "</i>"; 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<msgs::Notice> &event, /* * Used to display remote emote messages. */ -TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event, +TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote> &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<msgs::Emote> &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<msgs::Emote> &event, /* * Used to display remote text messages. */ -TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, +TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text> &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<msgs::Text> &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 6b7928db..8e9f5f7c 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<MatrixClient> 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<msgs::Audio>; - using Emote = events::MessageEvent<msgs::Emote>; - using File = events::MessageEvent<msgs::File>; - using Image = events::MessageEvent<msgs::Image>; - using Notice = events::MessageEvent<msgs::Notice>; - using Text = events::MessageEvent<msgs::Text>; - using Video = events::MessageEvent<msgs::Video>; - - if (msg_type == events::MessageEventType::Audio) { - return processMessageEvent<Audio, AudioItem>(event, direction); - } else if (msg_type == events::MessageEventType::Emote) { - return processMessageEvent<Emote>(event, direction); - } else if (msg_type == events::MessageEventType::File) { - return processMessageEvent<File, FileItem>(event, direction); - } else if (msg_type == events::MessageEventType::Image) { - return processMessageEvent<Image, ImageItem>(event, direction); - } else if (msg_type == events::MessageEventType::Notice) { - return processMessageEvent<Notice>(event, direction); - } else if (msg_type == events::MessageEventType::Text) { - return processMessageEvent<Text>(event, direction); - } else if (msg_type == events::MessageEventType::Video) { - return processMessageEvent<Video, VideoItem>(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<msg::Audio>; + using EmoteEvent = mtx::events::RoomEvent<msg::Emote>; + using FileEvent = mtx::events::RoomEvent<msg::File>; + using ImageEvent = mtx::events::RoomEvent<msg::Image>; + using NoticeEvent = mtx::events::RoomEvent<msg::Notice>; + using TextEvent = mtx::events::RoomEvent<msg::Text>; + using VideoEvent = mtx::events::RoomEvent<msg::Video>; + + if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Audio>>(event)) { + auto audio = mpark::get<mtx::events::RoomEvent<msg::Audio>>(event); + return processMessageEvent<AudioEvent, AudioItem>(audio, direction); + } else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Emote>>(event)) { + auto emote = mpark::get<mtx::events::RoomEvent<msg::Emote>>(event); + return processMessageEvent<EmoteEvent>(emote, direction); + } else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::File>>(event)) { + auto file = mpark::get<mtx::events::RoomEvent<msg::File>>(event); + return processMessageEvent<FileEvent, FileItem>(file, direction); + } else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Image>>(event)) { + auto image = mpark::get<mtx::events::RoomEvent<msg::Image>>(event); + return processMessageEvent<ImageEvent, ImageItem>(image, direction); + } else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Notice>>(event)) { + auto notice = mpark::get<mtx::events::RoomEvent<msg::Notice>>(event); + return processMessageEvent<NoticeEvent>(notice, direction); + } else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Text>>(event)) { + auto text = mpark::get<mtx::events::RoomEvent<msg::Text>>(event); + return processMessageEvent<TextEvent>(text, direction); + } else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Video>>(event)) { + auto video = mpark::get<mtx::events::RoomEvent<msg::Video>>(event); + return processMessageEvent<VideoEvent, VideoItem>(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<mtx::events::state::Aliases>; + using Avatar = mtx::events::StateEvent<mtx::events::state::Avatar>; + using CanonicalAlias = mtx::events::StateEvent<mtx::events::state::CanonicalAlias>; + using Create = mtx::events::StateEvent<mtx::events::state::Create>; + using HistoryVisibility = mtx::events::StateEvent<mtx::events::state::HistoryVisibility>; + using JoinRules = mtx::events::StateEvent<mtx::events::state::JoinRules>; + using Member = mtx::events::StateEvent<mtx::events::state::Member>; + using Name = mtx::events::StateEvent<mtx::events::state::Name>; + using PowerLevels = mtx::events::StateEvent<mtx::events::state::PowerLevels>; + using Topic = mtx::events::StateEvent<mtx::events::state::Topic>; + + using Audio = mtx::events::RoomEvent<mtx::events::msg::Audio>; + using Emote = mtx::events::RoomEvent<mtx::events::msg::Emote>; + using File = mtx::events::RoomEvent<mtx::events::msg::File>; + using Image = mtx::events::RoomEvent<mtx::events::msg::Image>; + using Notice = mtx::events::RoomEvent<mtx::events::msg::Notice>; + using Text = mtx::events::RoomEvent<mtx::events::msg::Text>; + using Video = mtx::events::RoomEvent<mtx::events::msg::Video>; + + if (mpark::holds_alternative<Aliases>(event)) { + auto msg = mpark::get<Aliases>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Avatar>(event)) { + auto msg = mpark::get<Avatar>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<CanonicalAlias>(event)) { + auto msg = mpark::get<CanonicalAlias>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Create>(event)) { + auto msg = mpark::get<Create>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<HistoryVisibility>(event)) { + auto msg = mpark::get<HistoryVisibility>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<JoinRules>(event)) { + auto msg = mpark::get<JoinRules>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Name>(event)) { + auto msg = mpark::get<Name>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Member>(event)) { + auto msg = mpark::get<Member>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<PowerLevels>(event)) { + auto msg = mpark::get<PowerLevels>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Topic>(event)) { + auto msg = mpark::get<Topic>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Audio>(event)) { + auto msg = mpark::get<Audio>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Emote>(event)) { + auto msg = mpark::get<Emote>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<File>(event)) { + auto msg = mpark::get<File>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Image>(event)) { + auto msg = mpark::get<Image>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Notice>(event)) { + auto msg = mpark::get<Notice>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Text>(event)) { + auto msg = mpark::get<Text>(event); + return QString::fromStdString(msg.sender); + } else if (mpark::holds_alternative<Video>(event)) { + auto msg = mpark::get<Video>(event); + return QString::fromStdString(msg.sender); + } + + return QString(""); +} diff --git a/src/timeline/TimelineViewManager.cc b/src/timeline/TimelineViewManager.cc index 281cafcd..de1e1e32 100644 --- a/src/timeline/TimelineViewManager.cc +++ b/src/timeline/TimelineViewManager.cc @@ -23,7 +23,6 @@ #include <QSettings> #include "MatrixClient.h" -#include "Sync.h" #include "timeline/TimelineView.h" #include "timeline/TimelineViewManager.h" @@ -72,7 +71,7 @@ TimelineViewManager::queueTextMessage(const QString &msg) auto room_id = active_room_; auto view = views_[room_id]; - view->addUserMessage(matrix::events::MessageEventType::Text, msg); + view->addUserMessage(mtx::events::MessageType::Text, msg); } void @@ -81,7 +80,7 @@ TimelineViewManager::queueEmoteMessage(const QString &msg) auto room_id = active_room_; auto view = views_[room_id]; - view->addUserMessage(matrix::events::MessageEventType::Emote, msg); + view->addUserMessage(mtx::events::MessageType::Emote, msg); } void @@ -96,7 +95,7 @@ TimelineViewManager::queueImageMessage(const QString &roomid, auto view = views_[roomid]; - view->addUserMessage<ImageItem, matrix::events::MessageEventType::Image>(url, filename); + view->addUserMessage<ImageItem, mtx::events::MessageType::Image>(url, filename); } void @@ -111,7 +110,7 @@ TimelineViewManager::queueFileMessage(const QString &roomid, auto view = views_[roomid]; - view->addUserMessage<FileItem, matrix::events::MessageEventType::File>(url, filename); + view->addUserMessage<FileItem, mtx::events::MessageType::File>(url, filename); } void @@ -126,7 +125,7 @@ TimelineViewManager::queueAudioMessage(const QString &roomid, auto view = views_[roomid]; - view->addUserMessage<AudioItem, matrix::events::MessageEventType::Audio>(url, filename); + view->addUserMessage<AudioItem, mtx::events::MessageType::Audio>(url, filename); } void @@ -139,10 +138,10 @@ TimelineViewManager::clearAll() } void -TimelineViewManager::initialize(const Rooms &rooms) +TimelineViewManager::initialize(const mtx::responses::Rooms &rooms) { - for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); ++it) { - addRoom(it.value(), it.key()); + for (auto it = rooms.join.cbegin(); it != rooms.join.cend(); ++it) { + addRoom(it->second, QString::fromStdString(it->first)); } } @@ -155,10 +154,10 @@ TimelineViewManager::initialize(const QList<QString> &rooms) } void -TimelineViewManager::addRoom(const JoinedRoom &room, const QString &room_id) +TimelineViewManager::addRoom(const mtx::responses::JoinedRoom &room, const QString &room_id) { // Create a history view with the room events. - TimelineView *view = new TimelineView(room.timeline(), client_, room_id); + TimelineView *view = new TimelineView(room.timeline, client_, room_id); views_.insert(room_id, QSharedPointer<TimelineView>(view)); connect(view, @@ -195,10 +194,10 @@ TimelineViewManager::addRoom(const QString &room_id) } void -TimelineViewManager::sync(const Rooms &rooms) +TimelineViewManager::sync(const mtx::responses::Rooms &rooms) { - for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); ++it) { - auto roomid = it.key(); + for (auto it = rooms.join.cbegin(); it != rooms.join.cend(); ++it) { + auto roomid = QString::fromStdString(it->first); if (!views_.contains(roomid)) { qDebug() << "Ignoring event from unknown room" << roomid; @@ -207,7 +206,7 @@ TimelineViewManager::sync(const Rooms &rooms) auto view = views_.value(roomid); - int msgs_added = view->addEvents(it.value().timeline()); + int msgs_added = view->addEvents(it->second.timeline); if (msgs_added > 0) { // TODO: When the app window gets active the current diff --git a/src/timeline/widgets/AudioItem.cc b/src/timeline/widgets/AudioItem.cc index 2a417b3e..5d9dd77b 100644 --- a/src/timeline/widgets/AudioItem.cc +++ b/src/timeline/widgets/AudioItem.cc @@ -26,9 +26,6 @@ #include "timeline/widgets/AudioItem.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - constexpr int MaxWidth = 400; constexpr int Height = 70; constexpr int IconRadius = 22; @@ -77,15 +74,15 @@ AudioItem::init() } AudioItem::AudioItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::Audio> &event, + const mtx::events::RoomEvent<mtx::events::msg::Audio> &event, QWidget *parent) : QWidget(parent) - , url_{event.msgContent().url()} - , text_{event.content().body()} + , url_{QUrl(QString::fromStdString(event.content.url))} + , text_{QString::fromStdString(event.content.body)} , event_{event} , client_{client} { - readableFileSize_ = calculateFileSize(event.msgContent().info().size); + readableFileSize_ = calculateFileSize(event.content.info.size); init(); } @@ -151,14 +148,14 @@ AudioItem::mousePressEvent(QMouseEvent *event) if (filenameToSave_.isEmpty()) return; - client_->downloadFile(event_.eventId(), url_); + client_->downloadFile(QString::fromStdString(event_.event_id), url_); } } void AudioItem::fileDownloaded(const QString &event_id, const QByteArray &data) { - if (event_id != event_.eventId()) + if (event_id != QString::fromStdString(event_.event_id)) return; try { diff --git a/src/timeline/widgets/FileItem.cc b/src/timeline/widgets/FileItem.cc index e4cc02b2..3c38dc31 100644 --- a/src/timeline/widgets/FileItem.cc +++ b/src/timeline/widgets/FileItem.cc @@ -26,9 +26,6 @@ #include "timeline/widgets/FileItem.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - constexpr int MaxWidth = 400; constexpr int Height = 70; constexpr int IconRadius = 22; @@ -64,15 +61,15 @@ FileItem::init() } FileItem::FileItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::File> &event, + const mtx::events::RoomEvent<mtx::events::msg::File> &event, QWidget *parent) : QWidget(parent) - , url_{event.msgContent().url()} - , text_{event.content().body()} + , url_{QString::fromStdString(event.content.url)} + , text_{QString::fromStdString(event.content.body)} , event_{event} , client_{client} { - readableFileSize_ = calculateFileSize(event.msgContent().info().size); + readableFileSize_ = calculateFileSize(event.content.info.size); init(); } @@ -138,7 +135,7 @@ FileItem::mousePressEvent(QMouseEvent *event) if (filenameToSave_.isEmpty()) return; - client_->downloadFile(event_.eventId(), url_); + client_->downloadFile(QString::fromStdString(event_.event_id), url_); } else { openUrl(); } @@ -147,7 +144,7 @@ FileItem::mousePressEvent(QMouseEvent *event) void FileItem::fileDownloaded(const QString &event_id, const QByteArray &data) { - if (event_id != event_.eventId()) + if (event_id != QString::fromStdString(event_.event_id)) return; try { diff --git a/src/timeline/widgets/ImageItem.cc b/src/timeline/widgets/ImageItem.cc index c8cf8e23..46a4518c 100644 --- a/src/timeline/widgets/ImageItem.cc +++ b/src/timeline/widgets/ImageItem.cc @@ -25,11 +25,8 @@ #include "dialogs/ImageOverlay.h" #include "timeline/widgets/ImageItem.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - ImageItem::ImageItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::Image> &event, + const mtx::events::RoomEvent<mtx::events::msg::Image> &event, QWidget *parent) : QWidget(parent) , event_{event} @@ -39,8 +36,8 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client, setCursor(Qt::PointingHandCursor); setAttribute(Qt::WA_Hover, true); - url_ = event.msgContent().url(); - text_ = event.content().body(); + url_ = QString::fromStdString(event.content.url); + text_ = QString::fromStdString(event.content.body); QList<QString> url_parts = url_.toString().split("mxc://"); @@ -53,7 +50,7 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client, url_ = QString("%1/_matrix/media/r0/download/%2") .arg(client_.data()->getHomeServer().toString(), media_params); - client_.data()->downloadImage(event.eventId(), url_); + client_.data()->downloadImage(QString::fromStdString(event.event_id), url_); connect(client_.data(), SIGNAL(imageDownloaded(const QString &, const QPixmap &)), @@ -91,7 +88,7 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client, void ImageItem::imageDownloaded(const QString &event_id, const QPixmap &img) { - if (event_id != event_.eventId()) + if (event_id != QString::fromStdString(event_.event_id)) return; setImage(img); diff --git a/src/timeline/widgets/VideoItem.cc b/src/timeline/widgets/VideoItem.cc index 63cbc20c..1d67118a 100644 --- a/src/timeline/widgets/VideoItem.cc +++ b/src/timeline/widgets/VideoItem.cc @@ -21,9 +21,6 @@ #include "timeline/widgets/VideoItem.h" -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - void VideoItem::init() { @@ -39,15 +36,15 @@ VideoItem::init() } VideoItem::VideoItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::Video> &event, + const mtx::events::RoomEvent<mtx::events::msg::Video> &event, QWidget *parent) : QWidget(parent) - , url_{event.msgContent().url()} - , text_{event.content().body()} + , url_{QString::fromStdString(event.content.url)} + , text_{QString::fromStdString(event.content.body)} , event_{event} , client_{client} { - readableFileSize_ = calculateFileSize(event.msgContent().info().size); + readableFileSize_ = calculateFileSize(event.content.info.size); init(); diff --git a/tests/event_collection.cc b/tests/event_collection.cc deleted file mode 100644 index 0ba7d227..00000000 --- a/tests/event_collection.cc +++ /dev/null @@ -1,111 +0,0 @@ -#include <gtest/gtest.h> - -#include <QJsonArray> -#include <QJsonObject> - -#include "Event.h" -#include "RoomEvent.h" -#include "StateEvent.h" - -#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" - -using namespace matrix::events; - -TEST(EventCollection, Deserialize) -{ - auto events = QJsonArray{ - QJsonObject{ { "content", QJsonObject{ { "name", "Name" } } }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "prev_content", QJsonObject{ { "name", "Previous Name" } } }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "state_key", "" }, - { "type", "m.room.name" } }, - QJsonObject{ { "content", QJsonObject{ { "topic", "Topic" } } }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "prev_content", QJsonObject{ { "topic", "Previous Topic" } } }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "state_key", "" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.topic" } }, - }; - - for (const auto &event : events) { - EventType ty = extractEventType(event.toObject()); - - if (ty == EventType::RoomName) { - StateEvent<NameEventContent> name_event; - name_event.deserialize(event); - - EXPECT_EQ(name_event.content().name(), "Name"); - EXPECT_EQ(name_event.previousContent().name(), "Previous Name"); - } else if (ty == EventType::RoomTopic) { - StateEvent<TopicEventContent> topic_event; - topic_event.deserialize(event); - - EXPECT_EQ(topic_event.content().topic(), "Topic"); - EXPECT_EQ(topic_event.previousContent().topic(), "Previous Topic"); - } else { - ASSERT_EQ(false, true); - } - } -} - -TEST(EventCollection, DeserializationException) -{ - // Using wrong event types. - auto events = QJsonArray{ - QJsonObject{ { "content", QJsonObject{ { "name", "Name" } } }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "prev_content", QJsonObject{ { "name", "Previous Name" } } }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "state_key", "" }, - { "type", "m.room.topic" } }, - QJsonObject{ { "content", QJsonObject{ { "topic", "Topic" } } }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "prev_content", QJsonObject{ { "topic", "Previous Topic" } } }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "state_key", "" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.name" } }, - }; - - for (const auto &event : events) { - EventType ty = extractEventType(event.toObject()); - - if (ty == EventType::RoomName) { - StateEvent<NameEventContent> name_event; - - try { - name_event.deserialize(event); - } catch (const DeserializationException &e) { - ASSERT_STREQ("name key is missing", e.what()); - } - - } else if (ty == EventType::RoomTopic) { - StateEvent<TopicEventContent> topic_event; - - try { - topic_event.deserialize(event); - } catch (const DeserializationException &e) { - ASSERT_STREQ("topic key is missing", e.what()); - } - } else { - ASSERT_EQ(false, true); - } - } -} diff --git a/tests/events.cc b/tests/events.cc deleted file mode 100644 index a4f6fedf..00000000 --- a/tests/events.cc +++ /dev/null @@ -1,707 +0,0 @@ -#include <QDebug> -#include <QJsonArray> -#include <gtest/gtest.h> - -#include "Event.h" -#include "RoomEvent.h" -#include "StateEvent.h" - -#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" - -using namespace matrix::events; - -TEST(BaseEvent, Deserialization) -{ - // NameEventContent - auto data = - QJsonObject{{"content", QJsonObject{{"name", "Room Name"}}}, {"type", "m.room.name"}}; - - Event<NameEventContent> name_event; - name_event.deserialize(data); - EXPECT_EQ(name_event.content().name(), "Room Name"); - EXPECT_EQ(name_event.serialize(), data); - - // TopicEventContent - data = QJsonObject{{"content", QJsonObject{{"topic", "Room Topic"}}}, - {"unsigned", QJsonObject{{"age", 22}, {"transaction_id", "randomid"}}}, - {"type", "m.room.topic"}}; - - Event<TopicEventContent> topic_event; - topic_event.deserialize(data); - EXPECT_EQ(topic_event.content().topic(), "Room Topic"); - EXPECT_EQ(topic_event.unsignedData().age(), 22); - EXPECT_EQ(topic_event.unsignedData().transactionId(), "randomid"); - EXPECT_EQ(topic_event.serialize(), data); - - // AvatarEventContent - data = QJsonObject{ - {"content", QJsonObject{{"url", "https://matrix.org"}}}, - {"unsigned", QJsonObject{{"age", 1343434343}, {"transaction_id", "m33434.33"}}}, - {"type", "m.room.avatar"}}; - - Event<AvatarEventContent> avatar_event; - avatar_event.deserialize(data); - EXPECT_EQ(avatar_event.content().url().toString(), "https://matrix.org"); - EXPECT_EQ(avatar_event.unsignedData().age(), 1343434343); - EXPECT_EQ(avatar_event.unsignedData().transactionId(), "m33434.33"); - EXPECT_EQ(avatar_event.serialize(), data); - - // AliasesEventContent - data = QJsonObject{ - {"content", - QJsonObject{{"aliases", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}}}, - {"unsigned", QJsonObject{{"transaction_id", "m33434.33"}}}, - {"type", "m.room.aliases"}}; - - Event<AliasesEventContent> aliases_event; - aliases_event.deserialize(data); - EXPECT_EQ(aliases_event.content().aliases().size(), 2); - EXPECT_EQ(aliases_event.unsignedData().transactionId(), "m33434.33"); - EXPECT_EQ(aliases_event.serialize(), data); - - // CreateEventContent - data = QJsonObject{{"content", QJsonObject{{"creator", "@alice:matrix.org"}}}, - {"unsigned", QJsonObject{{"age", 2233}}}, - {"type", "m.room.create"}}; - - Event<CreateEventContent> create_event; - create_event.deserialize(data); - EXPECT_EQ(create_event.content().creator(), "@alice:matrix.org"); - EXPECT_EQ(create_event.unsignedData().age(), 2233); - EXPECT_EQ(create_event.serialize(), data); - - // JoinRulesEventContent - data = QJsonObject{{"content", QJsonObject{{"join_rule", "private"}}}, - {"type", "m.room.join_rules"}}; - - Event<JoinRulesEventContent> join_rules_event; - join_rules_event.deserialize(data); - EXPECT_EQ(join_rules_event.content().joinRule(), JoinRule::Private); - EXPECT_EQ(join_rules_event.serialize(), data); -} - -TEST(BaseEvent, DeserializationException) -{ - auto data = - QJsonObject{{"content", QJsonObject{{"rule", "private"}}}, {"type", "m.room.join_rules"}}; - - Event<JoinRulesEventContent> event1; - ASSERT_THROW(event1.deserialize(data), DeserializationException); - - data = QJsonObject{{"contents", QJsonObject{{"join_rule", "private"}}}, - {"type", "m.room.join_rules"}}; - - Event<JoinRulesEventContent> event2; - ASSERT_THROW(event2.deserialize(data), DeserializationException); - - data = QJsonObject{{"contents", QJsonObject{{"join_rule", "private"}}}, - {"unsigned", QJsonObject{{"age", "222"}}}, - {"type", "m.room.join_rules"}}; - - Event<JoinRulesEventContent> event3; - ASSERT_THROW(event3.deserialize(data), DeserializationException); -} - -TEST(RoomEvent, Deserialization) -{ - auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}}, - {"event_id", "$asdfafdf8af:matrix.org"}, - {"room_id", "!aasdfaeae23r9:matrix.org"}, - {"sender", "@alice:matrix.org"}, - {"origin_server_ts", 1323238293289323LL}, - {"type", "m.room.name"}}; - - RoomEvent<NameEventContent> event; - event.deserialize(data); - - EXPECT_EQ(event.eventId(), "$asdfafdf8af:matrix.org"); - EXPECT_EQ(event.roomId(), "!aasdfaeae23r9:matrix.org"); - EXPECT_EQ(event.sender(), "@alice:matrix.org"); - EXPECT_EQ(event.timestamp(), 1323238293289323); - EXPECT_EQ(event.content().name(), "Name"); - EXPECT_EQ(event.serialize(), data); -} - -TEST(RoomEvent, DeserializationException) -{ - auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}}, - {"event_id", "$asdfafdf8af:matrix.org"}, - {"room_id", "!aasdfaeae23r9:matrix.org"}, - {"origin_server_ts", 1323238293289323LL}, - {"type", "m.room.name"}}; - - RoomEvent<NameEventContent> event; - - try { - event.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("sender key is missing", e.what()); - } -} - -TEST(StateEvent, Deserialization) -{ - auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}}, - {"event_id", "$asdfafdf8af:matrix.org"}, - {"state_key", "some_state_key"}, - {"prev_content", QJsonObject{{"name", "Previous Name"}}}, - {"room_id", "!aasdfaeae23r9:matrix.org"}, - {"sender", "@alice:matrix.org"}, - {"origin_server_ts", 1323238293289323LL}, - {"type", "m.room.name"}}; - - StateEvent<NameEventContent> event; - event.deserialize(data); - - EXPECT_EQ(event.eventId(), "$asdfafdf8af:matrix.org"); - EXPECT_EQ(event.roomId(), "!aasdfaeae23r9:matrix.org"); - EXPECT_EQ(event.sender(), "@alice:matrix.org"); - EXPECT_EQ(event.timestamp(), 1323238293289323); - EXPECT_EQ(event.content().name(), "Name"); - EXPECT_EQ(event.stateKey(), "some_state_key"); - EXPECT_EQ(event.previousContent().name(), "Previous Name"); - EXPECT_EQ(event.serialize(), data); -} - -TEST(StateEvent, DeserializationException) -{ - auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}}, - {"event_id", "$asdfafdf8af:matrix.org"}, - {"prev_content", QJsonObject{{"name", "Previous Name"}}}, - {"room_id", "!aasdfaeae23r9:matrix.org"}, - {"sender", "@alice:matrix.org"}, - {"origin_server_ts", 1323238293289323LL}, - {"type", "m.room.name"}}; - - StateEvent<NameEventContent> event; - - try { - event.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("state_key key is missing", e.what()); - } -} - -TEST(EventType, Mapping) -{ - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.aliases"}}), - EventType::RoomAliases); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.avatar"}}), EventType::RoomAvatar); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.canonical_alias"}}), - EventType::RoomCanonicalAlias); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.create"}}), EventType::RoomCreate); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.history_visibility"}}), - EventType::RoomHistoryVisibility); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.join_rules"}}), - EventType::RoomJoinRules); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.member"}}), EventType::RoomMember); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.message"}}), - EventType::RoomMessage); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.name"}}), EventType::RoomName); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.power_levels"}}), - EventType::RoomPowerLevels); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.topic"}}), EventType::RoomTopic); - EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.unknown"}}), - EventType::Unsupported); -} - -TEST(AliasesEventContent, Deserialization) -{ - auto data = QJsonObject{{"aliases", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}}; - - AliasesEventContent content; - content.deserialize(data); - - EXPECT_EQ(content.aliases().size(), 2); - EXPECT_EQ(content.serialize(), data); -} - -TEST(AliasesEventContent, NotAnObject) -{ - auto data = QJsonArray{"#test:matrix.org", "#test2:matrix.org"}; - - AliasesEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(AliasesEventContent, MissingKey) -{ - auto data = QJsonObject{{"key", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}}; - - AliasesEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("aliases key is missing", e.what()); - } -} - -TEST(AvatarEventContent, Deserialization) -{ - auto data = QJsonObject{{"url", "https://matrix.org/avatar.png"}}; - - AvatarEventContent content; - content.deserialize(data); - - EXPECT_EQ(content.url().toString(), "https://matrix.org/avatar.png"); - EXPECT_EQ(content.serialize(), data); -} - -TEST(AvatarEventContent, NotAnObject) -{ - auto data = QJsonArray{"key", "url"}; - - AvatarEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(AvatarEventContent, MissingKey) -{ - auto data = QJsonObject{{"key", "https://matrix.org"}}; - - AvatarEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("url key is missing", e.what()); - } -} - -TEST(CreateEventContent, Deserialization) -{ - auto data = QJsonObject{{"creator", "@alice:matrix.org"}}; - - CreateEventContent content; - content.deserialize(data); - - EXPECT_EQ(content.creator(), "@alice:matrix.org"); - EXPECT_EQ(content.serialize(), data); -} - -TEST(CreateEventContent, NotAnObject) -{ - auto data = QJsonArray{"creator", "alice"}; - - CreateEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(CreateEventContent, MissingKey) -{ - auto data = QJsonObject{{"key", "@alice:matrix.org"}}; - - CreateEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("creator key is missing", e.what()); - } -} - -TEST(HistoryVisibilityEventContent, Deserialization) -{ - auto data = QJsonObject{{"history_visibility", "invited"}}; - - HistoryVisibilityEventContent content; - content.deserialize(data); - EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Invited); - - data = QJsonObject{{"history_visibility", "joined"}}; - - content.deserialize(data); - EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Joined); - - data = QJsonObject{{"history_visibility", "shared"}}; - - content.deserialize(data); - EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Shared); - - data = QJsonObject{{"history_visibility", "world_readable"}}; - - content.deserialize(data); - EXPECT_EQ(content.historyVisibility(), HistoryVisibility::WorldReadable); -} - -TEST(HistoryVisibilityEventContent, NotAnObject) -{ - auto data = QJsonArray{"history_visibility", "alice"}; - - HistoryVisibilityEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(HistoryVisibilityEventContent, InvalidHistoryVisibility) -{ - auto data = QJsonObject{{"history_visibility", "wrong"}}; - - HistoryVisibilityEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("Unknown history_visibility value: wrong", e.what()); - } -} - -TEST(HistoryVisibilityEventContent, MissingKey) -{ - auto data = QJsonObject{{"key", "joined"}}; - - HistoryVisibilityEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("history_visibility key is missing", e.what()); - } -} - -TEST(JoinRulesEventContent, Deserialization) -{ - auto data = QJsonObject{{"join_rule", "invite"}}; - - JoinRulesEventContent content; - content.deserialize(data); - EXPECT_EQ(content.joinRule(), JoinRule::Invite); - - data = QJsonObject{{"join_rule", "knock"}}; - - content.deserialize(data); - EXPECT_EQ(content.joinRule(), JoinRule::Knock); - - data = QJsonObject{{"join_rule", "private"}}; - - content.deserialize(data); - EXPECT_EQ(content.joinRule(), JoinRule::Private); - - data = QJsonObject{{"join_rule", "public"}}; - - content.deserialize(data); - EXPECT_EQ(content.joinRule(), JoinRule::Public); -} - -TEST(JoinRulesEventContent, NotAnObject) -{ - auto data = QJsonArray{"rule", "alice"}; - - JoinRulesEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(JoinRulesEventContent, InvalidHistoryVisibility) -{ - auto data = QJsonObject{{"join_rule", "wrong"}}; - - JoinRulesEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("Unknown join_rule value: wrong", e.what()); - } -} - -TEST(JoinRulesEventContent, MissingKey) -{ - auto data = QJsonObject{{"key", "invite"}}; - - JoinRulesEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("join_rule key is missing", e.what()); - } -} - -TEST(CanonicalAliasEventContent, Deserialization) -{ - auto data = QJsonObject{{"alias", "Room Alias"}}; - - CanonicalAliasEventContent content; - content.deserialize(data); - - EXPECT_EQ(content.alias(), "Room Alias"); - EXPECT_EQ(content.serialize(), data); -} - -TEST(CanonicalAliasEventContent, NotAnObject) -{ - auto data = QJsonArray{"alias", "Room Alias"}; - - CanonicalAliasEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(CanonicalAliasEventContent, MissingKey) -{ - auto data = QJsonObject{{"key", "alias"}}; - - CanonicalAliasEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("alias key is missing", e.what()); - } -} - -TEST(MemberEventContent, Deserialization) -{ - MemberEventContent content; - - auto data = QJsonObject{{"membership", "join"}}; - - content.deserialize(data); - EXPECT_EQ(content.membershipState(), Membership::Join); - - data = QJsonObject{{"membership", "invite"}, {"displayname", "Username"}}; - - content.deserialize(data); - EXPECT_EQ(content.membershipState(), Membership::Invite); - EXPECT_EQ(content.displayName(), "Username"); - - data = QJsonObject{{"membership", "leave"}, {"avatar_url", "https://matrix.org"}}; - - content.deserialize(data); - EXPECT_EQ(content.membershipState(), Membership::Leave); - EXPECT_EQ(content.avatarUrl().toString(), "https://matrix.org"); - - data = QJsonObject{{"membership", "ban"}}; - - content.deserialize(data); - EXPECT_EQ(content.membershipState(), Membership::Ban); - - data = QJsonObject{{"membership", "knock"}}; - - content.deserialize(data); - EXPECT_EQ(content.membershipState(), Membership::Knock); -} - -TEST(MemberEventContent, InvalidMembership) -{ - auto data = QJsonObject{{"membership", "wrong"}}; - - MemberEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("Unknown membership value: wrong", e.what()); - } -} - -TEST(MemberEventContent, NotAnObject) -{ - auto data = QJsonArray{"name", "join"}; - - MemberEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(MemberEventContent, MissingName) -{ - auto data = QJsonObject{{"key", "random"}}; - - MemberEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("membership key is missing", e.what()); - } -} - -TEST(NameEventContent, Deserialization) -{ - auto data = QJsonObject{{"name", "Room Name"}}; - - NameEventContent content; - content.deserialize(data); - - EXPECT_EQ(content.name(), "Room Name"); - EXPECT_EQ(content.serialize(), data); -} - -TEST(NameEventContent, NotAnObject) -{ - auto data = QJsonArray{"name", "Room Name"}; - - NameEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(NameEventContent, MissingName) -{ - auto data = QJsonObject{{"key", "Room Name"}}; - - NameEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("name key is missing", e.what()); - } -} - -TEST(PowerLevelsEventContent, DefaultValues) -{ - PowerLevelsEventContent power_levels; - - EXPECT_EQ(power_levels.banLevel(), static_cast<int>(PowerLevels::Moderator)); - EXPECT_EQ(power_levels.inviteLevel(), static_cast<int>(PowerLevels::Moderator)); - EXPECT_EQ(power_levels.kickLevel(), static_cast<int>(PowerLevels::Moderator)); - EXPECT_EQ(power_levels.redactLevel(), static_cast<int>(PowerLevels::Moderator)); - - EXPECT_EQ(power_levels.eventsDefaultLevel(), static_cast<int>(PowerLevels::User)); - EXPECT_EQ(power_levels.usersDefaultLevel(), static_cast<int>(PowerLevels::User)); - EXPECT_EQ(power_levels.stateDefaultLevel(), static_cast<int>(PowerLevels::Moderator)); - - // Default levels. - EXPECT_EQ(power_levels.userLevel("@joe:matrix.org"), static_cast<int>(PowerLevels::User)); - EXPECT_EQ(power_levels.eventLevel("m.room.message"), static_cast<int>(PowerLevels::User)); -} - -TEST(PowerLevelsEventContent, FullDeserialization) -{ - auto data = QJsonObject{ - {"ban", 1}, - {"invite", 2}, - {"kick", 3}, - {"redact", 4}, - - {"events_default", 5}, - {"state_default", 6}, - {"users_default", 7}, - - {"events", QJsonObject{{"m.message.text", 8}, {"m.message.image", 9}}}, - {"users", QJsonObject{{"@alice:matrix.org", 10}, {"@bob:matrix.org", 11}}}, - }; - - PowerLevelsEventContent power_levels; - power_levels.deserialize(data); - - EXPECT_EQ(power_levels.banLevel(), 1); - EXPECT_EQ(power_levels.inviteLevel(), 2); - EXPECT_EQ(power_levels.kickLevel(), 3); - EXPECT_EQ(power_levels.redactLevel(), 4); - - EXPECT_EQ(power_levels.eventsDefaultLevel(), 5); - EXPECT_EQ(power_levels.stateDefaultLevel(), 6); - EXPECT_EQ(power_levels.usersDefaultLevel(), 7); - - EXPECT_EQ(power_levels.userLevel("@alice:matrix.org"), 10); - EXPECT_EQ(power_levels.userLevel("@bob:matrix.org"), 11); - EXPECT_EQ(power_levels.userLevel("@carl:matrix.org"), 7); - - EXPECT_EQ(power_levels.eventLevel("m.message.text"), 8); - EXPECT_EQ(power_levels.eventLevel("m.message.image"), 9); - EXPECT_EQ(power_levels.eventLevel("m.message.gif"), 5); - - EXPECT_EQ(power_levels.serialize(), data); -} - -TEST(PowerLevelsEventContent, PartialDeserialization) -{ - auto data = QJsonObject{ - {"ban", 1}, - {"invite", 2}, - - {"events_default", 5}, - {"users_default", 7}, - - {"users", QJsonObject{{"@alice:matrix.org", 10}, {"@bob:matrix.org", 11}}}, - }; - - PowerLevelsEventContent power_levels; - power_levels.deserialize(data); - - EXPECT_EQ(power_levels.banLevel(), 1); - EXPECT_EQ(power_levels.inviteLevel(), 2); - EXPECT_EQ(power_levels.kickLevel(), static_cast<int>(PowerLevels::Moderator)); - EXPECT_EQ(power_levels.redactLevel(), static_cast<int>(PowerLevels::Moderator)); - - EXPECT_EQ(power_levels.eventsDefaultLevel(), 5); - EXPECT_EQ(power_levels.stateDefaultLevel(), static_cast<int>(PowerLevels::Moderator)); - EXPECT_EQ(power_levels.usersDefaultLevel(), 7); - - EXPECT_EQ(power_levels.userLevel("@alice:matrix.org"), 10); - EXPECT_EQ(power_levels.userLevel("@bob:matrix.org"), 11); - EXPECT_EQ(power_levels.userLevel("@carl:matrix.org"), 7); - - EXPECT_EQ(power_levels.eventLevel("m.message.text"), 5); - EXPECT_EQ(power_levels.eventLevel("m.message.image"), 5); - EXPECT_EQ(power_levels.eventLevel("m.message.gif"), 5); -} - -TEST(PowerLevelsEventContent, NotAnObject) -{ - auto data = QJsonArray{"test", "test2"}; - - PowerLevelsEventContent power_levels; - - ASSERT_THROW(power_levels.deserialize(data), DeserializationException); -} - -TEST(TopicEventContent, Deserialization) -{ - auto data = QJsonObject{{"topic", "Room Topic"}}; - - TopicEventContent content; - content.deserialize(data); - - EXPECT_EQ(content.topic(), "Room Topic"); - EXPECT_EQ(content.serialize(), data); -} - -TEST(TopicEventContent, NotAnObject) -{ - auto data = QJsonArray{"topic", "Room Topic"}; - - TopicEventContent content; - - ASSERT_THROW(content.deserialize(data), DeserializationException); -} - -TEST(TopicEventContent, MissingName) -{ - auto data = QJsonObject{{"key", "Room Name"}}; - - TopicEventContent content; - ASSERT_THROW(content.deserialize(data), DeserializationException); - - try { - content.deserialize(data); - } catch (const DeserializationException &e) { - ASSERT_STREQ("topic key is missing", e.what()); - } -} diff --git a/tests/message_events.cc b/tests/message_events.cc deleted file mode 100644 index dfff50ab..00000000 --- a/tests/message_events.cc +++ /dev/null @@ -1,287 +0,0 @@ -#include <gtest/gtest.h> - -#include <QJsonArray> -#include <QJsonObject> - -#include "MessageEvent.h" -#include "MessageEventContent.h" - -#include "Audio.h" -#include "Emote.h" -#include "File.h" -#include "Image.h" -#include "Location.h" -#include "Notice.h" -#include "Text.h" -#include "Video.h" - -using namespace matrix::events; - -TEST(MessageEvent, Audio) -{ - auto info = - QJsonObject{ { "duration", 2140786 }, { "mimetype", "audio/mpeg" }, { "size", 1563688 } }; - - auto content = QJsonObject{ { "body", "Bee Gees - Stayin' Alive" }, - { "msgtype", "m.audio" }, - { "url", "mxc://localhost/2sdfj23f33r3faad" }, - { "info", info } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Audio> audio; - audio.deserialize(event); - - EXPECT_EQ(audio.msgContent().info().duration, 2140786); - EXPECT_EQ(audio.msgContent().info().size, 1563688); - EXPECT_EQ(audio.msgContent().info().mimetype, "audio/mpeg"); - EXPECT_EQ(audio.content().body(), "Bee Gees - Stayin' Alive"); -} - -TEST(MessageEvent, Emote) -{ - auto content = QJsonObject{ { "body", "emote message" }, { "msgtype", "m.emote" } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Emote> emote; - emote.deserialize(event); - - EXPECT_EQ(emote.content().body(), "emote message"); -} - -TEST(MessageEvent, File) -{ - auto thumbnail_info = QJsonObject{ - { "h", 300 }, { "w", 400 }, { "size", 3432434 }, { "mimetype", "image/jpeg" } - }; - - auto file_info = QJsonObject{ { "size", 24242424 }, - { "mimetype", "application/msword" }, - { "thumbnail_url", "mxc://localhost/adfaefaFAFSDFF3" }, - { "thumbnail_info", thumbnail_info } }; - - auto content = QJsonObject{ { "body", "something-important.doc" }, - { "filename", "something-important.doc" }, - { "url", "mxc://localhost/23d233d32r3r2r" }, - { "info", file_info }, - { "msgtype", "m.file" } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::File> file; - file.deserialize(event); - - EXPECT_EQ(file.content().body(), "something-important.doc"); - EXPECT_EQ(file.msgContent().info().thumbnail_info.h, 300); - EXPECT_EQ(file.msgContent().info().thumbnail_info.w, 400); - EXPECT_EQ(file.msgContent().info().thumbnail_info.mimetype, "image/jpeg"); - EXPECT_EQ(file.msgContent().info().mimetype, "application/msword"); - EXPECT_EQ(file.msgContent().info().size, 24242424); - EXPECT_EQ(file.content().body(), "something-important.doc"); -} - -TEST(MessageEvent, Image) -{ - auto thumbinfo = QJsonObject{ - { "h", 11 }, { "w", 22 }, { "size", 212 }, { "mimetype", "img/jpeg" }, - }; - - auto imginfo = QJsonObject{ - { "h", 110 }, - { "w", 220 }, - { "size", 2120 }, - { "mimetype", "img/jpeg" }, - { "thumbnail_url", "https://images.com/image-thumb.jpg" }, - { "thumbnail_info", thumbinfo }, - }; - - auto content = QJsonObject{ { "body", "Image title" }, - { "msgtype", "m.image" }, - { "url", "https://images.com/image.jpg" }, - { "info", imginfo } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Image> img; - img.deserialize(event); - - EXPECT_EQ(img.content().body(), "Image title"); - EXPECT_EQ(img.msgContent().info().h, 110); - EXPECT_EQ(img.msgContent().info().w, 220); - EXPECT_EQ(img.msgContent().info().thumbnail_info.w, 22); - EXPECT_EQ(img.msgContent().info().mimetype, "img/jpeg"); - EXPECT_EQ(img.msgContent().info().thumbnail_url, "https://images.com/image-thumb.jpg"); -} - -TEST(MessageEvent, Location) -{ - auto thumbnail_info = QJsonObject{ - { "h", 300 }, { "w", 400 }, { "size", 3432434 }, { "mimetype", "image/jpeg" } - }; - - auto info = QJsonObject{ { "thumbnail_url", "mxc://localhost/adfaefaFAFSDFF3" }, - { "thumbnail_info", thumbnail_info } }; - - auto content = QJsonObject{ { "body", "Big Ben, London, UK" }, - { "geo_uri", "geo:51.5008,0.1247" }, - { "info", info }, - { "msgtype", "m.location" } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Location> location; - location.deserialize(event); - - EXPECT_EQ(location.msgContent().info().thumbnail_info.h, 300); - EXPECT_EQ(location.msgContent().info().thumbnail_info.w, 400); - EXPECT_EQ(location.msgContent().info().thumbnail_info.mimetype, "image/jpeg"); - EXPECT_EQ(location.msgContent().info().thumbnail_url, "mxc://localhost/adfaefaFAFSDFF3"); - EXPECT_EQ(location.content().body(), "Big Ben, London, UK"); -} - -TEST(MessageEvent, Notice) -{ - auto content = QJsonObject{ { "body", "notice message" }, { "msgtype", "m.notice" } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Notice> notice; - notice.deserialize(event); - - EXPECT_EQ(notice.content().body(), "notice message"); -} - -TEST(MessageEvent, Text) -{ - auto content = QJsonObject{ { "body", "text message" }, { "msgtype", "m.text" } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Text> text; - text.deserialize(event); - - EXPECT_EQ(text.content().body(), "text message"); -} - -TEST(MessageEvent, Video) -{ - auto thumbnail_info = QJsonObject{ - { "h", 300 }, { "w", 400 }, { "size", 3432434 }, { "mimetype", "image/jpeg" } - }; - - auto video_info = QJsonObject{ { "h", 222 }, - { "w", 333 }, - { "duration", 232323 }, - { "size", 24242424 }, - { "mimetype", "video/mp4" }, - { "thumbnail_url", "mxc://localhost/adfaefaFAFSDFF3" }, - { "thumbnail_info", thumbnail_info } }; - - auto content = QJsonObject{ { "body", "Gangnam Style" }, - { "url", "mxc://localhost/23d233d32r3r2r" }, - { "info", video_info }, - { "msgtype", "m.video" } }; - - auto event = QJsonObject{ { "content", content }, - { "event_id", "$asdfafdf8af:matrix.org" }, - { "room_id", "!aasdfaeae23r9:matrix.org" }, - { "sender", "@alice:matrix.org" }, - { "origin_server_ts", 1323238293289323LL }, - { "type", "m.room.message" } }; - - MessageEvent<messages::Video> video; - video.deserialize(event); - - EXPECT_EQ(video.msgContent().info().thumbnail_info.h, 300); - EXPECT_EQ(video.msgContent().info().thumbnail_info.w, 400); - EXPECT_EQ(video.msgContent().info().thumbnail_info.mimetype, "image/jpeg"); - EXPECT_EQ(video.msgContent().info().duration, 232323); - EXPECT_EQ(video.msgContent().info().size, 24242424); - EXPECT_EQ(video.msgContent().info().mimetype, "video/mp4"); - EXPECT_EQ(video.content().body(), "Gangnam Style"); -} - -TEST(MessageEvent, Types) -{ - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.audio" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Audio); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.emote" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Emote); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.file" } } }, { "type", "m.room.message" }, - }), - MessageEventType::File); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.image" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Image); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.location" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Location); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.notice" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Notice); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.text" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Text); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.video" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Video); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.random" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Unknown); -} |