// SPDX-FileCopyrightText: Nheko Contributors // // SPDX-License-Identifier: GPL-3.0-or-later #include "EventAccessors.h" #include #include #include #include #include namespace { struct IsStateEvent { template constexpr bool operator()(const mtx::events::StateEvent &) { return true; } template constexpr bool operator()(const mtx::events::Event &) { return false; } }; struct EventMsgType { template mtx::events::MessageType operator()(const mtx::events::Event &e) { if constexpr (requires(decltype(e) t) { t.content.msgtype.value(); }) return mtx::events::getMessageType(e.content.msgtype.value()); else if constexpr (requires(decltype(e) t) { std::string{t.content.msgtype}; }) return mtx::events::getMessageType(e.content.msgtype); return mtx::events::MessageType::Unknown; } }; struct EventType { template mtx::events::EventType operator()(const mtx::events::Event &e) { return e.type; } }; struct CallType { template std::string operator()(const T &e) { if constexpr (std::is_same_v, T>) { const char video[] = "m=video"; const std::string &sdp = e.content.offer.sdp; return std::search(sdp.cbegin(), sdp.cend(), std::cbegin(video), std::cend(video) - 1, [](unsigned char c1, unsigned char c2) { return std::tolower(c1) == std::tolower(c2); }) != sdp.cend() ? "video" : "voice"; } return ""; } }; struct EventBody { template const std::string *operator()(const mtx::events::Event &e) { if constexpr (requires(decltype(e) t) { t.content.body.value(); }) return e.content.body ? &e.content.body.value() : nullptr; else if constexpr (requires(decltype(e) t) { std::string{t.content.body}; }) return &e.content.body; return nullptr; } }; struct EventFormattedBody { template const std::string *operator()(const mtx::events::RoomEvent &e) { if constexpr (requires { T::formatted_body; }) { if (e.content.format == "org.matrix.custom.html") return &e.content.formatted_body; } return nullptr; } }; struct EventFile { template const std::optional *operator()(const mtx::events::Event &e) { if constexpr (requires { T::file; }) return &e.content.file; return nullptr; } }; struct EventThumbnailFile { template std::optional operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.thumbnail_file; }) return e.content.info.thumbnail_file; return std::nullopt; } }; struct EventUrl { template std::string operator()(const mtx::events::Event &e) { if constexpr (requires { T::url; }) { if (auto file = EventFile{}(e); file && *file) return (*file)->url; return e.content.url; } return ""; } }; struct EventThumbnailUrl { template std::string operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.thumbnail_url; }) { if (auto file = EventThumbnailFile{}(e)) return file->url; return e.content.info.thumbnail_url; } return ""; } }; struct EventDuration { template uint64_t operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.duration; }) { return e.content.info.duration; } return 0; } }; struct EventBlurhash { template std::string operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.blurhash; }) { return e.content.info.blurhash; } return ""; } }; struct EventFilename { template std::string operator()(const mtx::events::Event &) { return ""; } std::string operator()(const mtx::events::RoomEvent &e) { // body may be the original filename return e.content.body; } std::string operator()(const mtx::events::RoomEvent &e) { // body may be the original filename return e.content.body; } std::string operator()(const mtx::events::RoomEvent &e) { // body may be the original filename return e.content.body; } std::string operator()(const mtx::events::RoomEvent &e) { // body may be the original filename if (!e.content.filename.empty()) return e.content.filename; return e.content.body; } }; struct EventMimeType { template std::string operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.mimetype; }) { return e.content.info.mimetype; } return ""; } }; struct EventFilesize { template int64_t operator()(const mtx::events::RoomEvent &e) { if constexpr (requires { e.content.info.size; }) { return e.content.info.size; } return 0; } }; struct EventRelations { inline const static mtx::common::Relations empty; template const mtx::common::Relations &operator()(const mtx::events::Event &e) { if constexpr (requires { T::relations; }) { return e.content.relations; } return empty; } }; struct EventMentions { template std::optional operator()(const mtx::events::Event &e) { if constexpr (requires { T::mentions; }) { return e.content.mentions; } return std::nullopt; } }; struct SetEventRelations { mtx::common::Relations new_relations; template void operator()(mtx::events::Event &e) { if constexpr (requires { T::relations; }) { e.content.relations = std::move(new_relations); } } }; struct EventTransactionId { template std::string operator()(const mtx::events::RoomEvent &e) { return e.unsigned_data.transaction_id; } template std::string operator()(const mtx::events::Event &e) { return e.unsigned_data.transaction_id; } }; struct EventMediaHeight { template uint64_t operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.h; }) { return e.content.info.h; } return -1; } }; struct EventMediaWidth { template uint64_t operator()(const mtx::events::Event &e) { if constexpr (requires { e.content.info.h; }) { return e.content.info.w; } return -1; } }; template double eventPropHeight(const mtx::events::RoomEvent &e) { auto w = eventWidth(e); if (w == 0) w = 1; double prop = eventHeight(e) / (double)w; return prop > 0 ? prop : 1.; } } const std::string & mtx::accessors::event_id(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto &e) -> const std::string & { return e.event_id; }, event); } const std::string & mtx::accessors::room_id(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto &e) -> const std::string & { return e.room_id; }, event); } const std::string & mtx::accessors::sender(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto &e) -> const std::string & { return e.sender; }, event); } QDateTime mtx::accessors::origin_server_ts(const mtx::events::collections::TimelineEvents &event) { return QDateTime::fromMSecsSinceEpoch(origin_server_ts_ms(event)); } std::uint64_t mtx::accessors::origin_server_ts_ms(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto &e) { return e.origin_server_ts; }, event); } std::string mtx::accessors::filename(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventFilename{}, event); } mtx::events::EventType mtx::accessors::event_type(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventType{}, event); } mtx::events::MessageType mtx::accessors::msg_type(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventMsgType{}, event); } std::string mtx::accessors::room_name(const mtx::events::collections::TimelineEvents &event) { if (auto c = std::get_if>(&event)) return c->content.name; else return ""; } std::string mtx::accessors::room_topic(const mtx::events::collections::TimelineEvents &event) { if (auto c = std::get_if>(&event)) return c->content.topic; else return ""; } std::string mtx::accessors::call_type(const mtx::events::collections::TimelineEvents &event) { return std::visit(CallType{}, event); } std::string mtx::accessors::body(const mtx::events::collections::TimelineEvents &event) { auto body = std::visit(EventBody{}, event); return body ? *body : std::string{}; } std::string mtx::accessors::formatted_body(const mtx::events::collections::TimelineEvents &event) { auto body = std::visit(EventFormattedBody{}, event); return body ? *body : std::string{}; } QString mtx::accessors::formattedBodyWithFallback(const mtx::events::collections::TimelineEvents &event) { auto formatted = formatted_body(event); if (!formatted.empty()) return QString::fromStdString(formatted); else return QString::fromStdString(body(event)) .toHtmlEscaped() .replace(QLatin1String("\n"), QLatin1String("
")); } std::optional mtx::accessors::file(const mtx::events::collections::TimelineEvents &event) { auto temp = std::visit(EventFile{}, event); if (temp) return *temp; else return {}; } std::optional mtx::accessors::thumbnail_file(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventThumbnailFile{}, event); } std::string mtx::accessors::url(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventUrl{}, event); } std::string mtx::accessors::thumbnail_url(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventThumbnailUrl{}, event); } uint64_t mtx::accessors::duration(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventDuration{}, event); } std::string mtx::accessors::blurhash(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventBlurhash{}, event); } std::string mtx::accessors::mimetype(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventMimeType{}, event); } const mtx::common::Relations & mtx::accessors::relations(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventRelations{}, event); } std::optional mtx::accessors::mentions(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventMentions{}, event); } void mtx::accessors::set_relations(mtx::events::collections::TimelineEvents &event, mtx::common::Relations relations) { std::visit(SetEventRelations{std::move(relations)}, event); } std::string mtx::accessors::transaction_id(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventTransactionId{}, event); } int64_t mtx::accessors::filesize(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventFilesize{}, event); } uint64_t mtx::accessors::media_height(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventMediaHeight{}, event); } uint64_t mtx::accessors::media_width(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventMediaWidth{}, event); } nlohmann::json mtx::accessors::serialize_event(const mtx::events::collections::TimelineEvents &event) { return nlohmann::json(event); } bool mtx::accessors::is_state_event(const mtx::events::collections::StateEvents &event) { return std::visit(IsStateEvent{}, event); } bool mtx::accessors::is_state_event(const mtx::events::collections::TimelineEvents &event) { return std::visit(IsStateEvent{}, event); } template static constexpr auto isMessage(const mtx::events::RoomEvent &e) -> std::enable_if_t::value, bool> { return true; } template static constexpr auto isMessage(const mtx::events::Event &) { return false; } template static constexpr auto isMessage(const mtx::events::EncryptedEvent &) { return true; } static constexpr auto isMessage(const mtx::events::RoomEvent &) { return true; } static constexpr auto isMessage(const mtx::events::RoomEvent &) { return true; } static constexpr auto isMessage(const mtx::events::RoomEvent &) { return true; } static constexpr auto isMessage(const mtx::events::RoomEvent &) { return true; } static constexpr auto isMessage(const mtx::events::RoomEvent &) { return true; } bool mtx::accessors::is_message(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto &e) { return isMessage(e); }, event); }