diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index d4fcfacf..9db16bae 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -41,14 +41,6 @@ public: connect(&typingTimeout_, &QTimer::timeout, this, &InputBar::stopTyping); } - void image(const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize, - const QSize &dimensions, - const QString &blurhash); - public slots: QString text() const; QString previousText(); @@ -78,6 +70,13 @@ private: void emote(QString body, bool rainbowify); void notice(QString body, bool rainbowify); void command(QString name, QString args); + void image(const QString &filename, + const std::optional &file, + const QString &url, + const QString &mime, + uint64_t dsize, + const QSize &dimensions, + const QString &blurhash); void file(const QString &filename, const std::optional &encryptedFile, const QString &url, diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index ae807f2d..f71fd42b 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -627,86 +627,72 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven auto elem = *e; auto room = models.find(roomId); auto messageType = mtx::accessors::msg_type(elem); + auto content = mtx::accessors::url(elem); - if (sentFromEncrypted && messageType == mtx::events::MessageType::Image) { - auto body = mtx::accessors::body(elem); - auto mimetype = mtx::accessors::mimetype(elem); - auto imageHeight = mtx::accessors::media_height(elem); - auto imageWidth = mtx::accessors::media_height(elem); + if (sentFromEncrypted) { + std::optional encryptionInfo = + mtx::accessors::file(elem); - QString mxcUrl = QString::fromStdString(mtx::accessors::url(elem)); - MxcImageProvider::download( - mxcUrl.remove("mxc://"), - QSize(imageWidth, imageHeight), - [this, roomId, body, mimetype](QString, QSize, QImage image, QString) { - QByteArray data = - QByteArray::fromRawData((const char *)image.bits(), image.byteCount()); - - auto payload = std::string(data.data(), data.size()); - std::optional encryptedFile; - - QSize dimensions; - QString blurhash; - auto mimeClass = QString::fromStdString(mimetype).split("/")[0]; - - dimensions = image.size(); - if (image.height() > 200 && image.width() > 360) - image = image.scaled(360, 200, Qt::KeepAspectRatioByExpanding); - std::vector data_; - for (int y = 0; y < image.height(); y++) { - for (int x = 0; x < image.width(); x++) { - auto p = image.pixel(x, y); - data_.push_back(static_cast(qRed(p))); - data_.push_back(static_cast(qGreen(p))); - data_.push_back(static_cast(qBlue(p))); - } + http::client()->download( + content, + [this, roomId, e, encryptionInfo](const std::string &res, + const std::string &content_type, + const std::string &originalFilename, + mtx::http::RequestErr err) { + if (err) { + return; } - blurhash = QString::fromStdString( - blurhash::encode(data_.data(), image.width(), image.height(), 4, 3)); - http::client()->upload( - payload, - encryptedFile ? "application/octet-stream" : mimetype, - body, - [this, - roomId, - filename = body, - encryptedFile = std::move(encryptedFile), - mimeClass, - mimetype, - size = payload.size(), - dimensions, - blurhash](const mtx::responses::ContentURI &res, - mtx::http::RequestErr err) mutable { - if (err) { - nhlog::net()->warn("failed to upload media: {} {} ({})", - err->matrix_error.error, - to_string(err->matrix_error.errcode), - static_cast(err->status_code)); - return; - } + assert(encryptionInfo); - auto url = QString::fromStdString(res.content_uri); - if (encryptedFile) - encryptedFile->url = res.content_uri; + auto data = mtx::crypto::to_string( + mtx::crypto::decrypt_file(res, encryptionInfo.value())); - auto r = models.find(roomId); - r.value()->input()->image(QString::fromStdString(filename), - encryptedFile, - url, - QString::fromStdString(mimetype), - size, - dimensions, - blurhash); - }); + http::client()->upload( + data, + content_type, + originalFilename, + [this, roomId, e](const mtx::responses::ContentURI &res, + mtx::http::RequestErr err) mutable { + if (err) { + nhlog::net()->warn("failed to upload media: {} {} ({})", + err->matrix_error.error, + to_string(err->matrix_error.errcode), + static_cast(err->status_code)); + return; + } + + std::visit( + [this, roomId, e, url = res.content_uri](auto ev) { + if constexpr (mtx::events::message_content_to_type< + decltype(ev.content)> == + mtx::events::EventType::RoomMessage) { + if constexpr (messageWithFileAndUrl(ev)) { + ev.content.relations.relations.clear(); + ev.content.file.reset(); + ev.content.url = url; + + auto room = models.find(roomId); + room.value()->sendMessageEvent( + ev.content, + mtx::events::EventType::RoomMessage); + } + } + }, + *e); + }); + + return; }); + return; - }; + } std::visit( [room](auto e) { if constexpr (mtx::events::message_content_to_type == mtx::events::EventType::RoomMessage) { + e.content.relations.relations.clear(); room.value()->sendMessageEvent(e.content, mtx::events::EventType::RoomMessage); } diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 40bee990..9d1b4b1d 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "Cache.h" #include "CallManager.h" @@ -31,6 +32,33 @@ class UserSettings; class ChatPage; class DeviceVerificationFlow; +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; + class TimelineViewManager : public QObject { Q_OBJECT @@ -154,6 +182,23 @@ public slots: private slots: void openImageOverlayInternal(QString eventId, QImage img); +private: + template + using f_t = decltype(Content::file); + + template + using u_t = decltype(Content::url); + + template + static constexpr bool messageWithFileAndUrl(const mtx::events::Event &e) + { + if constexpr (is_detected::value && is_detected::value) { + return true; + } + + return false; + } + private: #ifdef USE_QUICK_VIEW QQuickView *view;