#include "EventAccessors.h" #include #include #include namespace { struct nonesuch { ~nonesuch() = delete; nonesuch(nonesuch const &) = delete; void operator=(nonesuch const &) = delete; }; namespace detail { template class Op, class... Args> struct detector { using value_t = std::false_type; using type = Default; }; template class Op, class... Args> struct detector>, Op, Args...> { using value_t = std::true_type; using type = Op; }; } // namespace detail template class Op, class... Args> using is_detected = typename detail::detector::value_t; struct EventMsgType { template using msgtype_t = decltype(E::msgtype); template mtx::events::MessageType operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { if constexpr (std::is_same_v, std::remove_cv_t>) return mtx::events::getMessageType(e.content.msgtype.value()); else if constexpr (std::is_same_v< std::string, std::remove_cv_t>) return mtx::events::getMessageType(e.content.msgtype); } return mtx::events::MessageType::Unknown; } }; struct EventRoomName { template std::string operator()(const T &e) { if constexpr (std::is_same_v, T>) return e.content.name; return ""; } }; struct EventRoomTopic { template std::string operator()(const T &e) { if constexpr (std::is_same_v, T>) return e.content.topic; return ""; } }; 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.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 std::string(); } }; struct EventBody { template using body_t = decltype(C::body); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { if constexpr (std::is_same_v, std::remove_cv_t>) return e.content.body ? e.content.body.value() : ""; else if constexpr (std::is_same_v< std::string, std::remove_cv_t>) return e.content.body; } return ""; } }; struct EventFormattedBody { template using formatted_body_t = decltype(C::formatted_body); template std::string operator()(const mtx::events::RoomEvent &e) { if constexpr (is_detected::value) { if (e.content.format == "org.matrix.custom.html") return e.content.formatted_body; } return ""; } }; struct EventFile { template using file_t = decltype(Content::file); template std::optional operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) return e.content.file; return std::nullopt; } }; struct EventUrl { template using url_t = decltype(Content::url); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { if (auto file = EventFile{}(e)) return file->url; return e.content.url; } return ""; } }; struct EventThumbnailUrl { template using thumbnail_url_t = decltype(Content::info.thumbnail_url); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { return e.content.info.thumbnail_url; } return ""; } }; struct EventBlurhash { template using blurhash_t = decltype(Content::info.blurhash); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { 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 using mimetype_t = decltype(Content::info.mimetype); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { return e.content.info.mimetype; } return ""; } }; struct EventFilesize { template using filesize_t = decltype(Content::info.size); template int64_t operator()(const mtx::events::RoomEvent &e) { if constexpr (is_detected::value) { return e.content.info.size; } return 0; } }; struct EventInReplyTo { template using related_ev_id_t = decltype(Content::relates_to.in_reply_to.event_id); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { return e.content.relates_to.in_reply_to.event_id; } return ""; } }; struct EventRelatesTo { template using related_ev_id_t = decltype(Content::relates_to.event_id); template std::string operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { return e.content.relates_to.event_id; } return ""; } }; 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 using h_t = decltype(Content::info.h); template uint64_t operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { return e.content.info.h; } return -1; } }; struct EventMediaWidth { template using w_t = decltype(Content::info.w); template uint64_t operator()(const mtx::events::Event &e) { if constexpr (is_detected::value) { 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.; } } std::string mtx::accessors::event_id(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto e) { return e.event_id; }, event); } std::string mtx::accessors::room_id(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto e) { return e.room_id; }, event); } std::string mtx::accessors::sender(const mtx::events::collections::TimelineEvents &event) { return std::visit([](const auto e) { return e.sender; }, event); } QDateTime mtx::accessors::origin_server_ts(const mtx::events::collections::TimelineEvents &event) { return QDateTime::fromMSecsSinceEpoch( 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::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) { return std::visit(EventRoomName{}, event); } std::string mtx::accessors::room_topic(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventRoomTopic{}, event); } 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) { return std::visit(EventBody{}, event); } std::string mtx::accessors::formatted_body(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventFormattedBody{}, event); } 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("\n", "
"); } std::optional mtx::accessors::file(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventFile{}, 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); } 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); } std::string mtx::accessors::in_reply_to_event(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventInReplyTo{}, event); } std::string mtx::accessors::relates_to_event_id(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventRelatesTo{}, 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 std::visit([](const auto &e) { return nlohmann::json(e); }, event); }