diff --git a/Cargo.lock b/Cargo.lock index a037b4e33..7fbab4ae5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -127,6 +133,17 @@ dependencies = [ "x11rb", ] +[[package]] +name = "async-broadcast" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61" +dependencies = [ + "event-listener", + "futures-core", + "parking_lot 0.12.1", +] + [[package]] name = "async-channel" version = "1.6.1" @@ -138,6 +155,20 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + [[package]] name = "async-io" version = "1.7.0" @@ -157,6 +188,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "async-lock" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +dependencies = [ + "event-listener", +] + [[package]] name = "async-process" version = "1.4.0" @@ -174,6 +214,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-task" version = "4.2.0" @@ -976,6 +1027,23 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "dark-light" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b83576e2eee2d9cdaa8d08812ae59cbfe1b5ac7ac5ac4b8400303c6148a88c1" +dependencies = [ + "dconf_rs", + "detect-desktop-environment", + "dirs", + "objc", + "rust-ini", + "web-sys", + "winreg 0.8.0", + "zbus", + "zvariant", +] + [[package]] name = "darling" version = "0.13.4" @@ -1141,6 +1209,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "dconf_rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" + [[package]] name = "default-net" version = "0.11.0" @@ -1163,6 +1237,23 @@ dependencies = [ "byteorder", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "detect-desktop-environment" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810" + [[package]] name = "digest" version = "0.10.3" @@ -1183,6 +1274,15 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -1193,6 +1293,17 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1219,6 +1330,15 @@ dependencies = [ "libloading", ] +[[package]] +name = "dlv-list" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "docopt" version = "1.1.1" @@ -1295,6 +1415,27 @@ dependencies = [ "syn", ] +[[package]] +name = "enumflags2" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" +dependencies = [ + "enumflags2_derive", + "serde 1.0.137", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -1332,6 +1473,27 @@ dependencies = [ "synstructure", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "error-code" version = "2.3.1" @@ -2093,6 +2255,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -2159,6 +2330,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hound" version = "3.4.0" @@ -2314,7 +2491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg 1.1.0", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -3124,6 +3301,26 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "ordered-multimap" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" +dependencies = [ + "dlv-list", + "hashbrown 0.9.1", +] + +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_str_bytes" version = "6.1.0" @@ -3924,6 +4121,16 @@ dependencies = [ "which 3.1.1", ] +[[package]] +name = "rust-ini" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" +dependencies = [ + "cfg-if 1.0.0", + "ordered-multimap", +] + [[package]] name = "rust-pulsectl" version = "0.2.12" @@ -3972,10 +4179,12 @@ dependencies = [ "core-graphics 0.22.3", "cpal", "ctrlc", + "dark-light", "dasp", "default-net", "dispatch", "enigo", + "errno", "evdev", "flexi_logger", "flutter_rust_bridge", @@ -4293,6 +4502,17 @@ dependencies = [ "serde 1.0.137", ] +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4339,6 +4559,21 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sha2" version = "0.10.2" @@ -4468,6 +4703,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.1.3" @@ -4978,6 +5219,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "uds_windows" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi 0.3.9", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -5592,6 +5843,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "winreg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winreg" version = "0.10.1" @@ -5695,6 +5955,70 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "zbus" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8f1a037b2c4a67d9654dc7bdfa8ff2e80555bbefdd3c1833c1d1b27c963a6b" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "dirs", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "lazy_static", + "nix 0.23.1", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde 1.0.137", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi 0.3.9", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8fb5186d1c87ae88cf234974c240671238b4a679158ad3b94ec465237349a6" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_names" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a408fd8a352695690f53906dc7fd036be924ec51ea5e05666ff42685ed0af5" +dependencies = [ + "serde 1.0.137", + "static_assertions", + "zvariant", +] + [[package]] name = "zstd" version = "0.9.2+zstd.1.5.1" @@ -5723,3 +6047,29 @@ dependencies = [ "cc", "libc", ] + +[[package]] +name = "zvariant" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd68e4e6432ef19df47d7e90e2e72b5e7e3d778e0ae3baddf12b951265cc758" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde 1.0.137", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e977eaa3af652f63d479ce50d924254ad76722a6289ec1a1eac3231ca30430" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index d65c9dde3..f48ea2efb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ bytes = { version = "1.2", features = ["serde"] } default-net = "0.11.0" wol-rs = "0.9.1" flutter_rust_bridge = { git = "https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge", optional = true } +errno = "0.2.8" [target.'cfg(not(target_os = "linux"))'.dependencies] reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features=false } @@ -97,6 +98,7 @@ core-foundation = "0.9" core-graphics = "0.22" include_dir = "0.7.2" tray-item = "0.7" # looks better than trayicon +dark-light = "0.2" [target.'cfg(target_os = "linux")'.dependencies] psimple = { package = "libpulse-simple-binding", version = "2.25" } @@ -140,7 +142,7 @@ identifier = "com.carriez.rustdesk" icon = ["32x32.png", "128x128.png", "128x128@2x.png"] deb_depends = ["libgtk-3-0", "libxcb-randr0", "libxdo3", "libxfixes3", "libxcb-shape0", "libxcb-xfixes0", "libasound2", "libsystemd0", "pulseaudio", "python3-pip", "curl"] osx_minimum_system_version = "10.14" -resources = ["mac-tray.png"] +resources = ["mac-tray-light.png","mac-tray-dark.png"] #https://github.com/johnthagen/min-sized-rust [profile.release] diff --git a/Dockerfile b/Dockerfile index c08563614..5d15ff723 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM debian WORKDIR / -RUN apt update -y && apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo +RUN apt update -y && apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev RUN git clone https://github.com/microsoft/vcpkg && cd vcpkg && git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics diff --git a/README-CS.md b/README-CS.md index f6fa2fbf0..4f2c0e80f 100644 --- a/README-CS.md +++ b/README-CS.md @@ -29,7 +29,8 @@ Níže jsou uvedeny servery zdarma k vašemu použití (údaje se mohou v čase | --------- | ------------- | ------------------ | | Soul | AWS lightsail | 1 VCPU / 0,5GB RAM | | Singapur | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Softwarové součásti, na kterých závisí diff --git a/README-DE.md b/README-DE.md index 4e9929997..eb468d569 100644 --- a/README-DE.md +++ b/README-DE.md @@ -28,6 +28,8 @@ Hier sind die Server, die du kostenlos nutzen kannst, es kann sein das sich dies | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | | Singapore | Vultr | 1 VCPU / 1GB RAM | | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Codext | 2 VCPU / 4GB RAM | +| Germany | Hetzner | 4 VCPU / 8GB RAM | ## Abhängigkeiten diff --git a/README-ES.md b/README-ES.md index 1aab59213..7ceed149a 100644 --- a/README-ES.md +++ b/README-ES.md @@ -28,6 +28,8 @@ A continuación se muestran los servidores que está utilizando de forma gratuit | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-FA.md b/README-FA.md index 818e62fa8..5fd3c0d03 100644 --- a/README-FA.md +++ b/README-FA.md @@ -32,6 +32,8 @@ | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## وابستگی ها diff --git a/README-FI.md b/README-FI.md index 5f38d2e42..2e4c99ba6 100644 --- a/README-FI.md +++ b/README-FI.md @@ -27,6 +27,8 @@ Alla on palvelimia, joita voit käyttää ilmaiseksi, ne saattavat muuttua ajan | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Riippuvuudet diff --git a/README-FR.md b/README-FR.md index 9a303e6e6..3e33cb322 100644 --- a/README-FR.md +++ b/README-FR.md @@ -26,6 +26,8 @@ Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut ch - Séoul, AWS lightsail, 1 VCPU/0.5G RAM - Singapour, Vultr, 1 VCPU/1G RAM - Dallas, Vultr, 1 VCPU/1G RAM +- Germany, Codext, 2 VCPU / 4GB RAM +- Germany, Hetzner, 4 VCPU / 8GB RAM ## Dépendances diff --git a/README-HU.md b/README-HU.md index 7055ed446..3960d8b40 100644 --- a/README-HU.md +++ b/README-HU.md @@ -35,6 +35,8 @@ Ezalatt az üzenet alatt találhatóak azok a publikus szerverek, amelyeket ingy | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-ID.md b/README-ID.md index 363d4263b..3ea9bc454 100644 --- a/README-ID.md +++ b/README-ID.md @@ -26,7 +26,9 @@ Di bawah ini adalah server yang bisa Anda gunakan secara gratis, dapat berubah s | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-IT.md b/README-IT.md index a3f36af55..a79c28153 100644 --- a/README-IT.md +++ b/README-IT.md @@ -26,7 +26,9 @@ Qui sotto trovate i server che possono essere usati gratuitamente, la lista potr | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dipendenze diff --git a/README-JP.md b/README-JP.md index fb55d0ced..c1722a90f 100644 --- a/README-JP.md +++ b/README-JP.md @@ -31,7 +31,9 @@ RustDeskは誰からの貢献も歓迎します。 貢献するには [`CONTRIBU | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## 依存関係 diff --git a/README-KR.md b/README-KR.md index 00564e298..c7cf423da 100644 --- a/README-KR.md +++ b/README-KR.md @@ -31,7 +31,9 @@ RustDesk는 모든 기여를 환영합니다. 기여하고자 한다면 [`CONTRI | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## 의존관계 diff --git a/README-ML.md b/README-ML.md index d2931a2c7..45496b129 100644 --- a/README-ML.md +++ b/README-ML.md @@ -26,7 +26,9 @@ | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## ഡിപെൻഡൻസികൾ diff --git a/README-NL.md b/README-NL.md index 5db299e7c..8a4a119fc 100644 --- a/README-NL.md +++ b/README-NL.md @@ -26,7 +26,9 @@ Onderstaande servers zijn de servers die je gratis kunt gebruiken, ze kunnen op | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Afhankelijkheden diff --git a/README-PL.md b/README-PL.md index 119af95cf..d3b298d5a 100644 --- a/README-PL.md +++ b/README-PL.md @@ -26,7 +26,9 @@ Poniżej znajdują się serwery, z których można korzystać za darmo, może si | --------- | ------------- | ------------------ | | Seul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapur | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Zależności diff --git a/README-PTBR.md b/README-PTBR.md index 955456256..020941831 100644 --- a/README-PTBR.md +++ b/README-PTBR.md @@ -28,6 +28,8 @@ Abaixo estão os servidores que você está utilizando de graça, ele pode mudar | Seul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapura | Vultr | 1 VCPU / 1GB RAM | | Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependências diff --git a/README-RU.md b/README-RU.md index a9d81152c..d610f2dc5 100644 --- a/README-RU.md +++ b/README-RU.md @@ -32,7 +32,9 @@ RustDesk приветствует вклад каждого. Смотрите [` | --------- | ------------- | ------------------ | | Сеул | AWS lightsail | 1 VCPU / 0.5GB RAM | | Сингапур | Vultr | 1 VCPU / 1GB RAM | -| Даллас | Vultr | 1 VCPU / 1GB RAM | | +| Даллас | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Зависимости diff --git a/README-VN.md b/README-VN.md index b39005a31..641b80ebd 100644 --- a/README-VN.md +++ b/README-VN.md @@ -35,7 +35,9 @@ Dưới đây là những máy chủ mà bạn có thể sử dụng mà không | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Dallas | Vultr | 1 VCPU / 1GB RAM | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/README-ZH.md b/README-ZH.md index 0c3e7d5c1..e17254670 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -27,6 +27,8 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https: - 首尔, AWS lightsail, 1 VCPU/0.5G RAM - 新加坡, Vultr, 1 VCPU/1G RAM - 达拉斯, Vultr, 1 VCPU/1G RAM +- Germany, Codext, 2 VCPU / 4GB RAM +- Germany, Hetzner, 4 VCPU / 8GB RAM ## 依赖 diff --git a/README.md b/README.md index 346600f61..79a4b18d3 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ Below are the servers you are using for free, it may change along the time. If y | --------- | ------------- | ------------------ | | Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | | Singapore | Vultr | 1 VCPU / 1GB RAM | -| Dallas | Vultr | 1 VCPU / 1GB RAM | | +| Germany | Hetzner | 2 VCPU / 4GB RAM | +| Germany | Codext | 4 VCPU / 8GB RAM | ## Dependencies diff --git a/appimage/AppImageBuilder.yml b/appimage/AppImageBuilder.yml index 0ca62e97c..08a4f0786 100644 --- a/appimage/AppImageBuilder.yml +++ b/appimage/AppImageBuilder.yml @@ -40,12 +40,12 @@ AppDir: - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates universe - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic multiverse - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates multiverse - - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted - universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security main restricted - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security universe - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security multiverse include: + - libc6:amd64 - libgcc1:amd64 - libgcrypt20:amd64 - libgtk-3-0:amd64 @@ -95,4 +95,4 @@ AppDir: command: ./AppRun AppImage: arch: x86_64 - update-information: guess \ No newline at end of file + update-information: guess diff --git a/flutter/lib/desktop/widgets/peercard_widget.dart b/flutter/lib/desktop/widgets/peercard_widget.dart index f76336cda..d39f3d359 100644 --- a/flutter/lib/desktop/widgets/peercard_widget.dart +++ b/flutter/lib/desktop/widgets/peercard_widget.dart @@ -359,6 +359,17 @@ class _PeerCardState extends State<_PeerCard> _rename(id); } else if (value == 'unremember-password') { await bind.mainForgetPassword(id: id); + } else if (value == 'force-always-relay') { + String value; + String oldValue = + await bind.mainGetPeerOption(id: id, key: 'force-always-relay'); + if (oldValue.isEmpty) { + value = 'Y'; + } else { + value = ''; + } + await bind.mainSetPeerOption( + id: id, key: 'force-always-relay', value: value); } } @@ -572,6 +583,7 @@ class RecentPeerCard extends BasePeerCard { child: Text(translate('Transfer File')), value: 'file'), PopupMenuItem( child: Text(translate('TCP Tunneling')), value: 'tcp-tunnel'), + await _forceAlwaysRelayMenuItem(peer.id), PopupMenuItem(child: Text(translate('Rename')), value: 'rename'), PopupMenuItem(child: Text(translate('Remove')), value: 'remove'), PopupMenuItem( @@ -595,6 +607,7 @@ class FavoritePeerCard extends BasePeerCard { child: Text(translate('Transfer File')), value: 'file'), PopupMenuItem( child: Text(translate('TCP Tunneling')), value: 'tcp-tunnel'), + await _forceAlwaysRelayMenuItem(peer.id), PopupMenuItem(child: Text(translate('Rename')), value: 'rename'), PopupMenuItem(child: Text(translate('Remove')), value: 'remove'), PopupMenuItem( @@ -618,6 +631,7 @@ class DiscoveredPeerCard extends BasePeerCard { child: Text(translate('Transfer File')), value: 'file'), PopupMenuItem( child: Text(translate('TCP Tunneling')), value: 'tcp-tunnel'), + await _forceAlwaysRelayMenuItem(peer.id), PopupMenuItem(child: Text(translate('Rename')), value: 'rename'), PopupMenuItem(child: Text(translate('Remove')), value: 'remove'), PopupMenuItem( @@ -641,6 +655,7 @@ class AddressBookPeerCard extends BasePeerCard { child: Text(translate('Transfer File')), value: 'file'), PopupMenuItem( child: Text(translate('TCP Tunneling')), value: 'tcp-tunnel'), + await _forceAlwaysRelayMenuItem(peer.id), PopupMenuItem(child: Text(translate('Rename')), value: 'rename'), PopupMenuItem( child: Text(translate('Remove')), value: 'ab-delete'), @@ -654,3 +669,20 @@ class AddressBookPeerCard extends BasePeerCard { ]; } } + +Future> _forceAlwaysRelayMenuItem(String id) async { + bool force_always_relay = + (await bind.mainGetPeerOption(id: id, key: 'force-always-relay')) + .isNotEmpty; + return PopupMenuItem( + child: Row( + children: [ + Offstage( + offstage: !force_always_relay, + child: Icon(Icons.check), + ), + Text(translate('Always connect via relay')), + ], + ), + value: 'force-always-relay'); +} diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index b8f1421e3..0aca2aab1 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -119,7 +119,7 @@ packages: name: built_value url: "https://pub.flutter-io.cn" source: hosted - version: "8.4.0" + version: "8.4.1" cached_network_image: dependency: transitive description: @@ -340,35 +340,35 @@ packages: name: file url: "https://pub.flutter-io.cn" source: hosted - version: "6.1.2" + version: "6.1.4" firebase_analytics: dependency: "direct main" description: name: firebase_analytics url: "https://pub.flutter-io.cn" source: hosted - version: "9.3.1" + version: "9.3.2" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface url: "https://pub.flutter-io.cn" source: hosted - version: "3.3.1" + version: "3.3.2" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.2+1" + version: "0.4.2+2" firebase_core: dependency: transitive description: name: firebase_core url: "https://pub.flutter-io.cn" source: hosted - version: "1.20.1" + version: "1.21.0" firebase_core_platform_interface: dependency: transitive description: @@ -819,7 +819,7 @@ packages: name: pubspec_parse url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "1.2.1" qr_code_scanner: dependency: "direct main" description: @@ -1134,14 +1134,14 @@ packages: name: video_player url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.6" + version: "2.4.7" video_player_android: dependency: transitive description: name: video_player_android url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.8" + version: "2.3.9" video_player_avfoundation: dependency: transitive description: @@ -1234,7 +1234,7 @@ packages: resolved-ref: "799ef079e87938c3f4340591b4330c2598f38bb9" url: "https://github.com/Kingtous/rustdesk_window_manager" source: git - version: "0.2.5" + version: "0.2.6" xdg_directories: dependency: transitive description: diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 33c46e7ae..9354b4079 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -23,6 +23,7 @@ use crate::{ pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; pub const CONNECT_TIMEOUT: u64 = 18_000; +pub const READ_TIMEOUT: u64 = 30_000; pub const REG_INTERVAL: i64 = 12_000; pub const COMPRESS_LEVEL: i32 = 3; const SERIAL: i32 = 3; @@ -294,8 +295,37 @@ impl Config { fn load() -> Config { let mut config = Config::load_::(""); - let (password, _, store) = decrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION); + let mut store = false; + let (password, _, store1) = decrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION); config.password = password; + store |= store1; + let mut id_valid = false; + let (id, encrypted, store2) = decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION); + if encrypted { + config.id = id; + id_valid = true; + store |= store2; + } else { + if crate::get_modified_time(&Self::file_("")) + .checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation + .unwrap_or(crate::get_exe_time()) + < crate::get_exe_time() + { + id_valid = true; + store = true; + } + } + if !id_valid { + for _ in 0..3 { + if let Some(id) = Config::get_auto_id() { + config.id = id; + store = true; + break; + } else { + log::error!("Failed to generate new id"); + } + } + } if store { config.store(); } @@ -305,6 +335,7 @@ impl Config { fn store(&self) { let mut config = self.clone(); config.password = encrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION); + config.id = encrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION); Config::store_(&config, ""); } diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 2fdd74cd5..48fbfe23c 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -202,6 +202,24 @@ pub fn get_modified_time(path: &std::path::Path) -> SystemTime { .unwrap_or(UNIX_EPOCH) } +pub fn get_created_time(path: &std::path::Path) -> SystemTime { + std::fs::metadata(&path) + .map(|m| m.created().unwrap_or(UNIX_EPOCH)) + .unwrap_or(UNIX_EPOCH) +} + +pub fn get_exe_time() -> SystemTime { + std::env::current_exe().map_or(UNIX_EPOCH, |path| { + let m = get_modified_time(&path); + let c = get_created_time(&path); + if m > c { + m + } else { + c + } + }) +} + pub fn get_uuid() -> Vec { #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Ok(id) = machine_uid::get() { diff --git a/libs/hbb_common/src/password_security.rs b/libs/hbb_common/src/password_security.rs index ba57c11c4..55a6825fa 100644 --- a/libs/hbb_common/src/password_security.rs +++ b/libs/hbb_common/src/password_security.rs @@ -108,7 +108,7 @@ pub fn encrypt_vec_or_original(v: &[u8], version: &str) -> Vec { v.to_owned() } -// String: password +// Vec: password // bool: whether decryption is successful // bool: whether should store to re-encrypt when load pub fn decrypt_vec_or_original(v: &[u8], current_version: &str) -> (Vec, bool, bool) { diff --git a/mac-tray.png b/mac-tray-dark.png similarity index 100% rename from mac-tray.png rename to mac-tray-dark.png diff --git a/mac-tray-light.png b/mac-tray-light.png new file mode 100644 index 000000000..c3e107410 Binary files /dev/null and b/mac-tray-light.png differ diff --git a/rustdesk.desktop b/rustdesk.desktop index 11c7daad0..c9cf1f254 100644 --- a/rustdesk.desktop +++ b/rustdesk.desktop @@ -8,7 +8,7 @@ Icon=/usr/share/rustdesk/files/rustdesk.png Terminal=false Type=Application StartupNotify=true -Categories=Other; +Categories=Network;RemoteAccess;GTK; Keywords=internet; Actions=new-window; diff --git a/src/client.rs b/src/client.rs index 3c1e5c3c3..d7f0bf4fa 100644 --- a/src/client.rs +++ b/src/client.rs @@ -20,7 +20,10 @@ use hbb_common::{ allow_err, anyhow::{anyhow, Context}, bail, - config::{Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, RELAY_PORT, RENDEZVOUS_TIMEOUT}, + config::{ + Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT, + RENDEZVOUS_TIMEOUT, + }, log, message_proto::{option_message::BoolOption, *}, protobuf::Message as _, @@ -121,8 +124,9 @@ impl Client { key: &str, token: &str, conn_type: ConnType, + interface: impl Interface, ) -> ResultType<(Stream, bool)> { - match Self::_start(peer, key, token, conn_type).await { + match Self::_start(peer, key, token, conn_type, interface).await { Err(err) => { let err_str = err.to_string(); if err_str.starts_with("Failed") { @@ -141,6 +145,7 @@ impl Client { key: &str, token: &str, conn_type: ConnType, + interface: impl Interface, ) -> ResultType<(Stream, bool)> { // to-do: remember the port for each peer, so that we can retry easier let any_addr = Config::get_any_listen_addr(); @@ -187,7 +192,11 @@ impl Client { log::info!("#{} punch attempt with {}, id: {}", i, my_addr, peer); let mut msg_out = RendezvousMessage::new(); use hbb_common::protobuf::Enum; - let nat_type = NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT); + let nat_type = if interface.is_force_relay() { + NatType::SYMMETRIC + } else { + NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT) + }; msg_out.set_punch_hole_request(PunchHoleRequest { id: peer.to_owned(), token: token.to_owned(), @@ -239,7 +248,15 @@ impl Client { let mut conn = Self::create_relay(peer, rr.uuid, rr.relay_server, key, conn_type) .await?; - Self::secure_connection(peer, signed_id_pk, key, &mut conn).await?; + Self::secure_connection( + peer, + signed_id_pk, + key, + &mut conn, + false, + interface, + ) + .await?; return Ok((conn, false)); } _ => { @@ -280,6 +297,7 @@ impl Client { key, token, conn_type, + interface, ) .await } @@ -299,6 +317,7 @@ impl Client { key: &str, token: &str, conn_type: ConnType, + interface: impl Interface, ) -> ResultType<(Stream, bool)> { let direct_failures = PeerConfig::load(peer_id).direct_failures; let mut connect_timeout = 0; @@ -336,8 +355,8 @@ impl Client { let start = std::time::Instant::now(); // NOTICE: Socks5 is be used event in intranet. Which may be not a good way. let mut conn = socket_client::connect_tcp(peer, local_addr, connect_timeout).await; - let direct = !conn.is_err(); - if conn.is_err() { + let mut direct = !conn.is_err(); + if interface.is_force_relay() || conn.is_err() { if !relay_server.is_empty() { conn = Self::request_relay( peer_id, @@ -355,6 +374,7 @@ impl Client { conn.err().unwrap() ); } + direct = false; } else { bail!("Failed to make direct connection to remote desktop"); } @@ -367,7 +387,7 @@ impl Client { } let mut conn = conn?; log::info!("{:?} used to establish connection", start.elapsed()); - Self::secure_connection(peer_id, signed_id_pk, key, &mut conn).await?; + Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface).await?; Ok((conn, direct)) } @@ -377,6 +397,8 @@ impl Client { signed_id_pk: Vec, key: &str, conn: &mut Stream, + direct: bool, + mut interface: impl Interface, ) -> ResultType<()> { let rs_pk = get_rs_pk(if key.is_empty() { hbb_common::config::RS_PUB_KEY @@ -402,9 +424,15 @@ impl Client { return Ok(()); } }; - match timeout(CONNECT_TIMEOUT, conn.next()).await? { + match timeout(READ_TIMEOUT, conn.next()).await? { Some(res) => { - let bytes = res?; + let bytes = match res { + Ok(bytes) => bytes, + Err(err) => { + interface.set_force_relay(direct, false); + bail!("{}", err); + } + }; if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { if let Some(message::Union::SignedId(si)) = msg_in.union { if let Ok((id, their_pk_b)) = decode_id_pk(&si.id, &sign_pk) { @@ -831,6 +859,7 @@ pub struct LoginConfigHandler { session_id: u64, pub supported_encoding: Option<(bool, bool)>, pub restarting_remote_device: bool, + pub force_relay: bool, } impl Deref for LoginConfigHandler { @@ -869,6 +898,7 @@ impl LoginConfigHandler { self.session_id = rand::random(); self.supported_encoding = None; self.restarting_remote_device = false; + self.force_relay = !self.get_option("force-always-relay").is_empty(); } /// Check if the client should auto login. @@ -1620,6 +1650,8 @@ pub trait Interface: Send + Clone + 'static + Sized { fn msgbox(&self, msgtype: &str, title: &str, text: &str); fn handle_login_error(&mut self, err: &str) -> bool; fn handle_peer_info(&mut self, pi: PeerInfo); + fn set_force_relay(&mut self, direct: bool, received: bool); + fn is_force_relay(&self) -> bool; async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream); async fn handle_login_from_ui(&mut self, password: String, remember: bool, peer: &mut Stream); async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream); @@ -1790,14 +1822,16 @@ lazy_static::lazy_static! { pub fn check_if_retry(msgtype: &str, title: &str, text: &str) -> bool { msgtype == "error" && title == "Connection Error" - && !text.to_lowercase().contains("offline") - && !text.to_lowercase().contains("exist") - && !text.to_lowercase().contains("handshake") - && !text.to_lowercase().contains("failed") - && !text.to_lowercase().contains("resolve") - && !text.to_lowercase().contains("mismatch") - && !text.to_lowercase().contains("manually") - && !text.to_lowercase().contains("not allowed") + && (text.contains("10054") + || text.contains("104") + || (!text.to_lowercase().contains("offline") + && !text.to_lowercase().contains("exist") + && !text.to_lowercase().contains("handshake") + && !text.to_lowercase().contains("failed") + && !text.to_lowercase().contains("resolve") + && !text.to_lowercase().contains("mismatch") + && !text.to_lowercase().contains("manually") + && !text.to_lowercase().contains("not allowed"))) } #[inline] diff --git a/src/flutter.rs b/src/flutter.rs index 3af096494..ca00807f1 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -618,6 +618,24 @@ impl Interface for Session { } } + fn set_force_relay(&mut self, direct: bool, received: bool) { + let mut lc = self.lc.write().unwrap(); + lc.force_relay = false; + if direct && !received { + let errno = errno::errno().0; + log::info!("errno is {}", errno); + // TODO: check mac and ios + if cfg!(windows) && errno == 10054 || !cfg!(windows) && errno == 104 { + lc.force_relay = true; + lc.set_option("force-always-relay".to_owned(), "Y".to_owned()); + } + } + } + + fn is_force_relay(&self) -> bool { + self.lc.read().unwrap().force_relay + } + async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream) { handle_hash(self.lc.clone(), pass, hash, self, peer).await; } @@ -735,7 +753,7 @@ impl Connection { let key = Config::get_option("key"); let token = Config::get_option("access_token"); - match Client::start(&session.id, &key, &token, conn_type).await { + match Client::start(&session.id, &key, &token, conn_type, session.clone()).await { Ok((mut peer, direct)) => { SERVER_KEYBOARD_ENABLED.store(true, Ordering::SeqCst); SERVER_CLIPBOARD_ENABLED.store(true, Ordering::SeqCst); diff --git a/src/lang.rs b/src/lang.rs index 400c4dd95..7157f9b42 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -13,6 +13,7 @@ mod hu; mod id; mod it; mod ja; +mod ko; mod pl; mod ptbr; mod ru; @@ -43,6 +44,7 @@ lazy_static::lazy_static! { ("vn", "Tiếng Việt"), ("pl", "Polski"), ("ja", "日本語"), + ("ko", "한국어"), ]); } @@ -90,6 +92,7 @@ pub fn translate_locale(name: String, locale: &str) -> String { "vn" => vn::T.deref(), "pl" => pl::T.deref(), "ja" => ja::T.deref(), + "ko" => ko::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { diff --git a/src/lang/it.rs b/src/lang/it.rs index f4e2d0bce..c8ad93476 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -35,9 +35,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("About", "Informazioni"), ("Mute", "Silenzia"), ("Audio Input", "Input audio"), - ("Enhancements", ""), - ("Hardware Codec", ""), - ("Adaptive Bitrate", ""), + ("Enhancements", "Miglioramenti"), + ("Hardware Codec", "Codifica Hardware"), + ("Adaptive Bitrate", "Bitrate Adattivo"), ("ID Server", "ID server"), ("Relay Server", "Server relay"), ("API Server", "Server API"), @@ -53,10 +53,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Close", "Chiudi"), ("Retry", "Riprova"), ("OK", "OK"), - ("Password Required", "Password richiesta"), + ("Password Required", "Password Richiesta"), ("Please enter your password", "Inserisci la tua password"), ("Remember password", "Ricorda password"), - ("Wrong Password", "Password errata"), + ("Wrong Password", "Password Errata"), ("Do you want to enter again?", "Vuoi riprovare?"), ("Connection Error", "Errore di connessione"), ("Error", "Errore"), @@ -64,7 +64,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Connecting...", "Connessione..."), ("Connection in progress. Please wait.", "Connessione in corso. Attendi."), ("Please try 1 minute later", "Per favore riprova fra 1 minuto"), - ("Login Error", "Errore di login"), + ("Login Error", "Errore Login"), ("Successful", "Successo"), ("Connected, waiting for image...", "Connesso, in attesa dell'immagine..."), ("Name", "Nome"), @@ -222,7 +222,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Discovered", "Rilevati"), ("install_daemon_tip", "Per avviarsi all'accensione, è necessario installare il servizio di sistema."), ("Remote ID", "ID remoto"), - ("Paste", "Impasto"), + ("Paste", "Incolla"), ("Paste here?", "Incolla qui?"), ("Are you sure to close the connection?", "Sei sicuro di voler chiudere la connessione?"), ("Download new version", "Scarica nuova versione"), @@ -241,8 +241,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Two-Finger Move", "Movimento con due dita"), ("Canvas Move", "Sposta tela"), ("Pinch to Zoom", "Pizzica per zoomare"), - ("Canvas Zoom", "Zoom tela"), - ("Reset canvas", "Ripristina tela"), + ("Canvas Zoom", "Zoom canvas"), + ("Reset canvas", "Ripristina canvas"), ("No permission of file transfer", "Nessun permesso di trasferimento di file"), ("Note", "Nota"), ("Connection", "Connessione"), @@ -278,7 +278,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Succeeded", "Successo"), ("Someone turns on privacy mode, exit", "Qualcuno attiva la modalità privacy, esci"), ("Unsupported", "Non supportato"), - ("Peer denied", "Pari negato"), + ("Peer denied", "Peer negato"), ("Please install plugins", "Si prega di installare i plugin"), ("Peer exit", "Uscita tra pari"), ("Failed to turn off", "Impossibile spegnere"), @@ -289,18 +289,17 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Keep RustDesk background service", ""), ("Ignore Battery Optimizations", ""), ("android_open_battery_optimizations_tip", ""), - ("Connection not allowed", ""), - ("Use temporary password", ""), - ("Use permanent password", ""), - ("Use both passwords", ""), - ("Set permanent password", ""), - ("Set temporary password length", ""), - ("Enable Remote Restart", ""), - ("Allow remote restart", ""), - ("Restart Remote Device", ""), - ("Are you sure you want to restart", ""), - ("Restarting Remote Device", ""), - ("remote_restarting_tip", ""), - ("Copied", ""), + ("Connection not allowed", "Connessione non consentita"), + ("Use temporary password", "Usa password temporanea"), + ("Use permanent password", "Usa password permanente"), + ("Use both passwords", "Usa entrambe le password"), + ("Set permanent password", "Imposta password permanente"), + ("Set temporary password length", "Imposta lunghezza passwod temporanea"), + ("Enable Remote Restart", "Abilita riavvio da remoto"), + ("Allow remote restart", "Consenti riavvio da remoto"), + ("Restart Remote Device", "Riavvia dispositivo remoto"), + ("Are you sure you want to restart", "Sei sicuro di voler riavviare?"), + ("Restarting Remote Device", "Il dispositivo remoto si sta riavviando"), + ("remote_restarting_tip", "Riavviare il dispositivo remoto"), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index f4c991690..5c6ba1da7 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -103,8 +103,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "オリジナル"), ("Shrink", "縮小"), ("Stretch", "伸縮"), - ("Scrollbar", "スクロール・バー"), - ("ScrollAuto", "自動スクロール"), ("Good image quality", "画質優先"), ("Balanced", "バランス"), ("Optimize reaction time", "速度優先"), diff --git a/src/lang/ko.rs b/src/lang/ko.rs new file mode 100644 index 000000000..a0292adcb --- /dev/null +++ b/src/lang/ko.rs @@ -0,0 +1,303 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "상태"), + ("Your Desktop", "당신의 데스크탑"), + ("desk_tip", "아래 ID와 비밀번호를 통해 당신의 데스크탑으로 접속할 수 있습니다."), + ("Password", "비밀번호"), + ("Ready", "준비"), + ("Established", "연결됨"), + ("connecting_status", "RustDesk 네트워크로 연결중입니다..."), + ("Enable Service", "서비스 활성화"), + ("Start Service", "서비스 시작"), + ("Service is running", "서비스 동작중"), + ("Service is not running", "서비스가 동작하고 있지 않습니다"), + ("not_ready_status", "준비되지 않음. 연결을 확인해주시길 바랍니다."), + ("Control Remote Desktop", "원격 데스크탑 제어"), + ("Transfer File", "파일 전송"), + ("Connect", "접속하기"), + ("Recent Sessions", "최근 세션"), + ("Address Book", "세션 주소록"), + ("Confirmation", "확인"), + ("TCP Tunneling", "TCP 터널링"), + ("Remove", "삭제"), + ("Refresh random password", "랜덤 비밀번호 새로고침"), + ("Set your own password", "개인 비밀번호 설정"), + ("Enable Keyboard/Mouse", "키보드/마우스 활성화"), + ("Enable Clipboard", "클립보드 활성화"), + ("Enable File Transfer", "파일 전송 활성화"), + ("Enable TCP Tunneling", "TCP 터널링 활성화"), + ("IP Whitelisting", "IP 화이트리스트"), + ("ID/Relay Server", "ID/Relay 서버"), + ("Stop service", "서비스 중단"), + ("Change ID", "ID 변경"), + ("Website", "웹사이트"), + ("About", "정보"), + ("Mute", "음소거"), + ("Audio Input", "오디오 입력"), + ("Enhancements", ""), + ("Hardware Codec", "하드웨어 코덱"), + ("Adaptive Bitrate", "가변 비트레이트"), + ("ID Server", "ID 서버"), + ("Relay Server", "Relay 서버"), + ("API Server", "API 서버"), + ("invalid_http", "다음과 같이 시작해야 합니다. http:// 또는 https://"), + ("Invalid IP", "유효하지 않은 IP"), + ("id_change_tip", "a-z, A-Z, 0-9, _(밑줄 문자)만 입력 가능합니다. 첫 문자는 a-z 혹은 A-Z로 시작해야 합니다. 길이는 6 ~ 16글자가 요구됩니다."), + ("Invalid format", "유효하지 않은 형식"), + ("server_not_support", "해당 서버가 아직 지원하지 않습니다"), + ("Not available", "불가능"), + ("Too frequent", "너무 잦은 시도"), + ("Cancel", "취소"), + ("Skip", "넘기기"), + ("Close", "닫기"), + ("Retry", "재시도"), + ("OK", "확인"), + ("Password Required", "비밀번호 입력"), + ("Please enter your password", "비밀번호를 입력해주세요"), + ("Remember password", "이 비밀번호 기억하기"), + ("Wrong Password", "틀린 비밀번호"), + ("Do you want to enter again?", "다시 접속하시겠습니까?"), + ("Connection Error", "연결 에러"), + ("Error", "에러"), + ("Reset by the peer", "다른 접속자에 의해 초기화됨"), + ("Connecting...", "연결중..."), + ("Connection in progress. Please wait.", "연결중입니다. 잠시만 기다려주세요."), + ("Please try 1 minute later", "1분 뒤 다시 시도해주세요"), + ("Login Error", "로그인 에러"), + ("Successful", "성공"), + ("Connected, waiting for image...", "연결됨. 이미지를 기다리는중..."), + ("Name", "이름"), + ("Type", "유형"), + ("Modified", "수정됨"), + ("Size", "크기"), + ("Show Hidden Files", "숨김 파일 보기"), + ("Receive", "받기"), + ("Send", "보내기"), + ("Refresh File", "파일 새로고침"), + ("Local", "로컬"), + ("Remote", "원격"), + ("Remote Computer", "원격 컴퓨터"), + ("Local Computer", "로컬 컴퓨터"), + ("Confirm Delete", "삭제 재확인"), + ("Delete", "삭제"), + ("Properties", "속성"), + ("Multi Select", "다중 선택"), + ("Empty Directory", "빈 디렉터리"), + ("Not an empty directory", "디렉터리가 비어있지 않습니다"), + ("Are you sure you want to delete this file?", "정말로 해당 파일을 삭제하시겠습니까?"), + ("Are you sure you want to delete this empty directory?", "정말로 비어있는 해당 디렉터리를 삭제하시겠습니까?"), + ("Are you sure you want to delete the file of this directory?", "정말로 해당 파일 혹은 디렉터리를 삭제하시겠습니까?"), + ("Do this for all conflicts", "모든 충돌에 대해 해당 작업 수행"), + ("This is irreversible!", "해당 결정은 돌이킬 수 없습니다!"), + ("Deleting", "삭제중"), + ("files", "파일"), + ("Waiting", "대기중"), + ("Finished", "완료됨"), + ("Speed", "속도"), + ("Custom Image Quality", "이미지 품질 조정"), + ("Privacy mode", "개인정보 보호 모드"), + ("Block user input", "사용자 입력 차단"), + ("Unblock user input", "사용자 입력 차단 해제"), + ("Adjust Window", "화면 조정"), + ("Original", "원본"), + ("Shrink", "축소"), + ("Stretch", "확대"), + ("Good image quality", "최적 이미지 품질"), + ("Balanced", "균형"), + ("Optimize reaction time", "반응 시간 최적화"), + ("Custom", "커스텀"), + ("Show remote cursor", "원격 커서 보이기"), + ("Show quality monitor", "품질 모니터 띄우기"), + ("Disable clipboard", "클립보드 비활성화"), + ("Lock after session end", "세션 종료 후 화면 잠금"), + ("Insert", "입력"), + ("Insert Lock", "입력 잠금"), + ("Refresh", "새로고침"), + ("ID does not exist", "ID가 존재하지 않습니다"), + ("Failed to connect to rendezvous server", "rendezvous 서버에 접속을 실패하였습니다"), + ("Please try later", "다시 시도해주세요"), + ("Remote desktop is offline", "원격 데스크탑이 연결되어 있지 않습니다"), + ("Key mismatch", "키가 일치하지 않습니다."), + ("Timeout", "시간 초과"), + ("Failed to connect to relay server", "relay 서버에 접속을 실패하였습니다"), + ("Failed to connect via rendezvous server", "rendezvous 서버를 통한 접속에 실패하였습니다"), + ("Failed to connect via relay server", "relay 서버를 통한 접속에 실패하였습니다"), + ("Failed to make direct connection to remote desktop", "원격 데스크탑으로의 직접 연결 생성에 실패하였습니다"), + ("Set Password", "비밀번호 설정"), + ("OS Password", "OS 비밀번호"), + ("install_tip", "UAC로 인해, RustDesk가 원격지일 때 일부 기능이 동작하지 않을 수 있습니다. UAC 문제를 방지하려면, 아래 버튼을 클릭하여 RustDesk를 시스템에 설치해주세요."), + ("Click to upgrade", "클릭하여 업그레이드"), + ("Click to download", "클릭하여 다운로드"), + ("Click to update", "클릭하여 업데이트"), + ("Configure", "구성"), + ("config_acc", "당신의 데스크탑을 원격으로 제어하기 전에, RustDesk에게 \"Accessibility (접근성)\" 권한을 부여해야 합니다."), + ("config_screen", "당신의 데스크탑을 원격으로 제어하기 전에, RustDesk에게 \"Screen Recording (화면 녹화)\" 권한을 부여해야 합니다."), + ("Installing ...", "설치중 ..."), + ("Install", "설치하기"), + ("Installation", "설치"), + ("Installation Path", "설치 경로"), + ("Create start menu shortcuts", "시작 메뉴에 바로가기 생성"), + ("Create desktop icon", "데스크탑 아이콘 생성"), + ("agreement_tip", "설치를 시작하기 전에, 라이선스 약관에 동의를 해야합니다."), + ("Accept and Install", "동의 및 설치"), + ("End-user license agreement", "최종 사용자 라이선스 약관 동의"), + ("Generating ...", "생성중 ..."), + ("Your installation is lower version.", "설치 버전이 최신 버전이 아닙니다."), + ("not_close_tcp_tip", "연결을 사용하는 동안 이 창을 끄지 마세요"), + ("Listening ...", "연결 대기중 ..."), + ("Remote Host", "원격 호스트"), + ("Remote Port", "원격 포트"), + ("Action", "액션"), + ("Add", "추가"), + ("Local Port", "로컬 포트"), + ("setup_server_tip", "빠른 접속을 위해, 당신의 서버를 설정하세요"), + ("Too short, at least 6 characters.", "너무 짧습니다, 최소 6글자 이상 입력해주세요."), + ("The confirmation is not identical.", "확인용 입력이 일치하지 않습니다."), + ("Permissions", "권한"), + ("Accept", "수락"), + ("Dismiss", "거부"), + ("Disconnect", "연결 종료"), + ("Allow using keyboard and mouse", "키보드와 마우스 허용"), + ("Allow using clipboard", "클립보드 허용"), + ("Allow hearing sound", "소리 듣기 허용"), + ("Allow file copy and paste", "파일 복사 및 붙여넣기 허용"), + ("Connected", "연결됨"), + ("Direct and encrypted connection", "암호화된 직접 연결"), + ("Relayed and encrypted connection", "암호화된 릴레이 연결"), + ("Direct and unencrypted connection", "암호화되지 않은 직접 연결"), + ("Relayed and unencrypted connection", "암호화되지 않은 릴레이 연결"), + ("Enter Remote ID", "원격지 ID를 입력하세요"), + ("Enter your password", "비밀번호를 입력하세요"), + ("Logging in...", "로그인 중..."), + ("Enable RDP session sharing", "RDP 세션 공유를 활성화하세요"), + ("Auto Login", "자동 로그인"), + ("Enable Direct IP Access", "IP 직접 접근 활성화하세요"), + ("Rename", "이름 변경"), + ("Space", "공간"), + ("Create Desktop Shortcut", "데스크탑 바로가기 생성"), + ("Change Path", "경로 변경"), + ("Create Folder", "폴더 생성"), + ("Please enter the folder name", "폴더명을 입력해주세요"), + ("Fix it", "문제 해결"), + ("Warning", "경고"), + ("Login screen using Wayland is not supported", "Wayland를 사용한 로그인 화면이 지원되지 않습니다"), + ("Reboot required", "재부팅이 필요합니다"), + ("Unsupported display server ", "지원하지 않는 디스플레이 서버"), + ("x11 expected", "x11 예상됨"), + ("Port", "포트"), + ("Settings", "설정"), + ("Username", "사용자명"), + ("Invalid port", "유효하지 않은 포트"), + ("Closed manually by the peer", "다른 사용자에 의해 종료됨"), + ("Enable remote configuration modification", "원격 구성 변경 활성화"), + ("Run without install", "설치 없이 실행"), + ("Always connected via relay", "항상 relay를 통해 접속됨"), + ("Always connect via relay", "항상 relay를 통해 접속하기"), + ("whitelist_tip", "화이트리스트에 있는 IP만 현 데스크탑에 접속 가능합니다"), + ("Login", "로그인"), + ("Logout", "로그아웃"), + ("Tags", "태그"), + ("Search ID", "ID 검색"), + ("Current Wayland display server is not supported", "현재 Wayland 디스플레이 서버가 지원되지 않습니다"), + ("whitelist_sep", "다음 글자로 구분합니다. ',(콤마) ;(세미콜론) 띄어쓰기 혹은 줄바꿈'"), + ("Add ID", "ID 추가"), + ("Add Tag", "태그 추가"), + ("Unselect all tags", "모든 태그 선택 해제"), + ("Network error", "네트워크 에러"), + ("Username missed", "사용자명 누락"), + ("Password missed", "비밀번호 누락"), + ("Wrong credentials", "틀린 인증 정보"), + ("Edit Tag", "태그 수정"), + ("Unremember Password", "패스워드 기억하지 않기"), + ("Favorites", "즐겨찾기"), + ("Add to Favorites", "즐겨찾기에 추가"), + ("Remove from Favorites", "즐겨찾기에서 삭제"), + ("Empty", "비어 있음"), + ("Invalid folder name", "유효하지 않은 폴더명"), + ("Socks5 Proxy", "Socks5 프록시"), + ("Hostname", "호스트명"), + ("Discovered", "찾음"), + ("install_daemon_tip", "부팅된 이후 시스템 서비스에 설치해야 합니다."), + ("Remote ID", "원격지 ID"), + ("Paste", "붙여넣기"), + ("Paste here?", "여기에 붙여넣겠습니까?"), + ("Are you sure to close the connection?", "정말로 연결을 종료하시겠습니까?"), + ("Download new version", "최신 버전 다운로드"), + ("Touch mode", "터치 모드"), + ("Mouse mode", "마우스 모드"), + ("One-Finger Tap", "한 손가락 탭"), + ("Left Mouse", "왼쪽 마우스"), + ("One-Long Tap", "길게 누르기"), + ("Two-Finger Tap", "두 손가락 탭"), + ("Right Mouse", "오른쪽 마우스"), + ("One-Finger Move", "한 손가락 이동"), + ("Double Tap & Move", "두 번 탭 하고 이동"), + ("Mouse Drag", "마우스 드래그"), + ("Three-Finger vertically", "세 손가락 세로로"), + ("Mouse Wheel", "마우스 휠"), + ("Two-Finger Move", "두 손가락 이동"), + ("Canvas Move", "캔버스 이동"), + ("Pinch to Zoom", "확대/축소"), + ("Canvas Zoom", "캔버스 확대"), + ("Reset canvas", "캔버스 초기화"), + ("No permission of file transfer", "파일 전송 권한이 없습니다"), + ("Note", "노트"), + ("Connection", "연결"), + ("Share Screen", "화면 공유"), + ("CLOSE", "종료"), + ("OPEN", "열기"), + ("Chat", "채팅"), + ("Total", "총합"), + ("items", "개체"), + ("Selected", "선택됨"), + ("Screen Capture", "화면 캡처"), + ("Input Control", "입력 제어"), + ("Audio Capture", "오디오 캡처"), + ("File Connection", "파일 전송"), + ("Screen Connection", "화면 전송"), + ("Do you accept?", "동의하십니까?"), + ("Open System Setting", "시스템 설정 열기"), + ("How to get Android input permission?", "안드로이드 입력 권한에 어떻게 접근합니까?"), + ("android_input_permission_tip1", "원격지로서 마우스나 터치를 통해 Android 장치를 제어하려면 RustDesk에서 \"Accessibility (접근성)\" 서비스 사용을 허용해야 합니다."), + ("android_input_permission_tip2", "시스템 설정 페이지로 이동하여 [설치된 서비스]에서 [RustDesk Input] 서비스를 켜십시오."), + ("android_new_connection_tip", "현재 장치의 새로운 제어 요청이 수신되었습니다."), + ("android_service_will_start_tip", "\"화면 캡처\"를 켜면 서비스가 자동으로 시작되어 다른 장치에서 사용자 장치에 대한 연결을 요청할 수 있습니다."), + ("android_stop_service_tip", "서비스를 종료하면 모든 연결이 자동으로 닫힙니다."), + ("android_version_audio_tip", "현재 Android 버전은 오디오 캡처를 지원하지 않습니다. Android 10 이상으로 업그레이드하십시오."), + ("android_start_service_tip", "[서비스 시작] 또는 [화면 캡처] 권한을 눌러 화면 공유 서비스를 시작합니다."), + ("Account", "계정"), + ("Overwrite", "덮어쓰기"), + ("This file exists, skip or overwrite this file?", "해당 파일이 이미 존재합니다, 넘어가거나 덮어쓰시겠습니까?"), + ("Quit", "종료"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), + ("Help", "지원"), + ("Failed", "실패"), + ("Succeeded", "성공"), + ("Someone turns on privacy mode, exit", "누군가가 개인정보 보호 모드를 활성화하여 종료됩니다"), + ("Unsupported", "지원되지 않음"), + ("Peer denied", "다른 사용자에 의해 거부됨"), + ("Please install plugins", "플러그인을 설치해주세요"), + ("Peer exit", "다른 사용자가 나감"), + ("Failed to turn off", "종료에 실패함"), + ("Turned off", "종료됨"), + ("In privacy mode", "개인정보 보호 모드 진입"), + ("Out privacy mode", "개인정보 보호 모드 나감"), + ("Language", "언어"), + ("Keep RustDesk background service", "RustDesk 백그라운드 서비스로 유지하기"), + ("Ignore Battery Optimizations", "배터리 최적화 무시하기"), + ("android_open_battery_optimizations_tip", "해당 기능을 비활성화하려면 RustDesk 응용 프로그램 설정 페이지로 이동하여 [배터리]에서 [제한 없음] 선택을 해제하십시오."), + ("Connection not allowed", "연결이 허용되지 않음"), + ("Use temporary password", "임시 비밀번호 사용"), + ("Use permanent password", "영구 비밀번호 사용"), + ("Use both passwords", "두 비밀번호 (임시/영구) 사용"), + ("Set permanent password", "영구 비밀번호 설정"), + ("Set temporary password length", "임시 비밀번호 길이 설정"), + ("Enable Remote Restart", "원격지 재시작 활성화"), + ("Allow remote restart", "원격지 재시작 허용"), + ("Restart Remote Device", "원격 기기 재시작"), + ("Are you sure you want to restart", "정말로 재시작 하시겠습니까"), + ("Restarting Remote Device", "원격 기기를 다시 시작하는중"), + ("remote_restarting_tip", "원격 장치를 다시 시작하는 중입니다. 이 메시지 상자를 닫고 잠시 후 영구 비밀번호로 다시 연결하십시오."), + ].iter().cloned().collect(); +} \ No newline at end of file diff --git a/src/lang/pt_PT b/src/lang/pt_PT new file mode 100644 index 000000000..e6e282575 --- /dev/null +++ b/src/lang/pt_PT @@ -0,0 +1,303 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "Estado"), + ("Your Desktop", "Ambiente de Trabalho"), + ("desk_tip", "O seu Ambiente de Trabalho pode ser acedido com este ID e palavra-passe."), + ("Password", "Senha"), + ("Ready", "Pronto"), + ("Established", "Estabelecido"), + ("connecting_status", "A ligar à rede do RustDesk..."), + ("Enable Service", "Activar Serviço"), + ("Start Service", "Iniciar Serviço"), + ("Service is running", "Serviço está activo"), + ("Service is not running", "Serviço não está activo"), + ("not_ready_status", "Indisponível. Por favor verifique a sua ligação"), + ("Control Remote Desktop", "Controle o Ambiente de Trabalho à distância"), + ("Transfer File", "Transferir Ficheiro"), + ("Connect", "Ligar"), + ("Recent Sessions", "Sessões recentes"), + ("Address Book", "Lista de Endereços"), + ("Confirmation", "Confirmação"), + ("TCP Tunneling", "Túnel TCP"), + ("Remove", "Remover"), + ("Refresh random password", "Actualizar palavra-chave"), + ("Set your own password", "Configure a sua palavra-passe"), + ("Enable Keyboard/Mouse", "Activar Teclado/Rato"), + ("Enable Clipboard", "Activar Área de Transferência"), + ("Enable File Transfer", "Activar Transferência de Ficheiros"), + ("Enable TCP Tunneling", "Activar Túnel TCP"), + ("IP Whitelisting", "Whitelist de IP"), + ("ID/Relay Server", "Servidor ID/Relay"), + ("Stop service", "Parar serviço"), + ("Change ID", "Alterar ID"), + ("Website", "Website"), + ("About", "Sobre"), + ("Mute", "Emudecer"), + ("Audio Input", "Entrada de Áudio"), + ("Enhancements", "Melhorias"), + ("Hardware Codec", ""), + ("Adaptive Bitrate", ""), + ("ID Server", "Servidor de ID"), + ("Relay Server", "Servidor de Relay"), + ("API Server", "Servidor da API"), + ("invalid_http", "deve iniciar com http:// ou https://"), + ("Invalid IP", "IP inválido"), + ("id_change_tip", "Somente os caracteres a-z, A-Z, 0-9 e _ (sublinhado) são permitidos. A primeira letra deve ser a-z, A-Z. Comprimento entre 6 e 16."), + ("Invalid format", "Formato inválido"), + ("server_not_support", "Ainda não suportado pelo servidor"), + ("Not available", "Indisponível"), + ("Too frequent", "Muito frequente"), + ("Cancel", "Cancelar"), + ("Skip", "Passar"), + ("Close", "Fechar"), + ("Retry", "Tentar novamente"), + ("OK", "Confirmar"), + ("Password Required", "Palavra-chave Necessária"), + ("Please enter your password", "Por favor introduza a sua palavra-chave"), + ("Remember password", "Memorizar palavra-chave"), + ("Wrong Password", "Palavra-chave inválida"), + ("Do you want to enter again?", "Deseja tentar novamente??"), + ("Connection Error", "Erro de Ligação"), + ("Error", "Erro"), + ("Reset by the peer", "Reiniciado pelo destino"), + ("Connecting...", "A Ligar..."), + ("Connection in progress. Please wait.", "Ligação em progresso. Aguarde por favor."), + ("Please try 1 minute later", "Por favor tente após 1 minuto"), + ("Login Error", "Erro de Login"), + ("Successful", "Sucesso"), + ("Connected, waiting for image...", "Ligado. A aguardar pela imagem..."), + ("Name", "Nome"), + ("Type", "Tipo"), + ("Modified", "Modificado"), + ("Size", "Tamanho"), + ("Show Hidden Files", "Mostrar Ficheiros Ocultos"), + ("Receive", "Receber"), + ("Send", "Enviar"), + ("Refresh File", "Actualizar Ficheiro"), + ("Local", "Local"), + ("Remote", "Remoto"), + ("Remote Computer", "Computador Remoto"), + ("Local Computer", "Computador Local"), + ("Confirm Delete", "Confirmar Apagar"), + ("Delete", "Apagar"), + ("Properties", "Propriedades"), + ("Multi Select", "Selecção Múltipla"), + ("Empty Directory", "Directório Vazio"), + ("Not an empty directory", "Directório não está vazio"), + ("Are you sure you want to delete this file?", "Tem certeza que deseja apagar este ficheiro?"), + ("Are you sure you want to delete this empty directory?", "Tem certeza que deseja apagar este directório vazio?"), + ("Are you sure you want to delete the file of this directory?", "Tem certeza que deseja apagar este ficheiro deste directório?"), + ("Do this for all conflicts", "Fazer isto para todos os conflictos"), + ("This is irreversible!", "Isto é irreversível!"), + ("Deleting", "A apagar"), + ("files", "ficheiros"), + ("Waiting", "A aguardar"), + ("Finished", "Completo"), + ("Speed", "Velocidade"), + ("Custom Image Quality", "Qualidade Visual Personalizada"), + ("Privacy mode", "Modo privado"), + ("Block user input", "Bloquear entrada de utilizador"), + ("Unblock user input", "Desbloquear entrada de utilizador"), + ("Adjust Window", "Ajustar Janela"), + ("Original", "Original"), + ("Shrink", "Reduzir"), + ("Stretch", "Aumentar"), + ("Good image quality", "Qualidade visual boa"), + ("Balanced", "Equilibrada"), + ("Optimize reaction time", "Optimizar tempo de reacção"), + ("Custom", "Personalizado"), + ("Show remote cursor", "Mostrar cursor remoto"), + ("Show quality monitor", ""), + ("Disable clipboard", "Desabilitar área de transferência"), + ("Lock after session end", "Bloquear após o fim da sessão"), + ("Insert", "Inserir"), + ("Insert Lock", "Bloquear Inserir"), + ("Refresh", "Actualizar"), + ("ID does not exist", "ID não existente"), + ("Failed to connect to rendezvous server", "Falha ao ligar ao servidor de rendezvous"), + ("Please try later", "Por favor tente mais tarde"), + ("Remote desktop is offline", "Ambiente de trabalho remoto está desligado"), + ("Key mismatch", "Chaves incompatíveis"), + ("Timeout", "Tempo esgotado"), + ("Failed to connect to relay server", "Falha ao ligar ao servidor de relay"), + ("Failed to connect via rendezvous server", "Falha ao ligar ao servidor de rendezvous"), + ("Failed to connect via relay server", "Falha ao ligar através do servidor de relay"), + ("Failed to make direct connection to remote desktop", "Falha ao fazer ligação directa ao desktop remoto"), + ("Set Password", "Definir palavra-chave"), + ("OS Password", "Senha do SO"), + ("install_tip", "Devido ao UAC, o RustDesk não funciona correctamente em alguns casos. Para evitar o UAC, por favor clique no botão abaixo para instalar o RustDesk no sistema."), + ("Click to update", "Clique para fazer a actualização"), + ("Click to download", "Clique para carregar"), + ("Click to update", "Clique para fazer a actualização"), + ("Configure", "Configurar"), + ("config_acc", "Para controlar o seu Ambiente de Trabalho remotamente, é preciso conceder ao RustDesk permissões de \"Acessibilidade\"."), + ("config_screen", "Para aceder ao seu Ambiente de Trabalho remotamente, é preciso conceder ao RustDesk permissões de \"Gravar a Tela\"/"), + ("Installing ...", "A Instalar ..."), + ("Install", "Instalar"), + ("Installation", "Instalação"), + ("Installation Path", "Caminho da Instalação"), + ("Create start menu shortcuts", "Criar atalhos no menu iniciar"), + ("Create desktop icon", "Criar ícone no ambiente de trabalho"), + ("agreement_tip", "Ao iniciar a instalação, você concorda com o acordo de licença."), + ("Accept and Install", "Aceitar e Instalar"), + ("End-user license agreement", "Acordo de licença do utilizador final"), + ("Generating ...", "A Gerar ..."), + ("Your installation is lower version.", "A sua instalação é de uma versão anterior."), + ("not_close_tcp_tip", "Não feche esta janela enquanto estiver a utilizar o túnel"), + ("Listening ...", "A escuta ..."), + ("Remote Host", "Host Remoto"), + ("Remote Port", "Porta Remota"), + ("Action", "Acção"), + ("Add", "Adicionar"), + ("Local Port", "Porta Local"), + ("setup_server_tip", "Para uma ligação mais rápida, por favor configure seu próprio servidor"), + ("Too short, at least 6 characters.", "Muito curto, pelo menos 6 caracteres."), + ("The confirmation is not identical.", "A confirmação não é idêntica."), + ("Permissions", "Permissões"), + ("Accept", "Aceitar"), + ("Dismiss", "Dispensar"), + ("Disconnect", "Desconectar"), + ("Allow using keyboard and mouse", "Permitir o uso de teclado e rato"), + ("Allow using clipboard", "Permitir o uso da área de transferência"), + ("Allow hearing sound", "Permitir ouvir som"), + ("Allow file copy and paste", "Permitir copiar e mover ficheiros"), + ("Connected", "Ligado"), + ("Direct and encrypted connection", "Ligação directa e encriptada"), + ("Relayed and encrypted connection", "Ligação via relay e encriptada"), + ("Direct and unencrypted connection", "Ligação direta e não encriptada"), + ("Relayed and unencrypted connection", "Ligação via relay e não encriptada"), + ("Enter Remote ID", "Introduza o ID Remoto"), + ("Enter your password", "Introduza a sua palavra-chave"), + ("Logging in...", "A efectuar Login..."), + ("Enable RDP session sharing", "Activar partilha de sessão RDP"), + ("Auto Login", "Login Automático (Somente válido se você activou \"Bloquear após o fim da sessão\")"), + ("Enable Direct IP Access", "Activar Acesso IP Directo"), + ("Rename", "Renomear"), + ("Space", "Espaço"), + ("Create Desktop Shortcut", "Criar Atalho no Ambiente de Trabalho"), + ("Change Path", "Alterar Caminho"), + ("Create Folder", "Criar Diretório"), + ("Please enter the folder name", "Por favor introduza o nome do diretório"), + ("Fix it", "Reparar"), + ("Warning", "Aviso"), + ("Login screen using Wayland is not supported", "Tela de Login com Wayland não é suportada"), + ("Reboot required", "Reinicialização necessária"), + ("Unsupported display server ", "Servidor de display não suportado"), + ("x11 expected", "x11 em falha"), + ("Port", "Porta"), + ("Settings", "Configurações"), + ("Username", "Nome de utilizador"), + ("Invalid port", "Porta inválida"), + ("Closed manually by the peer", "Fechada manualmente pelo destino"), + ("Enable remote configuration modification", "Habilitar modificações de configuração remotas"), + ("Run without install", "Executar sem instalar"), + ("Always connected via relay", "Sempre conectado via relay"), + ("Always connect via relay", "Sempre conectar via relay"), + ("whitelist_tip", "Somente IPs na whitelist podem me acessar"), + ("Login", "Login"), + ("Logout", "Sair"), + ("Tags", "Tags"), + ("Search ID", "Procurar ID"), + ("Current Wayland display server is not supported", "Servidor de display Wayland atual não é suportado"), + ("whitelist_sep", "Separado por vírcula, ponto-e-vírgula, espaços ou nova linha"), + ("Add ID", "Adicionar ID"), + ("Add Tag", "Adicionar Tag"), + ("Unselect all tags", "Desselecionar todas as tags"), + ("Network error", "Erro de rede"), + ("Username missed", "Nome de utilizador em falta"), + ("Password missed", "Palavra-chave em falta"), + ("Wrong credentials", "Nome de utilizador ou palavra-chave incorrectos"), + ("Edit Tag", "Editar Tag"), + ("Unremember Password", "Esquecer Palavra-chave"), + ("Favorites", "Favoritos"), + ("Add to Favorites", "Adicionar aos Favoritos"), + ("Remove from Favorites", "Remover dos Favoritos"), + ("Empty", "Vazio"), + ("Invalid folder name", "Nome de diretório inválido"), + ("Socks5 Proxy", "Proxy Socks5"), + ("Hostname", "Nome de anfitrião"), + ("Discovered", "Descoberto"), + ("install_daemon_tip", "Para inicialização junto do sistema, deve instalar o serviço de sistema."), + ("Remote ID", "ID Remoto"), + ("Paste", "Colar"), + ("Paste here?", "Colar aqui?"), + ("Are you sure to close the connection?", "Tem certeza que deseja fechar a ligação?"), + ("Download new version", "Transferir nova versão"), + ("Touch mode", "Modo toque"), + ("Mouse mode", "Modo rato"), + ("One-Finger Tap", "Toque com um dedo"), + ("Left Mouse", "Botão esquerdo do rato"), + ("One-Long Tap", "Um toque longo"), + ("Two-Finger Tap", "Toque com dois dedos"), + ("Right Mouse", "Botão direito do rato"), + ("One-Finger Move", "Mover com um dedo"), + ("Double Tap & Move", "Toque duplo & mover"), + ("Mouse Drag", "Arrastar com o rato"), + ("Three-Finger vertically", "Três dedos verticalmente"), + ("Mouse Wheel", "Roda do rato"), + ("Two-Finger Move", "Mover com dois dedos"), + ("Canvas Move", "Mover Tela"), + ("Pinch to Zoom", "Beliscar para Zoom"), + ("Canvas Zoom", "Zoom na Tela"), + ("Reset canvas", "Reiniciar tela"), + ("No permission of file transfer", "Sem permissões de transferência de ficheiro"), + ("Note", "Nota"), + ("Connection", "Ligação"), + ("Share Screen", "Partilhar ecran"), + ("CLOSE", "FECHAR"), + ("OPEN", "ABRIR"), + ("Chat", "Conversar"), + ("Total", "Total"), + ("items", "itens"), + ("Selected", "Seleccionado"), + ("Screen Capture", "Captura de Ecran"), + ("Input Control", "Controle de Entrada"), + ("Audio Capture", "Captura de Áudio"), + ("File Connection", "Ligação de Arquivo"), + ("Screen Connection", "Ligação de Ecran"), + ("Do you accept?", "Aceita?"), + ("Open System Setting", "Abrir Configurações do Sistema"), + ("How to get Android input permission?", "Como activar a permissão de entrada do Android?"), + ("android_input_permission_tip1", "Para que um dispositivo remoto controle o seu dispositivo Android via rato ou toque, você precisa permitir que o RustDesk use o serviço \"Acessibilidade\"."), + ("android_input_permission_tip2", "Por favor vá para a próxima página de configuração do sistema, encontre e entre [Serviços Instalados], ACTIVE o serviço [RustDesk Input]."), + ("android_new_connection_tip", "Nova requisição de controle recebida, solicita o controle do seu dispositivo atual."), + ("android_service_will_start_tip", "Activar a Captura de Ecran irá automaticamente inicializar o serviço, permitindo que outros dispositivos solicitem uma ligação deste dispositivo."), + ("android_stop_service_tip", "Fechar o serviço irá automaticamente fechar todas as ligações estabelecidas."), + ("android_version_audio_tip", "A versão atual do Android não suporta captura de áudio, por favor actualize para o Android 10 ou maior."), + ("android_start_service_tip", "Toque [Iniciar Serviço] ou abra a permissão [Captura de Ecran] para iniciar o serviço de partilha de ecran."), + ("Account", "Conta"), + ("Overwrite", "Substituir"), + ("This file exists, skip or overwrite this file?", "Este ficheiro já existe, ignorar ou substituir este ficheiro?"), + ("Quit", "Saída"), + ("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"), + ("Help", "Ajuda"), + ("Failed", "Falhou"), + ("Succeeded", "Conseguiu"), + ("Someone turns on privacy mode, exit", "Alguém activou o modo de privacidade, desligue"), + ("Unsupported", "Sem suporte"), + ("Peer denied", "Remoto negado"), + ("Please install plugins", "Por favor instale plugins"), + ("Peer exit", "Saída do Remoto"), + ("Failed to turn off", "Falha ao desligar"), + ("Turned off", "Desligado"), + ("In privacy mode", "Em modo de privacidade"), + ("Out privacy mode", "Sair do modo de privacidade"), + ("Language", "Linguagem"), + ("Keep RustDesk background service", "Manter o serviço RustDesk em funcionamento"), + ("Ignore Battery Optimizations", "Ignorar optimizações de Bateria"), + ("android_open_battery_optimizations_tip", ""), + ("Connection not allowed", "Ligação não autorizada"), + ("Use temporary password", "Utilizar palavra-chave temporária"), + ("Use permanent password", "Utilizar palavra-chave permanente"), + ("Use both passwords", "Utilizar ambas as palavras-chave"), + ("Set permanent password", "Definir palavra-chave permanente"), + ("Set temporary password length", "Definir tamanho de palavra-chave temporária"), + ("Enable Remote Restart", "Activar reiniciar remoto"), + ("Allow remote restart", "Permitir reiniciar remoto"), + ("Restart Remote Device", "Reiniciar Dispositivo Remoto"), + ("Are you sure you want to restart", "Tem a certeza que pretende reiniciar"), + ("Restarting Remote Device", "A reiniciar sistema remoto"), + ("remote_restarting_tip", ""), + ].iter().cloned().collect(); +} diff --git a/src/main.rs b/src/main.rs index 8ecc72ad6..0acdde68f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -166,7 +166,7 @@ fn main() { } fn import_config(path: &str) { - use hbb_common::{config::*, get_modified_time}; + use hbb_common::{config::*, get_exe_time, get_modified_time}; let path2 = path.replace(".toml", "2.toml"); let path2 = std::path::Path::new(&path2); let path = std::path::Path::new(path); @@ -176,7 +176,9 @@ fn import_config(path: &str) { log::info!("Empty source config, skipped"); return; } - if get_modified_time(&path) > get_modified_time(&Config::file()) { + if get_modified_time(&path) > get_modified_time(&Config::file()) + && get_modified_time(&path) < get_exe_time() + { if store_path(Config::file(), config).is_err() { log::info!("config written"); } diff --git a/src/port_forward.rs b/src/port_forward.rs index a17ee8259..9a697da42 100644 --- a/src/port_forward.rs +++ b/src/port_forward.rs @@ -1,7 +1,7 @@ use crate::client::*; use hbb_common::{ allow_err, bail, - config::CONNECT_TIMEOUT, + config::READ_TIMEOUT, futures::{SinkExt, StreamExt}, log, message_proto::*, @@ -105,22 +105,61 @@ async fn connect_and_login( key: &str, token: &str, is_rdp: bool, +) -> ResultType> { + let mut res = connect_and_login_2( + id, + password, + ui_receiver, + interface.clone(), + forward, + key, + token, + is_rdp, + ) + .await; + if res.is_err() && interface.is_force_relay() { + res = connect_and_login_2( + id, + password, + ui_receiver, + interface, + forward, + key, + token, + is_rdp, + ) + .await; + } + res +} + +async fn connect_and_login_2( + id: &str, + password: &str, + ui_receiver: &mut mpsc::UnboundedReceiver, + interface: impl Interface, + forward: &mut Framed, + key: &str, + token: &str, + is_rdp: bool, ) -> ResultType> { let conn_type = if is_rdp { ConnType::RDP } else { ConnType::PORT_FORWARD }; - let (mut stream, _) = Client::start(id, key, token, conn_type).await?; + let (mut stream, direct) = Client::start(id, key, token, conn_type, interface.clone()).await?; let mut interface = interface; let mut buffer = Vec::new(); + let mut received = false; loop { tokio::select! { - res = timeout(CONNECT_TIMEOUT, stream.next()) => match res { + res = timeout(READ_TIMEOUT, stream.next()) => match res { Err(_) => { bail!("Timeout"); } Ok(Some(Ok(bytes))) => { + received = true; let msg_in = Message::parse_from_bytes(&bytes)?; match msg_in.union { Some(message::Union::Hash(hash)) => { @@ -143,6 +182,11 @@ async fn connect_and_login( _ => {} } } + Ok(Some(Err(err))) => { + log::error!("Connection closed: {}", err); + interface.set_force_relay(direct, received); + bail!("Connection closed: {}", err); + } _ => { bail!("Reset by the peer"); } diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 28fa62352..658783623 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -316,7 +316,7 @@ class SessionList: Reactor.Component {
  • {translate('Connect')}
  • {translate('Transfer File')}
  • {translate('TCP Tunneling')}
  • - {false && !handler.using_public_server() &&
  • {svg_checkmark}{translate('Always connect via relay')}
  • } +
  • {svg_checkmark}{translate('Always connect via relay')}
  • RDP
  • {translate('WOL')}
  • @@ -396,7 +396,6 @@ class SessionList: Reactor.Component { if (el) { var force = handler.get_peer_option(id, "force-always-relay"); el.attributes.toggleClass("selected", force == "Y"); - el.attributes.toggleClass("line-through", force != "Y"); } var conn = this.$(menu #connect); if (conn) { diff --git a/src/ui/index.tis b/src/ui/index.tis index be6e2c355..256f00c44 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -3,7 +3,7 @@ stdout.println("current platform:", OS); stdout.println("is_xfce: ", is_xfce); // html min-width, min-height not working on mac, below works for all -view.windowMinSize = (scaleIt(500), scaleIt(300)); +view.windowMinSize = (scaleIt(560), scaleIt(300)); var app; var tmp = handler.get_connect_status(); diff --git a/src/ui/macos.rs b/src/ui/macos.rs index 188fbb603..3c7a7dcd0 100644 --- a/src/ui/macos.rs +++ b/src/ui/macos.rs @@ -13,6 +13,7 @@ use objc::{ }; use sciter::{make_args, Host}; use std::{ffi::c_void, rc::Rc}; +use dark_light; static APP_HANDLER_IVAR: &str = "GoDeskAppHandler"; @@ -233,7 +234,17 @@ pub fn make_tray() { set_delegate(None); } use tray_item::TrayItem; - if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), "mac-tray.png") { + let mode = dark_light::detect(); + let mut icon_path = ""; + match mode { + dark_light::Mode::Dark => { + icon_path = "mac-tray-light.png"; + }, + dark_light::Mode::Light => { + icon_path = "mac-tray-dark.png"; + }, + } + if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), icon_path) { tray.add_label(&format!( "{} {}", crate::get_app_name(), diff --git a/src/ui/remote.rs b/src/ui/remote.rs index aa0282bc2..ee0bc3f1d 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -49,6 +49,7 @@ use crate::{ client::*, common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}, }; +use errno; type Video = AssetPtr; @@ -1452,12 +1453,21 @@ impl Remote { async fn io_loop(&mut self, key: &str, token: &str) { let stop_clipboard = self.start_clipboard(); let mut last_recv_time = Instant::now(); + let mut received = false; let conn_type = if self.handler.is_file_transfer() { ConnType::FILE_TRANSFER } else { ConnType::default() }; - match Client::start(&self.handler.id, key, token, conn_type).await { + match Client::start( + &self.handler.id, + key, + token, + conn_type, + self.handler.clone(), + ) + .await + { Ok((mut peer, direct)) => { SERVER_KEYBOARD_ENABLED.store(true, Ordering::SeqCst); SERVER_CLIPBOARD_ENABLED.store(true, Ordering::SeqCst); @@ -1480,11 +1490,13 @@ impl Remote { match res { Err(err) => { log::error!("Connection closed: {}", err); + self.handler.set_force_relay(direct, received); self.handler.msgbox("error", "Connection Error", &err.to_string()); break; } Ok(ref bytes) => { last_recv_time = Instant::now(); + received = true; self.data_count.fetch_add(bytes.len(), Ordering::Relaxed); if !self.handle_msg_from_peer(bytes, &mut peer).await { break @@ -2067,6 +2079,22 @@ impl Remote { true } + async fn send_opts_after_login(&self, peer: &mut Stream) { + if let Some(opts) = self + .handler + .lc + .read() + .unwrap() + .get_option_message_after_login() + { + let mut misc = Misc::new(); + misc.set_option(opts); + let mut msg_out = Message::new(); + msg_out.set_misc(misc); + allow_err!(peer.send(&msg_out).await); + } + } + async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool { if let Ok(msg_in) = Message::parse_from_bytes(&data) { match msg_in.union { @@ -2075,7 +2103,7 @@ impl Remote { self.first_frame = true; self.handler.call2("closeSuccess", &make_args!()); self.handler.call("adaptSize", &make_args!()); - common::send_opts_after_login(&self.handler.lc.read().unwrap(), peer).await; + self.send_opts_after_login(peer).await; } let incomming_format = CodecFormat::from(&vf); if self.video_format != incomming_format { @@ -2639,7 +2667,7 @@ impl Interface for Handler { self.lc.write().unwrap().handle_peer_info(username, pi); self.call("updatePrivacyMode", &[]); self.call("updatePi", &make_args!(pi_sciter)); - if self.is_file_transfer() || self.is_port_forward() { + if self.is_file_transfer() { self.call2("closeSuccess", &make_args!()); } else if !self.is_port_forward() { self.msgbox("success", "Successful", "Connected, waiting for image..."); @@ -2675,6 +2703,24 @@ impl Interface for Handler { handle_test_delay(t, peer).await; } } + + fn set_force_relay(&mut self, direct: bool, received: bool) { + let mut lc = self.lc.write().unwrap(); + lc.force_relay = false; + if direct && !received { + let errno = errno::errno().0; + log::info!("errno is {}", errno); + // TODO: check mac and ios + if cfg!(windows) && errno == 10054 || !cfg!(windows) && errno == 104 { + lc.force_relay = true; + lc.set_option("force-always-relay".to_owned(), "Y".to_owned()); + } + } + } + + fn is_force_relay(&self) -> bool { + self.lc.read().unwrap().force_relay + } } impl Handler {