diff options
author | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2017-12-04 18:41:19 +0200 |
---|---|---|
committer | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2017-12-04 18:41:19 +0200 |
commit | a605e4486f4b9d90d668d6d1844ba5f0d58bbc26 (patch) | |
tree | c82001904cb120d975361edb38a62b5b77fa0644 /src | |
parent | Run tests only with gcc (diff) | |
download | nheko-a605e4486f4b9d90d668d6d1844ba5f0d58bbc26.tar.xz |
Migrate to matrix-structs for event and response parsing
Diffstat (limited to 'src')
33 files changed, 456 insertions, 2044 deletions
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(); |