|
1 | 1 | package org.cryptomator.linux.revealpath;
|
2 | 2 |
|
| 3 | +import com.google.common.base.Preconditions; |
3 | 4 | import org.cryptomator.integrations.revealpath.RevealFailedException;
|
4 | 5 | import org.cryptomator.integrations.revealpath.RevealPathService;
|
5 | 6 |
|
|
15 | 16 | import java.util.concurrent.TimeUnit;
|
16 | 17 | import java.util.stream.Collectors;
|
17 | 18 |
|
18 |
| -public class DBusFileMangerRevealPath implements RevealPathService { |
| 19 | +/** |
| 20 | + * RevealPathService provider using the <a href="https://freedesktop.org/wiki/Specifications/file-manager-interface/">DBus freedesktop FileManager1 interface</a> and dbus-send command. |
| 21 | + */ |
| 22 | +public class DBusSendRevealPathService implements RevealPathService { |
19 | 23 |
|
| 24 | + private static final String FILEMANAGER1_XML_ELEMENT = "<interface name=\"org.freedesktop.FileManager1\">"; |
20 | 25 | private static final String FOR_FOLDERS = "org.freedesktop.FileManager1.ShowFolders";
|
21 | 26 | private static final String FOR_FILES = "org.freedesktop.FileManager1.ShowItems";
|
22 | 27 | private static final int TIMEOUT_THRESHOLD = 5000;
|
@@ -56,24 +61,52 @@ public void reveal(Path path) throws RevealFailedException {
|
56 | 61 |
|
57 | 62 | @Override
|
58 | 63 | public boolean isSupported() {
|
59 |
| - CountDownLatch waitBarrier = new CountDownLatch(3); |
60 |
| - ProcessBuilder builderExistsDbusSend = new ProcessBuilder().command("which", "dbus-send"); |
61 |
| - ProcessBuilder builderExistsNautilus = new ProcessBuilder().command("which", "nautilus"); |
62 |
| - ProcessBuilder builderExistsDolphin = new ProcessBuilder().command("which", "dolphin"); |
| 64 | + CountDownLatch waitBarrier = new CountDownLatch(2); |
| 65 | + ProcessBuilder dbusSendExistsBuilder = new ProcessBuilder().command("test", " `command -v dbus-send`"); |
| 66 | + ProcessBuilder fileManager1ExistsBuilder = createFileManager1Check(); |
| 67 | + |
63 | 68 | try {
|
64 |
| - var existsDbusSend = builderExistsDbusSend.start(); |
65 |
| - existsDbusSend.onExit().thenRun(waitBarrier::countDown); |
66 |
| - var existsNautilus = builderExistsNautilus.start(); |
67 |
| - existsNautilus.onExit().thenRun(waitBarrier::countDown); |
68 |
| - var existsDolphin = builderExistsDolphin.start(); |
69 |
| - existsDolphin.onExit().thenRun(waitBarrier::countDown); |
| 69 | + var dbusSendExists = dbusSendExistsBuilder.start(); |
| 70 | + dbusSendExists.onExit().thenRun(waitBarrier::countDown); |
| 71 | + var fileManager1Exists = fileManager1ExistsBuilder.start(); |
| 72 | + fileManager1Exists.onExit().thenRun(waitBarrier::countDown); |
| 73 | + |
70 | 74 | if (waitBarrier.await(TIMEOUT_THRESHOLD, TimeUnit.MILLISECONDS)) {
|
71 |
| - return existsDbusSend.exitValue() == 0 && (existsNautilus.exitValue() == 0 | existsDolphin.exitValue() == 0); |
| 75 | + if (dbusSendExists.exitValue() == 0 && fileManager1Exists.exitValue() == 0) { |
| 76 | + return parseOutputForFileManagerInterface(fileManager1Exists); |
| 77 | + } |
72 | 78 | }
|
73 | 79 | } catch (IOException | InterruptedException e) {
|
74 | 80 | //NO-OP
|
75 | 81 | }
|
76 | 82 | return false;
|
77 | 83 | }
|
78 | 84 |
|
| 85 | + /** |
| 86 | + * Parses process stdout to see if the answer contains "{@value FILEMANAGER1_XML_ELEMENT}". |
| 87 | + * DBus introspection output is defined in the <a href="https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format">dbus spec</a>. |
| 88 | + * |
| 89 | + * @param fileManager1Process The already exited process for checking the FileManager1 interface |
| 90 | + * @return {@code true} if the interface is found in the introspection output, otherwise false |
| 91 | + * @throws IOException if the Inputer reader on the process output cannot be created |
| 92 | + */ |
| 93 | + private boolean parseOutputForFileManagerInterface(Process fileManager1Process) throws IOException { |
| 94 | + Preconditions.checkState(!fileManager1Process.isAlive()); |
| 95 | + try (var reader = fileManager1Process.inputReader(StandardCharsets.UTF_8)) { |
| 96 | + return reader.lines().map(String::trim).anyMatch(FILEMANAGER1_XML_ELEMENT::equals); |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + private static ProcessBuilder createFileManager1Check() { |
| 101 | + return new ProcessBuilder().command( |
| 102 | + "dbus-send", |
| 103 | + "--session", |
| 104 | + "--print-reply", |
| 105 | + "--reply-timeout=" + TIMEOUT_THRESHOLD, |
| 106 | + "--dest=org.freedesktop.FileManager1", |
| 107 | + "--type=method_call", |
| 108 | + "/org/freedesktop/FileManager1", |
| 109 | + "org.freedesktop.DBus.Introspectable.Introspect" |
| 110 | + ); |
| 111 | + } |
79 | 112 | }
|
0 commit comments