| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "data/data_document_resolver.h"
- #include "base/options.h"
- #include "base/platform/base_platform_info.h"
- #include "boxes/abstract_box.h" // Ui::show().
- #include "chat_helpers/ttl_media_layer_widget.h"
- #include "core/application.h"
- #include "core/core_settings.h"
- #include "core/mime_type.h"
- #include "data/data_document.h"
- #include "data/data_document_media.h"
- #include "data/data_file_click_handler.h"
- #include "data/data_session.h"
- #include "history/history.h"
- #include "history/history_item.h"
- #include "history/view/media/history_view_gif.h"
- #include "lang/lang_keys.h"
- #include "media/player/media_player_instance.h"
- #include "platform/platform_file_utilities.h"
- #include "ui/boxes/confirm_box.h"
- #include "ui/chat/chat_theme.h"
- #include "ui/text/text_utilities.h"
- #include "ui/widgets/checkbox.h"
- #include "ui/wrap/slide_wrap.h"
- #include "window/window_session_controller.h"
- #include "styles/style_layers.h"
- #include <QtCore/QBuffer>
- #include <QtCore/QMimeType>
- #include <QtCore/QMimeDatabase>
- namespace Data {
- namespace {
- base::options::toggle OptionExternalVideoPlayer({
- .id = kOptionExternalVideoPlayer,
- .name = "External video player",
- .description = "Use system video player instead of the internal one. "
- "This disabes video playback in messages.",
- });
- void ConfirmDontWarnBox(
- not_null<Ui::GenericBox*> box,
- rpl::producer<TextWithEntities> &&text,
- rpl::producer<QString> &&check,
- rpl::producer<QString> &&confirm,
- Fn<void(bool)> callback) {
- auto checkbox = object_ptr<Ui::Checkbox>(
- box.get(),
- std::move(check),
- false,
- st::defaultBoxCheckbox);
- const auto weak = Ui::MakeWeak(checkbox.data());
- auto confirmed = crl::guard(weak, [=, callback = std::move(callback)] {
- const auto checked = weak->checked();
- box->closeBox();
- callback(checked);
- });
- Ui::ConfirmBox(box, {
- .text = std::move(text),
- .confirmed = std::move(confirmed),
- .confirmText = std::move(confirm),
- });
- auto padding = st::boxPadding;
- padding.setTop(padding.bottom());
- box->addRow(std::move(checkbox), std::move(padding));
- box->addRow(object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
- box,
- object_ptr<Ui::FlatLabel>(
- box,
- tr::lng_launch_dont_ask_settings(),
- st::boxLabel)
- ))->toggleOn(weak->checkedValue());
- }
- void LaunchWithWarning(
- // not_null<Window::Controller*> controller,
- const QString &name,
- HistoryItem *item) {
- const auto nameType = Core::DetectNameType(name);
- const auto isIpReveal = (nameType != Core::NameType::Executable)
- && Core::IsIpRevealingPath(name);
- const auto extension = Core::FileExtension(name).toLower();
- auto &app = Core::App();
- auto &settings = app.settings();
- const auto warn = [&] {
- if (item && item->history()->peer->isVerified()) {
- return false;
- }
- return (isIpReveal && settings.ipRevealWarning())
- || ((nameType == Core::NameType::Executable
- || nameType == Core::NameType::Unknown)
- && !settings.noWarningExtensions().contains(extension));
- }();
- if (extension.isEmpty()) {
- // If you launch a file without extension, like "test", in case
- // there is an executable file with the same name in this folder,
- // like "test.bat", the executable file will be launched.
- //
- // Now we always force an Open With dialog box for such files.
- //
- // Let's force it for all platforms for files without extension.
- crl::on_main([=] {
- Platform::File::UnsafeShowOpenWith(name);
- });
- return;
- } else if (!warn) {
- File::Launch(name);
- return;
- }
- const auto callback = [=, &app, &settings](bool checked) {
- if (checked) {
- if (isIpReveal) {
- settings.setIpRevealWarning(false);
- } else {
- auto copy = settings.noWarningExtensions();
- copy.emplace(extension);
- settings.setNoWarningExtensions(std::move(copy));
- }
- app.saveSettingsDelayed();
- }
- File::Launch(name);
- };
- auto text = isIpReveal
- ? tr::lng_launch_svg_warning(Ui::Text::WithEntities)
- : ((nameType == Core::NameType::Executable)
- ? tr::lng_launch_exe_warning
- : tr::lng_launch_other_warning)(
- lt_extension,
- rpl::single(Ui::Text::Bold('.' + extension)),
- Ui::Text::WithEntities);
- auto check = (isIpReveal
- ? tr::lng_launch_exe_dont_ask
- : tr::lng_launch_dont_ask)();
- auto confirm = ((nameType == Core::NameType::Executable)
- ? tr::lng_launch_exe_sure
- : tr::lng_launch_other_sure)();
- Ui::show(Box(
- ConfirmDontWarnBox,
- std::move(text),
- std::move(check),
- std::move(confirm),
- callback));
- }
- } // namespace
- const char kOptionExternalVideoPlayer[] = "external-video-player";
- base::binary_guard ReadBackgroundImageAsync(
- not_null<Data::DocumentMedia*> media,
- FnMut<QImage(QImage)> postprocess,
- FnMut<void(QImage&&)> done) {
- auto result = base::binary_guard();
- const auto gzipSvg = media->owner()->isPatternWallPaperSVG();
- crl::async([
- gzipSvg,
- bytes = media->bytes(),
- path = media->owner()->filepath(),
- postprocess = std::move(postprocess),
- guard = result.make_guard(),
- callback = std::move(done)
- ]() mutable {
- auto image = Ui::ReadBackgroundImage(path, bytes, gzipSvg);
- if (postprocess) {
- image = postprocess(std::move(image));
- }
- crl::on_main(std::move(guard), [
- image = std::move(image),
- callback = std::move(callback)
- ]() mutable {
- callback(std::move(image));
- });
- });
- return result;
- }
- void ResolveDocument(
- Window::SessionController *controller,
- not_null<DocumentData*> document,
- HistoryItem *item,
- MsgId topicRootId) {
- if (document->isNull()) {
- return;
- }
- const auto msgId = item ? item->fullId() : FullMsgId();
- const auto showDocument = [&] {
- if (OptionExternalVideoPlayer.value()
- && document->isVideoFile()
- && !document->filepath().isEmpty()) {
- File::Launch(document->location(false).fname);
- } else if (controller) {
- controller->openDocument(
- document,
- true,
- { msgId, topicRootId });
- }
- };
- const auto media = document->createMediaView();
- const auto openImageInApp = [&] {
- if (document->size >= Images::kReadBytesLimit) {
- return false;
- }
- const auto &location = document->location(true);
- const auto mime = u"image/"_q;
- if (!location.isEmpty() && location.accessEnable()) {
- const auto guard = gsl::finally([&] {
- location.accessDisable();
- });
- const auto path = location.name();
- if (Core::MimeTypeForFile(QFileInfo(path)).name().startsWith(mime)
- && QImageReader(path).canRead()) {
- showDocument();
- return true;
- }
- } else if (document->mimeString().startsWith(mime)
- && !media->bytes().isEmpty()) {
- auto bytes = media->bytes();
- auto buffer = QBuffer(&bytes);
- if (QImageReader(&buffer).canRead()) {
- showDocument();
- return true;
- }
- }
- return false;
- };
- const auto &location = document->location(true);
- if (document->isTheme() && media->loaded(true)) {
- showDocument();
- location.accessDisable();
- } else if (media->canBePlayed(item)) {
- if (document->isAudioFile()
- || document->isVoiceMessage()
- || document->isVideoMessage()) {
- ::Media::Player::instance()->playPause({ document, msgId });
- if (controller
- && item
- && item->media()
- && item->media()->ttlSeconds()) {
- ChatHelpers::ShowTTLMediaLayerWidget(controller, item);
- }
- } else {
- showDocument();
- }
- } else {
- document->saveFromDataSilent();
- if (!openImageInApp()) {
- if (!document->filepath(true).isEmpty()) {
- LaunchWithWarning(location.name(), item);
- } else if (document->status == FileReady
- || document->status == FileDownloadFailed) {
- DocumentSaveClickHandler::Save(
- item ? item->fullId() : Data::FileOrigin(),
- document);
- }
- }
- }
- }
- } // namespace Data
|