file_utilities_linux.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "platform/linux/file_utilities_linux.h"
  8. #include "base/platform/base_platform_info.h"
  9. #include "base/platform/linux/base_linux_xdp_utilities.h"
  10. #include "base/platform/linux/base_linux_xdg_activation_token.h"
  11. #include "base/random.h"
  12. #include <fcntl.h>
  13. #include <xdpopenuri/xdpopenuri.hpp>
  14. #include <xdprequest/xdprequest.hpp>
  15. namespace Platform {
  16. namespace File {
  17. namespace {
  18. using namespace gi::repository;
  19. using base::Platform::XdgActivationToken;
  20. } // namespace
  21. bool UnsafeShowOpenWith(const QString &filepath) {
  22. auto proxy = XdpOpenURI::OpenURIProxy::new_for_bus_sync(
  23. Gio::BusType::SESSION_,
  24. Gio::DBusProxyFlags::NONE_,
  25. base::Platform::XDP::kService,
  26. base::Platform::XDP::kObjectPath,
  27. nullptr);
  28. if (!proxy) {
  29. return false;
  30. }
  31. auto interface = XdpOpenURI::OpenURI(proxy);
  32. if (interface.get_version() < 3) {
  33. return false;
  34. }
  35. const auto fd = open(
  36. QFile::encodeName(filepath).constData(),
  37. O_RDONLY | O_CLOEXEC);
  38. if (fd == -1) {
  39. return false;
  40. }
  41. const auto handleToken = "tdesktop"
  42. + std::to_string(base::RandomValue<uint>());
  43. std::string uniqueName = proxy.get_connection().get_unique_name();
  44. uniqueName.erase(0, 1);
  45. uniqueName.replace(uniqueName.find('.'), 1, 1, '_');
  46. auto request = XdpRequest::Request(
  47. XdpRequest::RequestProxy::new_sync(
  48. proxy.get_connection(),
  49. Gio::DBusProxyFlags::NONE_,
  50. base::Platform::XDP::kService,
  51. base::Platform::XDP::kObjectPath
  52. + std::string("/request/")
  53. + uniqueName
  54. + '/'
  55. + handleToken,
  56. nullptr,
  57. nullptr));
  58. if (!request) {
  59. close(fd);
  60. return false;
  61. }
  62. auto loop = GLib::MainLoop::new_();
  63. const auto signalId = request.signal_response().connect([=](
  64. XdpRequest::Request,
  65. guint,
  66. GLib::Variant) mutable {
  67. loop.quit();
  68. });
  69. const auto signalGuard = gsl::finally([&] {
  70. request.disconnect(signalId);
  71. });
  72. auto result = interface.call_open_file_sync(
  73. base::Platform::XDP::ParentWindowID(),
  74. GLib::Variant::new_handle(0),
  75. GLib::Variant::new_array({
  76. GLib::Variant::new_dict_entry(
  77. GLib::Variant::new_string("handle_token"),
  78. GLib::Variant::new_variant(
  79. GLib::Variant::new_string(handleToken))),
  80. GLib::Variant::new_dict_entry(
  81. GLib::Variant::new_string("activation_token"),
  82. GLib::Variant::new_variant(
  83. GLib::Variant::new_string(
  84. XdgActivationToken().toStdString()))),
  85. GLib::Variant::new_dict_entry(
  86. GLib::Variant::new_string("ask"),
  87. GLib::Variant::new_variant(
  88. GLib::Variant::new_boolean(true))),
  89. }),
  90. Gio::UnixFDList::new_from_array(&fd, 1),
  91. nullptr);
  92. if (!result) {
  93. return false;
  94. }
  95. QWidget window;
  96. window.setAttribute(Qt::WA_DontShowOnScreen);
  97. window.setWindowModality(Qt::ApplicationModal);
  98. window.show();
  99. loop.run();
  100. return true;
  101. }
  102. } // namespace File
  103. } // namespace Platform