diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -111,6 +111,7 @@ endif() qt5_add_dbus_interface(kiocore_SRCS org.kde.KSlaveLauncher.xml klauncher_interface) +qt5_add_dbus_interface(kiocore_SRCS org.kde.KIOFuse.VFS.xml kiofuse_interface) set_source_files_properties(org.kde.KPasswdServer.xml PROPERTIES INCLUDE authinfo.h diff --git a/src/core/desktopexecparser.cpp b/src/core/desktopexecparser.cpp --- a/src/core/desktopexecparser.cpp +++ b/src/core/desktopexecparser.cpp @@ -20,6 +20,7 @@ */ #include "desktopexecparser.h" +#include "kiofuse_interface.h" #include #include @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include // CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 @@ -305,26 +308,50 @@ return result; } - // Check if we need kioexec + // Check if we need kioexec, or KIOFuse bool useKioexec = false; + org::kde::KIOFuse::VFS kiofuse_iface(QStringLiteral("org.kde.KIOFuse"), + QStringLiteral("/org/kde/KIOFuse"), + QDBusConnection::sessionBus()); + struct MountRequest { QDBusPendingReply reply; int urlIndex; }; + QVector requests; + requests.reserve(d->urls.count()); + QStringList appSupportedProtocols = supportedProtocols(d->service); if (!mx1.hasUrls) { - for (const QUrl &url : qAsConst(d->urls)) { + for (int i = 0; i < d->urls.count(); ++i) { + const QUrl url = d->urls.at(i); if (!url.isLocalFile() && !hasSchemeHandler(url)) { - useKioexec = true; - //qCDebug(KIO_CORE) << "non-local files, application does not support urls, using kioexec"; - break; + // Lets try a KIOFuse mount instead. + requests.push_back({ kiofuse_iface.mountUrl(url.toString()), i }); } } - } else { // app claims to support %u/%U, check which protocols - QStringList appSupportedProtocols = supportedProtocols(d->service); - for (const QUrl &url : qAsConst(d->urls)) { - if (!isProtocolInSupportedList(url, appSupportedProtocols) && !hasSchemeHandler(url)) { - useKioexec = true; - //qCDebug(KIO_CORE) << "application does not support url, using kioexec:" << url; - break; + } else if (!appSupportedProtocols.contains(QLatin1String("KIO"))) { + for (int i = 0; i < d->urls.count(); ++i) { + const QUrl url = d->urls.at(i); + const bool supported = isProtocolInSupportedList(url, appSupportedProtocols); + // NOTE: Some non-KIO apps may support the URLs (e.g. VLC supports smb://) + // but will not have the password if they are not in the URL itself. + // Hence convert URL to KIOFuse equivalent in case there is a password. + // @see https://pointieststick.com/2018/01/17/videos-on-samba-shares/ + // @see https://bugs.kde.org/show_bug.cgi?id=330192 + if (!supported || (!url.userName().isEmpty() && url.password().isEmpty())) { + requests.push_back({ kiofuse_iface.mountUrl(url.toString()), i }); } } } + + // Doesn't matter that we've blocked here to process the replies. + // Main thing that we want is to send the mount requests without blocking. + for (auto &request : requests) { + request.reply.waitForFinished(); + if (request.reply.isError()) { + useKioexec = true; + // At this point we should just send the original urls to kioexec. + // There's no point sending urls to kioexec that go through kiofuse. + break; + } + } + if (useKioexec) { // We need to run the app through kioexec result << kioexecPath(); @@ -340,6 +367,12 @@ return result; } + // At this point we know we're not using kioexec, so feel free to replace + // KIO URLs with their KIOFuse local path. + for (const auto &request : qAsConst(requests)) { + d->urls[request.urlIndex] = QUrl::fromLocalFile(request.reply.value()); + } + if (appHasTempFileOption) { exec += QLatin1String(" --tempfile"); } diff --git a/src/core/org.kde.KIOFuse.VFS.xml b/src/core/org.kde.KIOFuse.VFS.xml new file mode 100644 --- /dev/null +++ b/src/core/org.kde.KIOFuse.VFS.xml @@ -0,0 +1,9 @@ + + + + + + + + +