Merge branch 'master' into master
This commit is contained in:
commit
c8f38c9386
27
.github/workflows/flutter-ci.yml
vendored
27
.github/workflows/flutter-ci.yml
vendored
@ -13,8 +13,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
LLVM_VERSION: "15.0.6"
|
LLVM_VERSION: "15.0.6"
|
||||||
# Note: currently 3.0.5 does not support arm64 officially, we use latest stable version first.
|
FLUTTER_VERSION: "3.7.0"
|
||||||
FLUTTER_VERSION: "3.0.5"
|
|
||||||
# vcpkg version: 2022.05.10
|
# vcpkg version: 2022.05.10
|
||||||
# for multiarch gcc compatibility
|
# for multiarch gcc compatibility
|
||||||
VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44"
|
VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44"
|
||||||
@ -28,7 +27,7 @@ jobs:
|
|||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
job:
|
job:
|
||||||
- { target: i686-pc-windows-msvc , os: windows-2019 }
|
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||||
steps:
|
steps:
|
||||||
@ -51,9 +50,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
flutter doctor -v
|
flutter doctor -v
|
||||||
flutter precache --windows
|
flutter precache --windows
|
||||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
|
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.7.0-rustdesk/windows-x64-release-flutter.zip -OutFile windows-x64-flutter-release.zip
|
||||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
|
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-${{ env.FLUTTER_VERSION }}-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||||
|
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
@ -837,12 +836,12 @@ jobs:
|
|||||||
# disable git safe.directory
|
# disable git safe.directory
|
||||||
git config --global --add safe.directory "*"
|
git config --global --add safe.directory "*"
|
||||||
pushd /opt
|
pushd /opt
|
||||||
# clone repo and reset to flutter 3.0.5
|
# clone repo and reset to flutter 3.7.0
|
||||||
git clone https://github.com/sony/flutter-elinux.git || true
|
git clone https://github.com/sony/flutter-elinux.git || true
|
||||||
pushd flutter-elinux
|
pushd flutter-elinux
|
||||||
# reset to flutter 3.0.5
|
# reset to flutter 3.7.0
|
||||||
git fetch
|
git fetch
|
||||||
git reset --hard b09a90eee643859ce4e676839227edd9fd3feba8
|
git reset --hard 51a1d685901f79fbac51665a967c3a1a789ecee5
|
||||||
popd
|
popd
|
||||||
|
|
||||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||||
@ -867,11 +866,17 @@ jobs:
|
|||||||
git config --global --add safe.directory "*"
|
git config --global --add safe.directory "*"
|
||||||
pushd /workspace
|
pushd /workspace
|
||||||
# we use flutter-elinux to build our rustdesk
|
# we use flutter-elinux to build our rustdesk
|
||||||
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
|
|
||||||
# Setup flutter-elinux
|
|
||||||
export PATH=/opt/flutter-elinux/bin:$PATH
|
export PATH=/opt/flutter-elinux/bin:$PATH
|
||||||
|
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
|
||||||
|
# Setup flutter-elinux. Run doctor to check if issues here.
|
||||||
flutter-elinux doctor -v
|
flutter-elinux doctor -v
|
||||||
# edit to corresponding arch
|
# Patch arm64 engine for flutter 3.6.0+
|
||||||
|
flutter-elinux precache --linux
|
||||||
|
pushd /tmp
|
||||||
|
curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.7.0-stable.tar.xz
|
||||||
|
tar -xvf flutter_linux_3.7.0-stable.tar.xz flutter/bin/cache/artifacts/engine/linux-x64/shader_lib
|
||||||
|
cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib /opt/flutter-elinux/flutter/bin/cache/artifacts/engine/linux-arm64
|
||||||
|
popd
|
||||||
case ${{ matrix.job.arch }} in
|
case ${{ matrix.job.arch }} in
|
||||||
aarch64)
|
aarch64)
|
||||||
sed -i "s/Architecture: amd64/Architecture: arm64/g" ./build.py
|
sed -i "s/Architecture: amd64/Architecture: arm64/g" ./build.py
|
||||||
|
24
.github/workflows/flutter-nightly.yml
vendored
24
.github/workflows/flutter-nightly.yml
vendored
@ -8,8 +8,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
LLVM_VERSION: "15.0.6"
|
LLVM_VERSION: "15.0.6"
|
||||||
# Note: currently 3.0.5 does not support arm64 officially, we use latest stable version first.
|
FLUTTER_VERSION: "3.7.0"
|
||||||
FLUTTER_VERSION: "3.0.5"
|
|
||||||
TAG_NAME: "nightly"
|
TAG_NAME: "nightly"
|
||||||
# vcpkg version: 2022.05.10
|
# vcpkg version: 2022.05.10
|
||||||
# for multiarch gcc compatibility
|
# for multiarch gcc compatibility
|
||||||
@ -53,9 +52,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
flutter doctor -v
|
flutter doctor -v
|
||||||
flutter precache --windows
|
flutter precache --windows
|
||||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
|
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.7.0-rustdesk/windows-x64-release-flutter.zip -OutFile windows-x64-flutter-release.zip
|
||||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
|
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-${{ env.FLUTTER_VERSION }}-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||||
|
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
@ -983,12 +982,12 @@ jobs:
|
|||||||
# disable git safe.directory
|
# disable git safe.directory
|
||||||
git config --global --add safe.directory "*"
|
git config --global --add safe.directory "*"
|
||||||
pushd /opt
|
pushd /opt
|
||||||
# clone repo and reset to flutter 3.0.5
|
# clone repo and reset to flutter 3.7.0
|
||||||
git clone https://github.com/sony/flutter-elinux.git || true
|
git clone https://github.com/sony/flutter-elinux.git || true
|
||||||
pushd flutter-elinux
|
pushd flutter-elinux
|
||||||
# reset to flutter 3.0.5
|
# reset to flutter 3.7.0
|
||||||
git fetch
|
git fetch
|
||||||
git reset --hard b09a90eee643859ce4e676839227edd9fd3feba8
|
git reset --hard 51a1d685901f79fbac51665a967c3a1a789ecee5
|
||||||
popd
|
popd
|
||||||
|
|
||||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||||
@ -1013,10 +1012,17 @@ jobs:
|
|||||||
git config --global --add safe.directory "*"
|
git config --global --add safe.directory "*"
|
||||||
pushd /workspace
|
pushd /workspace
|
||||||
# we use flutter-elinux to build our rustdesk
|
# we use flutter-elinux to build our rustdesk
|
||||||
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
|
|
||||||
# Setup flutter-elinux
|
|
||||||
export PATH=/opt/flutter-elinux/bin:$PATH
|
export PATH=/opt/flutter-elinux/bin:$PATH
|
||||||
|
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
|
||||||
|
# Setup flutter-elinux. Run doctor to check if issues here.
|
||||||
flutter-elinux doctor -v
|
flutter-elinux doctor -v
|
||||||
|
# Patch arm64 engine for flutter 3.6.0+
|
||||||
|
flutter-elinux precache --linux
|
||||||
|
pushd /tmp
|
||||||
|
curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.7.0-stable.tar.xz
|
||||||
|
tar -xvf flutter_linux_3.7.0-stable.tar.xz flutter/bin/cache/artifacts/engine/linux-x64/shader_lib
|
||||||
|
cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib /opt/flutter-elinux/flutter/bin/cache/artifacts/engine/linux-arm64
|
||||||
|
popd
|
||||||
# edit to corresponding arch
|
# edit to corresponding arch
|
||||||
case ${{ matrix.job.arch }} in
|
case ${{ matrix.job.arch }} in
|
||||||
aarch64)
|
aarch64)
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -4371,7 +4371,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rdev"
|
name = "rdev"
|
||||||
version = "0.5.0-2"
|
version = "0.5.0-2"
|
||||||
source = "git+https://github.com/fufesou/rdev#1be26c7e8ed0d43cebdd8331d467bb61130a2e6e"
|
source = "git+https://github.com/fufesou/rdev#238c9778da40056e2efda1e4264355bc89fb6358"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cocoa",
|
"cocoa",
|
||||||
"core-foundation 0.9.3",
|
"core-foundation 0.9.3",
|
||||||
|
@ -1092,21 +1092,21 @@ Widget getOnline(double rightPadding, bool online) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ActionMore extends StatelessWidget {
|
class ActionMore extends StatelessWidget {
|
||||||
final RxBool _iconMoreHover = false.obs;
|
final RxBool _hover = false.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MouseRegion(
|
return InkWell(
|
||||||
onEnter: (_) => _iconMoreHover.value = true,
|
onTap: () {},
|
||||||
onExit: (_) => _iconMoreHover.value = false,
|
onHover: (value) => _hover.value = value,
|
||||||
child: Obx(() => CircleAvatar(
|
child: Obx(() => CircleAvatar(
|
||||||
radius: 14,
|
radius: 14,
|
||||||
backgroundColor: _iconMoreHover.value
|
backgroundColor: _hover.value
|
||||||
? Theme.of(context).scaffoldBackgroundColor
|
? Theme.of(context).scaffoldBackgroundColor
|
||||||
: Theme.of(context).backgroundColor,
|
: Theme.of(context).backgroundColor,
|
||||||
child: Icon(Icons.more_vert,
|
child: Icon(Icons.more_vert,
|
||||||
size: 18,
|
size: 18,
|
||||||
color: _iconMoreHover.value
|
color: _hover.value
|
||||||
? Theme.of(context).textTheme.titleLarge?.color
|
? Theme.of(context).textTheme.titleLarge?.color
|
||||||
: Theme.of(context)
|
: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
|
@ -652,8 +652,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
|
|||||||
dismissOnClicked: true,
|
dismissOnClicked: true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (false &&
|
if (pi.platform != kPeerPlatformAndroid &&
|
||||||
pi.platform != kPeerPlatformAndroid &&
|
|
||||||
version_cmp(peer_version, '1.2.0') >= 0) {
|
version_cmp(peer_version, '1.2.0') >= 0) {
|
||||||
displayMenu.add(MenuEntryButton<String>(
|
displayMenu.add(MenuEntryButton<String>(
|
||||||
childBuilder: (TextStyle? style) => Text(
|
childBuilder: (TextStyle? style) => Text(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -63,8 +64,10 @@ class RustDeskMultiWindowManager {
|
|||||||
..setFrame(const Offset(0, 0) & const Size(1280, 720))
|
..setFrame(const Offset(0, 0) & const Size(1280, 720))
|
||||||
..center()
|
..center()
|
||||||
..setTitle(getWindowNameWithId(remoteId,
|
..setTitle(getWindowNameWithId(remoteId,
|
||||||
overrideType: WindowType.RemoteDesktop))
|
overrideType: WindowType.RemoteDesktop));
|
||||||
..show();
|
if (Platform.isMacOS) {
|
||||||
|
Future.microtask(() => remoteDesktopController.show());
|
||||||
|
}
|
||||||
registerActiveWindow(remoteDesktopController.windowId);
|
registerActiveWindow(remoteDesktopController.windowId);
|
||||||
_remoteDesktopWindowId = remoteDesktopController.windowId;
|
_remoteDesktopWindowId = remoteDesktopController.windowId;
|
||||||
} else {
|
} else {
|
||||||
@ -90,8 +93,10 @@ class RustDeskMultiWindowManager {
|
|||||||
..setFrame(const Offset(0, 0) & const Size(1280, 720))
|
..setFrame(const Offset(0, 0) & const Size(1280, 720))
|
||||||
..center()
|
..center()
|
||||||
..setTitle(getWindowNameWithId(remoteId,
|
..setTitle(getWindowNameWithId(remoteId,
|
||||||
overrideType: WindowType.FileTransfer))
|
overrideType: WindowType.FileTransfer));
|
||||||
..show();
|
if (Platform.isMacOS) {
|
||||||
|
Future.microtask(() => fileTransferController.show());
|
||||||
|
}
|
||||||
registerActiveWindow(fileTransferController.windowId);
|
registerActiveWindow(fileTransferController.windowId);
|
||||||
_fileTransferWindowId = fileTransferController.windowId;
|
_fileTransferWindowId = fileTransferController.windowId;
|
||||||
} else {
|
} else {
|
||||||
@ -116,9 +121,11 @@ class RustDeskMultiWindowManager {
|
|||||||
portForwardController
|
portForwardController
|
||||||
..setFrame(const Offset(0, 0) & const Size(1280, 720))
|
..setFrame(const Offset(0, 0) & const Size(1280, 720))
|
||||||
..center()
|
..center()
|
||||||
..setTitle(
|
..setTitle(getWindowNameWithId(remoteId,
|
||||||
getWindowNameWithId(remoteId, overrideType: WindowType.PortForward))
|
overrideType: WindowType.PortForward));
|
||||||
..show();
|
if (Platform.isMacOS) {
|
||||||
|
Future.microtask(() => portForwardController.show());
|
||||||
|
}
|
||||||
registerActiveWindow(portForwardController.windowId);
|
registerActiveWindow(portForwardController.windowId);
|
||||||
_portForwardWindowId = portForwardController.windowId;
|
_portForwardWindowId = portForwardController.windowId;
|
||||||
} else {
|
} else {
|
||||||
|
@ -7,7 +7,7 @@ import desktop_drop
|
|||||||
import device_info_plus_macos
|
import device_info_plus_macos
|
||||||
import flutter_custom_cursor
|
import flutter_custom_cursor
|
||||||
import package_info_plus_macos
|
import package_info_plus_macos
|
||||||
import path_provider_macos
|
import path_provider_foundation
|
||||||
import screen_retriever
|
import screen_retriever
|
||||||
import sqflite
|
import sqflite
|
||||||
// import tray_manager
|
// import tray_manager
|
||||||
|
@ -31,7 +31,7 @@ dependencies:
|
|||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.3
|
cupertino_icons: ^1.0.3
|
||||||
ffi: ^2.0.1
|
ffi: ^2.0.1
|
||||||
path_provider: ^2.0.2
|
path_provider: ^2.0.12
|
||||||
external_path: ^1.0.1
|
external_path: ^1.0.1
|
||||||
provider: ^6.0.3
|
provider: ^6.0.3
|
||||||
tuple: ^2.0.0
|
tuple: ^2.0.0
|
||||||
@ -75,14 +75,14 @@ dependencies:
|
|||||||
debounce_throttle: ^2.0.0
|
debounce_throttle: ^2.0.0
|
||||||
file_picker: ^5.1.0
|
file_picker: ^5.1.0
|
||||||
flutter_svg: ^1.1.5
|
flutter_svg: ^1.1.5
|
||||||
flutter_improved_scrolling: ^0.0.3
|
flutter_improved_scrolling:
|
||||||
# currently, we use flutter 3.0.5 for windows build, latest for other builds.
|
# currently, we use flutter 3.0.5 for windows build, latest for other builds.
|
||||||
#
|
#
|
||||||
# for flutter 3.0.5, please use official version(just comment code below).
|
# for flutter 3.0.5, please use official version(just comment code below).
|
||||||
# if build rustdesk by flutter >=3.3, please use our custom pub below (uncomment code below).
|
# if build rustdesk by flutter >=3.3, please use our custom pub below (uncomment code below).
|
||||||
# git:
|
git:
|
||||||
# url: https://github.com/Kingtous/flutter_improved_scrolling
|
url: https://github.com/Kingtous/flutter_improved_scrolling
|
||||||
# ref: 62f09545149f320616467c306c8c5f71714a18e6
|
ref: 62f09545149f320616467c306c8c5f71714a18e6
|
||||||
uni_links: ^0.5.1
|
uni_links: ^0.5.1
|
||||||
uni_links_desktop: ^0.1.4
|
uni_links_desktop: ^0.1.4
|
||||||
path: ^1.8.1
|
path: ^1.8.1
|
||||||
|
@ -8,10 +8,7 @@ fn main() {
|
|||||||
.out_dir(out_dir)
|
.out_dir(out_dir)
|
||||||
.inputs(&["protos/rendezvous.proto", "protos/message.proto"])
|
.inputs(&["protos/rendezvous.proto", "protos/message.proto"])
|
||||||
.include("protos")
|
.include("protos")
|
||||||
.customize(
|
.customize(protobuf_codegen::Customize::default().tokio_bytes(true))
|
||||||
protobuf_codegen::Customize::default()
|
|
||||||
.tokio_bytes(true)
|
|
||||||
)
|
|
||||||
.run()
|
.run()
|
||||||
.expect("Codegen failed.");
|
.expect("Codegen failed.");
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,12 @@ enum DecodeState {
|
|||||||
Data(usize),
|
Data(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BytesCodec {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BytesCodec {
|
impl BytesCodec {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -56,7 +62,7 @@ impl BytesCodec {
|
|||||||
}
|
}
|
||||||
src.advance(head_len);
|
src.advance(head_len);
|
||||||
src.reserve(n);
|
src.reserve(n);
|
||||||
return Ok(Some(n));
|
Ok(Some(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_data(&self, n: usize, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
|
fn decode_data(&self, n: usize, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
|
||||||
|
@ -32,12 +32,7 @@ pub fn decompress(data: &[u8]) -> Vec<u8> {
|
|||||||
const MAX: usize = 1024 * 1024 * 64;
|
const MAX: usize = 1024 * 1024 * 64;
|
||||||
const MIN: usize = 1024 * 1024;
|
const MIN: usize = 1024 * 1024;
|
||||||
let mut n = 30 * data.len();
|
let mut n = 30 * data.len();
|
||||||
if n > MAX {
|
n = n.clamp(MIN, MAX);
|
||||||
n = MAX;
|
|
||||||
}
|
|
||||||
if n < MIN {
|
|
||||||
n = MIN;
|
|
||||||
}
|
|
||||||
match d.decompress(data, n) {
|
match d.decompress(data, n) {
|
||||||
Ok(res) => out = res,
|
Ok(res) => out = res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -29,7 +29,7 @@ pub const READ_TIMEOUT: u64 = 30_000;
|
|||||||
pub const REG_INTERVAL: i64 = 12_000;
|
pub const REG_INTERVAL: i64 = 12_000;
|
||||||
pub const COMPRESS_LEVEL: i32 = 3;
|
pub const COMPRESS_LEVEL: i32 = 3;
|
||||||
const SERIAL: i32 = 3;
|
const SERIAL: i32 = 3;
|
||||||
const PASSWORD_ENC_VERSION: &'static str = "00";
|
const PASSWORD_ENC_VERSION: &str = "00";
|
||||||
// 128x128
|
// 128x128
|
||||||
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
|
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
|
||||||
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
|
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
|
||||||
@ -43,6 +43,7 @@ lazy_static::lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Size = (i32, i32, i32, i32);
|
type Size = (i32, i32, i32, i32);
|
||||||
|
type KeyPair = (Vec<u8>, Vec<u8>);
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
|
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
|
||||||
@ -54,7 +55,7 @@ lazy_static::lazy_static! {
|
|||||||
_ => "",
|
_ => "",
|
||||||
}.to_owned()));
|
}.to_owned()));
|
||||||
pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned()));
|
pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned()));
|
||||||
static ref KEY_PAIR: Arc<Mutex<Option<(Vec<u8>, Vec<u8>)>>> = Default::default();
|
static ref KEY_PAIR: Arc<Mutex<Option<KeyPair>>> = Default::default();
|
||||||
static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load()));
|
static ref HW_CODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,18 +76,18 @@ lazy_static::lazy_static! {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHARS: &'static [char] = &[
|
const CHARS: &[char] = &[
|
||||||
'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
|
'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
|
||||||
'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||||
];
|
];
|
||||||
|
|
||||||
const RENDEZVOUS_SERVERS: &'static [&'static str] = &[
|
pub const RENDEZVOUS_SERVERS: &[&str] = &[
|
||||||
"rs-ny.rustdesk.com",
|
"rs-ny.rustdesk.com",
|
||||||
"rs-sg.rustdesk.com",
|
"rs-sg.rustdesk.com",
|
||||||
"rs-cn.rustdesk.com",
|
"rs-cn.rustdesk.com",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const RS_PUB_KEY: &'static str = match option_env!("RS_PUB_KEY") {
|
pub const RS_PUB_KEY: &str = match option_env!("RS_PUB_KEY") {
|
||||||
Some(key) if !key.is_empty() => key,
|
Some(key) if !key.is_empty() => key,
|
||||||
_ => "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=",
|
_ => "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=",
|
||||||
};
|
};
|
||||||
@ -131,7 +132,7 @@ pub struct Config {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
salt: String,
|
salt: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
key_pair: (Vec<u8>, Vec<u8>), // sk, pk
|
key_pair: KeyPair, // sk, pk
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
key_confirmed: bool,
|
key_confirmed: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -319,7 +320,7 @@ impl Config2 {
|
|||||||
pub fn load_path<T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug>(
|
pub fn load_path<T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug>(
|
||||||
file: PathBuf,
|
file: PathBuf,
|
||||||
) -> T {
|
) -> T {
|
||||||
let cfg = match confy::load_path(&file) {
|
let cfg = match confy::load_path(file) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Failed to load config: {}", err);
|
log::error!("Failed to load config: {}", err);
|
||||||
@ -366,21 +367,17 @@ impl Config {
|
|||||||
config.id = id;
|
config.id = id;
|
||||||
id_valid = true;
|
id_valid = true;
|
||||||
store |= store2;
|
store |= store2;
|
||||||
} else {
|
} else if crate::get_modified_time(&Self::file_(""))
|
||||||
if crate::get_modified_time(&Self::file_(""))
|
|
||||||
.checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation
|
.checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation
|
||||||
.unwrap_or(crate::get_exe_time())
|
.unwrap_or_else(crate::get_exe_time)
|
||||||
< crate::get_exe_time()
|
< crate::get_exe_time()
|
||||||
{
|
&& !config.id.is_empty()
|
||||||
if !config.id.is_empty()
|
|
||||||
&& config.enc_id.is_empty()
|
&& config.enc_id.is_empty()
|
||||||
&& !decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION).1
|
&& !decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION).1
|
||||||
{
|
{
|
||||||
id_valid = true;
|
id_valid = true;
|
||||||
store = true;
|
store = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if !id_valid {
|
if !id_valid {
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
if let Some(id) = Config::get_auto_id() {
|
if let Some(id) = Config::get_auto_id() {
|
||||||
@ -444,18 +441,18 @@ impl Config {
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
{
|
{
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let org = "";
|
let org = "".to_owned();
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let org = ORG.read().unwrap().clone();
|
let org = ORG.read().unwrap().clone();
|
||||||
// /var/root for root
|
// /var/root for root
|
||||||
if let Some(project) =
|
if let Some(project) =
|
||||||
directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap())
|
directories_next::ProjectDirs::from("", &org, &APP_NAME.read().unwrap())
|
||||||
{
|
{
|
||||||
let mut path = patch(project.config_dir().to_path_buf());
|
let mut path = patch(project.config_dir().to_path_buf());
|
||||||
path.push(p);
|
path.push(p);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
return "".into();
|
"".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,9 +536,9 @@ impl Config {
|
|||||||
rendezvous_server = Self::get_rendezvous_servers()
|
rendezvous_server = Self::get_rendezvous_servers()
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or("".to_owned());
|
.unwrap_or_default();
|
||||||
}
|
}
|
||||||
if !rendezvous_server.contains(":") {
|
if !rendezvous_server.contains(':') {
|
||||||
rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT);
|
rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT);
|
||||||
}
|
}
|
||||||
rendezvous_server
|
rendezvous_server
|
||||||
@ -559,8 +556,8 @@ impl Config {
|
|||||||
let serial_obsolute = CONFIG2.read().unwrap().serial > SERIAL;
|
let serial_obsolute = CONFIG2.read().unwrap().serial > SERIAL;
|
||||||
if serial_obsolute {
|
if serial_obsolute {
|
||||||
let ss: Vec<String> = Self::get_option("rendezvous-servers")
|
let ss: Vec<String> = Self::get_option("rendezvous-servers")
|
||||||
.split(",")
|
.split(',')
|
||||||
.filter(|x| x.contains("."))
|
.filter(|x| x.contains('.'))
|
||||||
.map(|x| x.to_owned())
|
.map(|x| x.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
if !ss.is_empty() {
|
if !ss.is_empty() {
|
||||||
@ -580,7 +577,7 @@ impl Config {
|
|||||||
let mut delay = i64::MAX;
|
let mut delay = i64::MAX;
|
||||||
for (tmp_host, tmp_delay) in ONLINE.lock().unwrap().iter() {
|
for (tmp_host, tmp_delay) in ONLINE.lock().unwrap().iter() {
|
||||||
if tmp_delay > &0 && tmp_delay < &delay {
|
if tmp_delay > &0 && tmp_delay < &delay {
|
||||||
delay = tmp_delay.clone();
|
delay = *tmp_delay;
|
||||||
host = tmp_host.to_string();
|
host = tmp_host.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,7 +644,7 @@ impl Config {
|
|||||||
for x in &ma.bytes()[2..] {
|
for x in &ma.bytes()[2..] {
|
||||||
id = (id << 8) | (*x as u32);
|
id = (id << 8) | (*x as u32);
|
||||||
}
|
}
|
||||||
id = id & 0x1FFFFFFF;
|
id &= 0x1FFFFFFF;
|
||||||
Some(id.to_string())
|
Some(id.to_string())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -679,11 +676,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_host_key_confirmed(host: &str) -> bool {
|
pub fn get_host_key_confirmed(host: &str) -> bool {
|
||||||
if let Some(true) = CONFIG.read().unwrap().keys_confirmed.get(host) {
|
matches!(CONFIG.read().unwrap().keys_confirmed.get(host), Some(true))
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_host_key_confirmed(host: &str, v: bool) {
|
pub fn set_host_key_confirmed(host: &str, v: bool) {
|
||||||
@ -695,7 +688,7 @@ impl Config {
|
|||||||
config.store();
|
config.store();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_key_pair() -> (Vec<u8>, Vec<u8>) {
|
pub fn get_key_pair() -> KeyPair {
|
||||||
// lock here to make sure no gen_keypair more than once
|
// lock here to make sure no gen_keypair more than once
|
||||||
// no use of CONFIG directly here to ensure no recursive calling in Config::load because of password dec which calling this function
|
// no use of CONFIG directly here to ensure no recursive calling in Config::load because of password dec which calling this function
|
||||||
let mut lock = KEY_PAIR.lock().unwrap();
|
let mut lock = KEY_PAIR.lock().unwrap();
|
||||||
@ -714,7 +707,7 @@ impl Config {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
*lock = Some(config.key_pair.clone());
|
*lock = Some(config.key_pair.clone());
|
||||||
return config.key_pair;
|
config.key_pair
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_id() -> String {
|
pub fn get_id() -> String {
|
||||||
@ -849,7 +842,7 @@ impl Config {
|
|||||||
let ext = path.extension();
|
let ext = path.extension();
|
||||||
if let Some(ext) = ext {
|
if let Some(ext) = ext {
|
||||||
let ext = format!("{}.toml", ext.to_string_lossy());
|
let ext = format!("{}.toml", ext.to_string_lossy());
|
||||||
path.with_extension(&ext)
|
path.with_extension(ext)
|
||||||
} else {
|
} else {
|
||||||
path.with_extension("toml")
|
path.with_extension("toml")
|
||||||
}
|
}
|
||||||
@ -861,7 +854,7 @@ const PEERS: &str = "peers";
|
|||||||
impl PeerConfig {
|
impl PeerConfig {
|
||||||
pub fn load(id: &str) -> PeerConfig {
|
pub fn load(id: &str) -> PeerConfig {
|
||||||
let _lock = CONFIG.read().unwrap();
|
let _lock = CONFIG.read().unwrap();
|
||||||
match confy::load_path(&Self::path(id)) {
|
match confy::load_path(Self::path(id)) {
|
||||||
Ok(config) => {
|
Ok(config) => {
|
||||||
let mut config: PeerConfig = config;
|
let mut config: PeerConfig = config;
|
||||||
let mut store = false;
|
let mut store = false;
|
||||||
@ -869,16 +862,16 @@ impl PeerConfig {
|
|||||||
decrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
decrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||||
config.password = password;
|
config.password = password;
|
||||||
store = store || store2;
|
store = store || store2;
|
||||||
config.options.get_mut("rdp_password").map(|v| {
|
if let Some(v) = config.options.get_mut("rdp_password") {
|
||||||
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||||
*v = password;
|
*v = password;
|
||||||
store = store || store2;
|
store = store || store2;
|
||||||
});
|
}
|
||||||
config.options.get_mut("os-password").map(|v| {
|
if let Some(v) = config.options.get_mut("os-password") {
|
||||||
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||||
*v = password;
|
*v = password;
|
||||||
store = store || store2;
|
store = store || store2;
|
||||||
});
|
}
|
||||||
if store {
|
if store {
|
||||||
config.store(id);
|
config.store(id);
|
||||||
}
|
}
|
||||||
@ -895,34 +888,29 @@ impl PeerConfig {
|
|||||||
let _lock = CONFIG.read().unwrap();
|
let _lock = CONFIG.read().unwrap();
|
||||||
let mut config = self.clone();
|
let mut config = self.clone();
|
||||||
config.password = encrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
config.password = encrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||||
config
|
if let Some(v) = config.options.get_mut("rdp_password") {
|
||||||
.options
|
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
|
||||||
.get_mut("rdp_password")
|
}
|
||||||
.map(|v| *v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION));
|
if let Some(v) = config.options.get_mut("os-password") {
|
||||||
config
|
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
|
||||||
.options
|
};
|
||||||
.get_mut("os-password")
|
|
||||||
.map(|v| *v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION));
|
|
||||||
if let Err(err) = store_path(Self::path(id), config) {
|
if let Err(err) = store_path(Self::path(id), config) {
|
||||||
log::error!("Failed to store config: {}", err);
|
log::error!("Failed to store config: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(id: &str) {
|
pub fn remove(id: &str) {
|
||||||
fs::remove_file(&Self::path(id)).ok();
|
fs::remove_file(Self::path(id)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path(id: &str) -> PathBuf {
|
fn path(id: &str) -> PathBuf {
|
||||||
let id_encoded: String;
|
|
||||||
|
|
||||||
//If the id contains invalid chars, encode it
|
//If the id contains invalid chars, encode it
|
||||||
let forbidden_paths = Regex::new(r".*[<>:/\\|\?\*].*").unwrap();
|
let forbidden_paths = Regex::new(r".*[<>:/\\|\?\*].*").unwrap();
|
||||||
if forbidden_paths.is_match(id) {
|
let id_encoded = if forbidden_paths.is_match(id) {
|
||||||
id_encoded =
|
"base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str()
|
||||||
"base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str();
|
|
||||||
} else {
|
} else {
|
||||||
id_encoded = id.to_string();
|
id.to_string()
|
||||||
}
|
};
|
||||||
let path: PathBuf = [PEERS, id_encoded.as_str()].iter().collect();
|
let path: PathBuf = [PEERS, id_encoded.as_str()].iter().collect();
|
||||||
Config::with_extension(Config::path(path))
|
Config::with_extension(Config::path(path))
|
||||||
}
|
}
|
||||||
@ -940,26 +928,24 @@ impl PeerConfig {
|
|||||||
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
|
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
|
||||||
})
|
})
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let t = crate::get_modified_time(&p);
|
let t = crate::get_modified_time(p);
|
||||||
let id = p
|
let id = p
|
||||||
.file_stem()
|
.file_stem()
|
||||||
.map(|p| p.to_str().unwrap_or(""))
|
.map(|p| p.to_str().unwrap_or(""))
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let id_decoded_string: String;
|
let id_decoded_string = if id.starts_with("base64_") && id.len() != 7 {
|
||||||
if id.starts_with("base64_") && id.len() != 7 {
|
|
||||||
let id_decoded = base64::decode(&id[7..], base64::Variant::Original)
|
let id_decoded = base64::decode(&id[7..], base64::Variant::Original)
|
||||||
.unwrap_or(Vec::new());
|
.unwrap_or_default();
|
||||||
id_decoded_string =
|
String::from_utf8_lossy(&id_decoded).as_ref().to_owned()
|
||||||
String::from_utf8_lossy(&id_decoded).as_ref().to_owned();
|
|
||||||
} else {
|
} else {
|
||||||
id_decoded_string = id;
|
id
|
||||||
}
|
};
|
||||||
|
|
||||||
let c = PeerConfig::load(&id_decoded_string);
|
let c = PeerConfig::load(&id_decoded_string);
|
||||||
if c.info.platform.is_empty() {
|
if c.info.platform.is_empty() {
|
||||||
fs::remove_file(&p).ok();
|
fs::remove_file(p).ok();
|
||||||
}
|
}
|
||||||
(id_decoded_string, t, c)
|
(id_decoded_string, t, c)
|
||||||
})
|
})
|
||||||
@ -1149,7 +1135,7 @@ pub struct LanPeers {
|
|||||||
impl LanPeers {
|
impl LanPeers {
|
||||||
pub fn load() -> LanPeers {
|
pub fn load() -> LanPeers {
|
||||||
let _lock = CONFIG.read().unwrap();
|
let _lock = CONFIG.read().unwrap();
|
||||||
match confy::load_path(&Config::file_("_lan_peers")) {
|
match confy::load_path(Config::file_("_lan_peers")) {
|
||||||
Ok(peers) => peers,
|
Ok(peers) => peers,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Failed to load lan peers: {}", err);
|
log::error!("Failed to load lan peers: {}", err);
|
||||||
@ -1158,9 +1144,9 @@ impl LanPeers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(peers: &Vec<DiscoveryPeer>) {
|
pub fn store(peers: &[DiscoveryPeer]) {
|
||||||
let f = LanPeers {
|
let f = LanPeers {
|
||||||
peers: peers.clone(),
|
peers: peers.to_owned(),
|
||||||
};
|
};
|
||||||
if let Err(err) = store_path(Config::file_("_lan_peers"), f) {
|
if let Err(err) = store_path(Config::file_("_lan_peers"), f) {
|
||||||
log::error!("Failed to store lan peers: {}", err);
|
log::error!("Failed to store lan peers: {}", err);
|
||||||
|
@ -13,13 +13,13 @@ use crate::{
|
|||||||
config::{Config, COMPRESS_LEVEL},
|
config::{Config, COMPRESS_LEVEL},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirectory> {
|
pub fn read_dir(path: &Path, include_hidden: bool) -> ResultType<FileDirectory> {
|
||||||
let mut dir = FileDirectory {
|
let mut dir = FileDirectory {
|
||||||
path: get_string(&path),
|
path: get_string(path),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if "/" == &get_string(&path) {
|
if "/" == &get_string(path) {
|
||||||
let drives = unsafe { winapi::um::fileapi::GetLogicalDrives() };
|
let drives = unsafe { winapi::um::fileapi::GetLogicalDrives() };
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
if drives & (1 << i) != 0 {
|
if drives & (1 << i) != 0 {
|
||||||
@ -36,8 +36,7 @@ pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirector
|
|||||||
}
|
}
|
||||||
return Ok(dir);
|
return Ok(dir);
|
||||||
}
|
}
|
||||||
for entry in path.read_dir()? {
|
for entry in path.read_dir()?.flatten() {
|
||||||
if let Ok(entry) = entry {
|
|
||||||
let p = entry.path();
|
let p = entry.path();
|
||||||
let name = p
|
let name = p
|
||||||
.file_name()
|
.file_name()
|
||||||
@ -73,13 +72,11 @@ pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirector
|
|||||||
} else {
|
} else {
|
||||||
(FileType::Dir.into(), 0)
|
(FileType::Dir.into(), 0)
|
||||||
}
|
}
|
||||||
} else {
|
} else if meta.file_type().is_symlink() {
|
||||||
if meta.file_type().is_symlink() {
|
|
||||||
(FileType::FileLink.into(), 0)
|
(FileType::FileLink.into(), 0)
|
||||||
} else {
|
} else {
|
||||||
(FileType::File.into(), meta.len())
|
(FileType::File.into(), meta.len())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let modified_time = meta
|
let modified_time = meta
|
||||||
.modified()
|
.modified()
|
||||||
@ -88,7 +85,7 @@ pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirector
|
|||||||
.map(|x| x.as_secs())
|
.map(|x| x.as_secs())
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
})
|
})
|
||||||
.unwrap_or(0) as u64;
|
.unwrap_or(0);
|
||||||
dir.entries.push(FileEntry {
|
dir.entries.push(FileEntry {
|
||||||
name: get_file_name(&p),
|
name: get_file_name(&p),
|
||||||
entry_type,
|
entry_type,
|
||||||
@ -98,12 +95,11 @@ pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirector
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(dir)
|
Ok(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_file_name(p: &PathBuf) -> String {
|
pub fn get_file_name(p: &Path) -> String {
|
||||||
p.file_name()
|
p.file_name()
|
||||||
.map(|p| p.to_str().unwrap_or(""))
|
.map(|p| p.to_str().unwrap_or(""))
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
@ -111,7 +107,7 @@ pub fn get_file_name(p: &PathBuf) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_string(path: &PathBuf) -> String {
|
pub fn get_string(path: &Path) -> String {
|
||||||
path.to_str().unwrap_or("").to_owned()
|
path.to_str().unwrap_or("").to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,14 +123,14 @@ pub fn get_home_as_string() -> String {
|
|||||||
|
|
||||||
fn read_dir_recursive(
|
fn read_dir_recursive(
|
||||||
path: &PathBuf,
|
path: &PathBuf,
|
||||||
prefix: &PathBuf,
|
prefix: &Path,
|
||||||
include_hidden: bool,
|
include_hidden: bool,
|
||||||
) -> ResultType<Vec<FileEntry>> {
|
) -> ResultType<Vec<FileEntry>> {
|
||||||
let mut files = Vec::new();
|
let mut files = Vec::new();
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
// to-do: symbol link handling, cp the link rather than the content
|
// to-do: symbol link handling, cp the link rather than the content
|
||||||
// to-do: file mode, for unix
|
// to-do: file mode, for unix
|
||||||
let fd = read_dir(&path, include_hidden)?;
|
let fd = read_dir(path, include_hidden)?;
|
||||||
for entry in fd.entries.iter() {
|
for entry in fd.entries.iter() {
|
||||||
match entry.entry_type.enum_value() {
|
match entry.entry_type.enum_value() {
|
||||||
Ok(FileType::File) => {
|
Ok(FileType::File) => {
|
||||||
@ -158,7 +154,7 @@ fn read_dir_recursive(
|
|||||||
}
|
}
|
||||||
Ok(files)
|
Ok(files)
|
||||||
} else if path.is_file() {
|
} else if path.is_file() {
|
||||||
let (size, modified_time) = if let Ok(meta) = std::fs::metadata(&path) {
|
let (size, modified_time) = if let Ok(meta) = std::fs::metadata(path) {
|
||||||
(
|
(
|
||||||
meta.len(),
|
meta.len(),
|
||||||
meta.modified()
|
meta.modified()
|
||||||
@ -167,7 +163,7 @@ fn read_dir_recursive(
|
|||||||
.map(|x| x.as_secs())
|
.map(|x| x.as_secs())
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
})
|
})
|
||||||
.unwrap_or(0) as u64,
|
.unwrap_or(0),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
@ -249,7 +245,7 @@ pub struct RemoveJobMeta {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_ext(name: &str) -> &str {
|
fn get_ext(name: &str) -> &str {
|
||||||
if let Some(i) = name.rfind(".") {
|
if let Some(i) = name.rfind('.') {
|
||||||
return &name[i + 1..];
|
return &name[i + 1..];
|
||||||
}
|
}
|
||||||
""
|
""
|
||||||
@ -270,6 +266,7 @@ fn is_compressed_file(name: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TransferJob {
|
impl TransferJob {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_write(
|
pub fn new_write(
|
||||||
id: i32,
|
id: i32,
|
||||||
remote: String,
|
remote: String,
|
||||||
@ -281,7 +278,7 @@ impl TransferJob {
|
|||||||
enable_overwrite_detection: bool,
|
enable_overwrite_detection: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
log::info!("new write {}", path);
|
log::info!("new write {}", path);
|
||||||
let total_size = files.iter().map(|x| x.size as u64).sum();
|
let total_size = files.iter().map(|x| x.size).sum();
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
remote,
|
remote,
|
||||||
@ -307,7 +304,7 @@ impl TransferJob {
|
|||||||
) -> ResultType<Self> {
|
) -> ResultType<Self> {
|
||||||
log::info!("new read {}", path);
|
log::info!("new read {}", path);
|
||||||
let files = get_recursive_files(&path, show_hidden)?;
|
let files = get_recursive_files(&path, show_hidden)?;
|
||||||
let total_size = files.iter().map(|x| x.size as u64).sum();
|
let total_size = files.iter().map(|x| x.size).sum();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id,
|
id,
|
||||||
remote,
|
remote,
|
||||||
@ -363,7 +360,7 @@ impl TransferJob {
|
|||||||
let entry = &self.files[file_num];
|
let entry = &self.files[file_num];
|
||||||
let path = self.join(&entry.name);
|
let path = self.join(&entry.name);
|
||||||
let download_path = format!("{}.download", get_string(&path));
|
let download_path = format!("{}.download", get_string(&path));
|
||||||
std::fs::rename(&download_path, &path).ok();
|
std::fs::rename(download_path, &path).ok();
|
||||||
filetime::set_file_mtime(
|
filetime::set_file_mtime(
|
||||||
&path,
|
&path,
|
||||||
filetime::FileTime::from_unix_time(entry.modified_time as _, 0),
|
filetime::FileTime::from_unix_time(entry.modified_time as _, 0),
|
||||||
@ -378,7 +375,7 @@ impl TransferJob {
|
|||||||
let entry = &self.files[file_num];
|
let entry = &self.files[file_num];
|
||||||
let path = self.join(&entry.name);
|
let path = self.join(&entry.name);
|
||||||
let download_path = format!("{}.download", get_string(&path));
|
let download_path = format!("{}.download", get_string(&path));
|
||||||
std::fs::remove_file(&download_path).ok();
|
std::fs::remove_file(download_path).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +430,7 @@ impl TransferJob {
|
|||||||
}
|
}
|
||||||
let name = &self.files[file_num].name;
|
let name = &self.files[file_num].name;
|
||||||
if self.file.is_none() {
|
if self.file.is_none() {
|
||||||
match File::open(self.join(&name)).await {
|
match File::open(self.join(name)).await {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
self.file = Some(file);
|
self.file = Some(file);
|
||||||
self.file_confirmed = false;
|
self.file_confirmed = false;
|
||||||
@ -447,20 +444,15 @@ impl TransferJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.enable_overwrite_detection {
|
if self.enable_overwrite_detection && !self.file_confirmed() {
|
||||||
if !self.file_confirmed() {
|
|
||||||
if !self.file_is_waiting() {
|
if !self.file_is_waiting() {
|
||||||
self.send_current_digest(stream).await?;
|
self.send_current_digest(stream).await?;
|
||||||
self.set_file_is_waiting(true);
|
self.set_file_is_waiting(true);
|
||||||
}
|
}
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const BUF_SIZE: usize = 128 * 1024;
|
const BUF_SIZE: usize = 128 * 1024;
|
||||||
let mut buf: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
let mut buf: Vec<u8> = vec![0; BUF_SIZE];
|
||||||
unsafe {
|
|
||||||
buf.set_len(BUF_SIZE);
|
|
||||||
}
|
|
||||||
let mut compressed = false;
|
let mut compressed = false;
|
||||||
let mut offset: usize = 0;
|
let mut offset: usize = 0;
|
||||||
loop {
|
loop {
|
||||||
@ -582,10 +574,7 @@ impl TransferJob {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn job_completed(&self) -> bool {
|
pub fn job_completed(&self) -> bool {
|
||||||
// has no error, Condition 2
|
// has no error, Condition 2
|
||||||
if !self.enable_overwrite_detection || (!self.file_confirmed && !self.file_is_waiting) {
|
!self.enable_overwrite_detection || (!self.file_confirmed && !self.file_is_waiting)
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get job error message, useful for getting status when job had finished
|
/// Get job error message, useful for getting status when job had finished
|
||||||
@ -660,7 +649,7 @@ pub fn new_dir(id: i32, path: String, files: Vec<FileEntry>) -> Message {
|
|||||||
resp.set_dir(FileDirectory {
|
resp.set_dir(FileDirectory {
|
||||||
id,
|
id,
|
||||||
path,
|
path,
|
||||||
entries: files.into(),
|
entries: files,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
@ -692,7 +681,7 @@ pub fn new_receive(id: i32, path: String, file_num: i32, files: Vec<FileEntry>)
|
|||||||
action.set_receive(FileTransferReceiveRequest {
|
action.set_receive(FileTransferReceiveRequest {
|
||||||
id,
|
id,
|
||||||
path,
|
path,
|
||||||
files: files.into(),
|
files,
|
||||||
file_num,
|
file_num,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
@ -736,8 +725,8 @@ pub fn remove_job(id: i32, jobs: &mut Vec<TransferJob>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_job(id: i32, jobs: &mut Vec<TransferJob>) -> Option<&mut TransferJob> {
|
pub fn get_job(id: i32, jobs: &mut [TransferJob]) -> Option<&mut TransferJob> {
|
||||||
jobs.iter_mut().filter(|x| x.id() == id).next()
|
jobs.iter_mut().find(|x| x.id() == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_read_jobs(
|
pub async fn handle_read_jobs(
|
||||||
@ -789,7 +778,7 @@ pub fn remove_all_empty_dir(path: &PathBuf) -> ResultType<()> {
|
|||||||
remove_all_empty_dir(&path.join(&entry.name)).ok();
|
remove_all_empty_dir(&path.join(&entry.name)).ok();
|
||||||
}
|
}
|
||||||
Ok(FileType::DirLink) | Ok(FileType::FileLink) => {
|
Ok(FileType::DirLink) | Ok(FileType::FileLink) => {
|
||||||
std::fs::remove_file(&path.join(&entry.name)).ok();
|
std::fs::remove_file(path.join(&entry.name)).ok();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -813,7 +802,7 @@ pub fn create_dir(dir: &str) -> ResultType<()> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn transform_windows_path(entries: &mut Vec<FileEntry>) {
|
pub fn transform_windows_path(entries: &mut Vec<FileEntry>) {
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
entry.name = entry.name.replace("\\", "/");
|
entry.name = entry.name.replace('\\', "/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +96,24 @@ pub type ResultType<F, E = anyhow::Error> = anyhow::Result<F, E>;
|
|||||||
|
|
||||||
pub struct AddrMangle();
|
pub struct AddrMangle();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn try_into_v4(addr: SocketAddr) -> SocketAddr {
|
||||||
|
match addr {
|
||||||
|
SocketAddr::V6(v6) if !addr.ip().is_loopback() => {
|
||||||
|
if let Some(v4) = v6.ip().to_ipv4() {
|
||||||
|
SocketAddr::new(IpAddr::V4(v4), addr.port())
|
||||||
|
} else {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => addr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AddrMangle {
|
impl AddrMangle {
|
||||||
pub fn encode(addr: SocketAddr) -> Vec<u8> {
|
pub fn encode(addr: SocketAddr) -> Vec<u8> {
|
||||||
|
// not work with [:1]:<port>
|
||||||
|
let addr = try_into_v4(addr);
|
||||||
match addr {
|
match addr {
|
||||||
SocketAddr::V4(addr_v4) => {
|
SocketAddr::V4(addr_v4) => {
|
||||||
let tm = (SystemTime::now()
|
let tm = (SystemTime::now()
|
||||||
@ -129,22 +145,20 @@ impl AddrMangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(bytes: &[u8]) -> SocketAddr {
|
pub fn decode(bytes: &[u8]) -> SocketAddr {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
if bytes.len() > 16 {
|
if bytes.len() > 16 {
|
||||||
if bytes.len() != 18 {
|
if bytes.len() != 18 {
|
||||||
return Config::get_any_listen_addr(false);
|
return Config::get_any_listen_addr(false);
|
||||||
}
|
}
|
||||||
#[allow(invalid_value)]
|
let tmp: [u8; 2] = bytes[16..].try_into().unwrap();
|
||||||
let mut tmp: [u8; 2] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
|
|
||||||
tmp.copy_from_slice(&bytes[16..]);
|
|
||||||
let port = u16::from_le_bytes(tmp);
|
let port = u16::from_le_bytes(tmp);
|
||||||
#[allow(invalid_value)]
|
let tmp: [u8; 16] = bytes[..16].try_into().unwrap();
|
||||||
let mut tmp: [u8; 16] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
|
|
||||||
tmp.copy_from_slice(&bytes[..16]);
|
|
||||||
let ip = std::net::Ipv6Addr::from(tmp);
|
let ip = std::net::Ipv6Addr::from(tmp);
|
||||||
return SocketAddr::new(IpAddr::V6(ip), port);
|
return SocketAddr::new(IpAddr::V6(ip), port);
|
||||||
}
|
}
|
||||||
let mut padded = [0u8; 16];
|
let mut padded = [0u8; 16];
|
||||||
padded[..bytes.len()].copy_from_slice(&bytes);
|
padded[..bytes.len()].copy_from_slice(bytes);
|
||||||
let number = u128::from_le_bytes(padded);
|
let number = u128::from_le_bytes(padded);
|
||||||
let tm = (number >> 17) & (u32::max_value() as u128);
|
let tm = (number >> 17) & (u32::max_value() as u128);
|
||||||
let ip = (((number >> 49) - tm) as u32).to_le_bytes();
|
let ip = (((number >> 49) - tm) as u32).to_le_bytes();
|
||||||
@ -158,21 +172,9 @@ impl AddrMangle {
|
|||||||
|
|
||||||
pub fn get_version_from_url(url: &str) -> String {
|
pub fn get_version_from_url(url: &str) -> String {
|
||||||
let n = url.chars().count();
|
let n = url.chars().count();
|
||||||
let a = url
|
let a = url.chars().rev().position(|x| x == '-');
|
||||||
.chars()
|
|
||||||
.rev()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, x)| x == &'-')
|
|
||||||
.next()
|
|
||||||
.map(|(i, _)| i);
|
|
||||||
if let Some(a) = a {
|
if let Some(a) = a {
|
||||||
let b = url
|
let b = url.chars().rev().position(|x| x == '.');
|
||||||
.chars()
|
|
||||||
.rev()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, x)| x == &'.')
|
|
||||||
.next()
|
|
||||||
.map(|(i, _)| i);
|
|
||||||
if let Some(b) = b {
|
if let Some(b) = b {
|
||||||
if a > b {
|
if a > b {
|
||||||
if url
|
if url
|
||||||
@ -195,21 +197,29 @@ pub fn get_version_from_url(url: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_version() {
|
pub fn gen_version() {
|
||||||
|
if Ok("release".to_owned()) != std::env::var("PROFILE") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!("cargo:rerun-if-changed=Cargo.toml");
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
let mut file = File::create("./src/version.rs").unwrap();
|
let mut file = File::create("./src/version.rs").unwrap();
|
||||||
for line in read_lines("Cargo.toml").unwrap() {
|
for line in read_lines("Cargo.toml").unwrap().flatten() {
|
||||||
if let Ok(line) = line {
|
let ab: Vec<&str> = line.split('=').map(|x| x.trim()).collect();
|
||||||
let ab: Vec<&str> = line.split("=").map(|x| x.trim()).collect();
|
|
||||||
if ab.len() == 2 && ab[0] == "version" {
|
if ab.len() == 2 && ab[0] == "version" {
|
||||||
file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes())
|
file.write_all(format!("pub const VERSION: &str = {};\n", ab[1]).as_bytes())
|
||||||
.ok();
|
.ok();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// generate build date
|
// generate build date
|
||||||
let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
|
let build_date = format!("{}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
|
||||||
file.write_all(format!("pub const BUILD_DATE: &str = \"{}\";", build_date).as_bytes())
|
file.write_all(
|
||||||
|
format!(
|
||||||
|
"#[allow(dead_code)]\npub const BUILD_DATE: &str = \"{}\";",
|
||||||
|
build_date
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
.ok();
|
.ok();
|
||||||
file.sync_all().ok();
|
file.sync_all().ok();
|
||||||
}
|
}
|
||||||
@ -230,20 +240,20 @@ pub fn is_valid_custom_id(id: &str) -> bool {
|
|||||||
|
|
||||||
pub fn get_version_number(v: &str) -> i64 {
|
pub fn get_version_number(v: &str) -> i64 {
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
for x in v.split(".") {
|
for x in v.split('.') {
|
||||||
n = n * 1000 + x.parse::<i64>().unwrap_or(0);
|
n = n * 1000 + x.parse::<i64>().unwrap_or(0);
|
||||||
}
|
}
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
|
pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
|
||||||
std::fs::metadata(&path)
|
std::fs::metadata(path)
|
||||||
.map(|m| m.modified().unwrap_or(UNIX_EPOCH))
|
.map(|m| m.modified().unwrap_or(UNIX_EPOCH))
|
||||||
.unwrap_or(UNIX_EPOCH)
|
.unwrap_or(UNIX_EPOCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_created_time(path: &std::path::Path) -> SystemTime {
|
pub fn get_created_time(path: &std::path::Path) -> SystemTime {
|
||||||
std::fs::metadata(&path)
|
std::fs::metadata(path)
|
||||||
.map(|m| m.created().unwrap_or(UNIX_EPOCH))
|
.map(|m| m.created().unwrap_or(UNIX_EPOCH))
|
||||||
.unwrap_or(UNIX_EPOCH)
|
.unwrap_or(UNIX_EPOCH)
|
||||||
}
|
}
|
||||||
@ -276,32 +286,6 @@ pub fn get_time() -> i64 {
|
|||||||
.unwrap_or(0) as _
|
.unwrap_or(0) as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_mangle() {
|
|
||||||
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
|
|
||||||
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
|
||||||
|
|
||||||
let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
|
|
||||||
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
|
||||||
|
|
||||||
let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
|
|
||||||
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_allow_err() {
|
|
||||||
allow_err!(Err("test err") as Result<(), &str>);
|
|
||||||
allow_err!(
|
|
||||||
Err("test err with msg") as Result<(), &str>,
|
|
||||||
"prompt {}",
|
|
||||||
"failed"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_ipv4_str(id: &str) -> bool {
|
pub fn is_ipv4_str(id: &str) -> bool {
|
||||||
regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
|
regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
|
||||||
@ -334,9 +318,31 @@ pub fn is_domain_port_str(id: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_lib {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mangle() {
|
||||||
|
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
|
||||||
|
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
||||||
|
|
||||||
|
let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
|
||||||
|
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
||||||
|
|
||||||
|
let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
|
||||||
|
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_allow_err() {
|
||||||
|
allow_err!(Err("test err") as Result<(), &str>);
|
||||||
|
allow_err!(
|
||||||
|
Err("test err with msg") as Result<(), &str>,
|
||||||
|
"prompt {}",
|
||||||
|
"failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ipv6() {
|
fn test_ipv6() {
|
||||||
assert_eq!(is_ipv6_str("1:2:3"), true);
|
assert_eq!(is_ipv6_str("1:2:3"), true);
|
||||||
@ -373,4 +379,20 @@ mod test_lib {
|
|||||||
assert_eq!(is_domain_port_str("test.com:0"), true);
|
assert_eq!(is_domain_port_str("test.com:0"), true);
|
||||||
assert_eq!(is_domain_port_str("test.com:98989"), true);
|
assert_eq!(is_domain_port_str("test.com:98989"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mangle2() {
|
||||||
|
let addr = "[::ffff:127.0.0.1]:8080".parse().unwrap();
|
||||||
|
let addr_v4 = "127.0.0.1:8080".parse().unwrap();
|
||||||
|
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr)), addr_v4);
|
||||||
|
assert_eq!(
|
||||||
|
AddrMangle::decode(&AddrMangle::encode("[::127.0.0.1]:8080".parse().unwrap())),
|
||||||
|
addr_v4
|
||||||
|
);
|
||||||
|
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v4)), addr_v4);
|
||||||
|
let addr_v6 = "[ef::fe]:8080".parse().unwrap();
|
||||||
|
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v6)), addr_v6);
|
||||||
|
let addr_v6 = "[::1]:8080".parse().unwrap();
|
||||||
|
assert_eq!(AddrMangle::decode(&AddrMangle::encode(addr_v6)), addr_v6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ pub fn decrypt_str_or_original(s: &str, current_version: &str) -> (String, bool,
|
|||||||
if s.len() > VERSION_LEN {
|
if s.len() > VERSION_LEN {
|
||||||
let version = &s[..VERSION_LEN];
|
let version = &s[..VERSION_LEN];
|
||||||
if version == "00" {
|
if version == "00" {
|
||||||
if let Ok(v) = decrypt(&s[VERSION_LEN..].as_bytes()) {
|
if let Ok(v) = decrypt(s[VERSION_LEN..].as_bytes()) {
|
||||||
return (
|
return (
|
||||||
String::from_utf8_lossy(&v).to_string(),
|
String::from_utf8_lossy(&v).to_string(),
|
||||||
true,
|
true,
|
||||||
@ -149,7 +149,7 @@ pub fn decrypt_vec_or_original(v: &[u8], current_version: &str) -> (Vec<u8>, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn encrypt(v: &[u8]) -> Result<String, ()> {
|
fn encrypt(v: &[u8]) -> Result<String, ()> {
|
||||||
if v.len() > 0 {
|
if !v.is_empty() {
|
||||||
symmetric_crypt(v, true).map(|v| base64::encode(v, base64::Variant::Original))
|
symmetric_crypt(v, true).map(|v| base64::encode(v, base64::Variant::Original))
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
@ -157,7 +157,7 @@ fn encrypt(v: &[u8]) -> Result<String, ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt(v: &[u8]) -> Result<Vec<u8>, ()> {
|
fn decrypt(v: &[u8]) -> Result<Vec<u8>, ()> {
|
||||||
if v.len() > 0 {
|
if !v.is_empty() {
|
||||||
base64::decode(v, base64::Variant::Original).and_then(|v| symmetric_crypt(&v, false))
|
base64::decode(v, base64::Variant::Original).and_then(|v| symmetric_crypt(&v, false))
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -32,7 +32,7 @@ pub fn get_display_server() -> String {
|
|||||||
// loginctl has not given the expected output. try something else.
|
// loginctl has not given the expected output. try something else.
|
||||||
if let Ok(sid) = std::env::var("XDG_SESSION_ID") {
|
if let Ok(sid) = std::env::var("XDG_SESSION_ID") {
|
||||||
// could also execute "cat /proc/self/sessionid"
|
// could also execute "cat /proc/self/sessionid"
|
||||||
session = sid.to_owned();
|
session = sid;
|
||||||
}
|
}
|
||||||
if session.is_empty() {
|
if session.is_empty() {
|
||||||
session = run_cmds("cat /proc/self/sessionid".to_owned()).unwrap_or_default();
|
session = run_cmds("cat /proc/self/sessionid".to_owned()).unwrap_or_default();
|
||||||
@ -63,7 +63,7 @@ fn get_display_server_of_session(session: &str) -> String {
|
|||||||
if let Ok(xorg_results) = run_cmds(format!("ps -e | grep \"{}.\\\\+Xorg\"", tty))
|
if let Ok(xorg_results) = run_cmds(format!("ps -e | grep \"{}.\\\\+Xorg\"", tty))
|
||||||
// And check if Xorg is running on that tty
|
// And check if Xorg is running on that tty
|
||||||
{
|
{
|
||||||
if xorg_results.trim_end().to_string() != "" {
|
if xorg_results.trim_end() != "" {
|
||||||
// If it is, manually return "x11", otherwise return tty
|
// If it is, manually return "x11", otherwise return tty
|
||||||
return "x11".to_owned();
|
return "x11".to_owned();
|
||||||
}
|
}
|
||||||
@ -88,7 +88,7 @@ pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
|
|||||||
if let Ok(output) = run_loginctl(None) {
|
if let Ok(output) = run_loginctl(None) {
|
||||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||||
if line.contains("seat0") {
|
if line.contains("seat0") {
|
||||||
if let Some(sid) = line.split_whitespace().nth(0) {
|
if let Some(sid) = line.split_whitespace().next() {
|
||||||
if is_active(sid) {
|
if is_active(sid) {
|
||||||
return indices
|
return indices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -103,7 +103,7 @@ pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
|
|||||||
// some case, there is no seat0 https://github.com/rustdesk/rustdesk/issues/73
|
// some case, there is no seat0 https://github.com/rustdesk/rustdesk/issues/73
|
||||||
if let Ok(output) = run_loginctl(None) {
|
if let Ok(output) = run_loginctl(None) {
|
||||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||||
if let Some(sid) = line.split_whitespace().nth(0) {
|
if let Some(sid) = line.split_whitespace().next() {
|
||||||
let d = get_display_server_of_session(sid);
|
let d = get_display_server_of_session(sid);
|
||||||
if is_active(sid) && d != "tty" {
|
if is_active(sid) && d != "tty" {
|
||||||
return indices
|
return indices
|
||||||
|
@ -71,7 +71,7 @@ pub trait IsResolvedSocketAddr {
|
|||||||
|
|
||||||
impl IsResolvedSocketAddr for SocketAddr {
|
impl IsResolvedSocketAddr for SocketAddr {
|
||||||
fn resolve(&self) -> Option<&SocketAddr> {
|
fn resolve(&self) -> Option<&SocketAddr> {
|
||||||
Some(&self)
|
Some(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +120,12 @@ pub async fn connect_tcp_local<
|
|||||||
if let Some(target) = target.resolve() {
|
if let Some(target) = target.resolve() {
|
||||||
if let Some(local) = local {
|
if let Some(local) = local {
|
||||||
if local.is_ipv6() && target.is_ipv4() {
|
if local.is_ipv6() && target.is_ipv4() {
|
||||||
let target = query_nip_io(&target).await?;
|
let target = query_nip_io(target).await?;
|
||||||
return Ok(FramedStream::new(target, Some(local), ms_timeout).await?);
|
return FramedStream::new(target, Some(local), ms_timeout).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(FramedStream::new(target, local, ms_timeout).await?)
|
FramedStream::new(target, local, ms_timeout).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -140,15 +140,14 @@ pub fn is_ipv4(target: &TargetAddr<'_>) -> bool {
|
|||||||
pub async fn query_nip_io(addr: &SocketAddr) -> ResultType<SocketAddr> {
|
pub async fn query_nip_io(addr: &SocketAddr) -> ResultType<SocketAddr> {
|
||||||
tokio::net::lookup_host(format!("{}.nip.io:{}", addr.ip(), addr.port()))
|
tokio::net::lookup_host(format!("{}.nip.io:{}", addr.ip(), addr.port()))
|
||||||
.await?
|
.await?
|
||||||
.filter(|x| x.is_ipv6())
|
.find(|x| x.is_ipv6())
|
||||||
.next()
|
|
||||||
.context("Failed to get ipv6 from nip.io")
|
.context("Failed to get ipv6 from nip.io")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
|
pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
|
||||||
if !ipv4 && crate::is_ipv4_str(&addr) {
|
if !ipv4 && crate::is_ipv4_str(&addr) {
|
||||||
if let Some(ip) = addr.split(":").next() {
|
if let Some(ip) = addr.split(':').next() {
|
||||||
return addr.replace(ip, &format!("{}.nip.io", ip));
|
return addr.replace(ip, &format!("{}.nip.io", ip));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{bail, bytes_codec::BytesCodec, ResultType};
|
use crate::{bail, bytes_codec::BytesCodec, ResultType};
|
||||||
|
use anyhow::Context as AnyhowCtx;
|
||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
@ -209,7 +210,7 @@ impl FramedStream {
|
|||||||
if let Some(Ok(bytes)) = res.as_mut() {
|
if let Some(Ok(bytes)) = res.as_mut() {
|
||||||
key.2 += 1;
|
key.2 += 1;
|
||||||
let nonce = Self::get_nonce(key.2);
|
let nonce = Self::get_nonce(key.2);
|
||||||
match secretbox::open(&bytes, &nonce, &key.0) {
|
match secretbox::open(bytes, &nonce, &key.0) {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
bytes.clear();
|
bytes.clear();
|
||||||
bytes.put_slice(&res);
|
bytes.put_slice(&res);
|
||||||
@ -245,16 +246,17 @@ impl FramedStream {
|
|||||||
|
|
||||||
const DEFAULT_BACKLOG: u32 = 128;
|
const DEFAULT_BACKLOG: u32 = 128;
|
||||||
|
|
||||||
#[allow(clippy::never_loop)]
|
|
||||||
pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<TcpListener> {
|
pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<TcpListener> {
|
||||||
if !reuse {
|
if !reuse {
|
||||||
Ok(TcpListener::bind(addr).await?)
|
Ok(TcpListener::bind(addr).await?)
|
||||||
} else {
|
} else {
|
||||||
for addr in lookup_host(&addr).await? {
|
let addr = lookup_host(&addr)
|
||||||
let socket = new_socket(addr, true)?;
|
.await?
|
||||||
return Ok(socket.listen(DEFAULT_BACKLOG)?);
|
.next()
|
||||||
}
|
.context("could not resolve to any address")?;
|
||||||
bail!("could not resolve to any address");
|
new_socket(addr, true)?
|
||||||
|
.listen(DEFAULT_BACKLOG)
|
||||||
|
.map_err(anyhow::Error::msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::{bail, ResultType};
|
use crate::ResultType;
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use socket2::{Domain, Socket, Type};
|
use socket2::{Domain, Socket, Type};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use tokio::net::{ToSocketAddrs, UdpSocket};
|
use tokio::net::{lookup_host, ToSocketAddrs, UdpSocket};
|
||||||
use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs};
|
use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs};
|
||||||
use tokio_util::{codec::BytesCodec, udp::UdpFramed};
|
use tokio_util::{codec::BytesCodec, udp::UdpFramed};
|
||||||
|
|
||||||
@ -37,39 +37,31 @@ fn new_socket(addr: SocketAddr, reuse: bool, buf_size: usize) -> Result<Socket,
|
|||||||
addr,
|
addr,
|
||||||
socket.recv_buffer_size()
|
socket.recv_buffer_size()
|
||||||
);
|
);
|
||||||
|
if addr.is_ipv6() && addr.ip().is_unspecified() && addr.port() > 0 {
|
||||||
|
socket.set_only_v6(false).ok();
|
||||||
|
}
|
||||||
socket.bind(&addr.into())?;
|
socket.bind(&addr.into())?;
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FramedSocket {
|
impl FramedSocket {
|
||||||
pub async fn new<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
pub async fn new<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
||||||
let socket = UdpSocket::bind(addr).await?;
|
Self::new_reuse(addr, false, 0).await
|
||||||
Ok(Self::Direct(UdpFramed::new(socket, BytesCodec::new())))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::never_loop)]
|
pub async fn new_reuse<T: ToSocketAddrs>(
|
||||||
pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
|
||||||
for addr in addr.to_socket_addrs()? {
|
|
||||||
let socket = new_socket(addr, true, 0)?.into_udp_socket();
|
|
||||||
return Ok(Self::Direct(UdpFramed::new(
|
|
||||||
UdpSocket::from_std(socket)?,
|
|
||||||
BytesCodec::new(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
bail!("could not resolve to any address");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn new_with_buf_size<T: std::net::ToSocketAddrs>(
|
|
||||||
addr: T,
|
addr: T,
|
||||||
|
reuse: bool,
|
||||||
buf_size: usize,
|
buf_size: usize,
|
||||||
) -> ResultType<Self> {
|
) -> ResultType<Self> {
|
||||||
for addr in addr.to_socket_addrs()? {
|
let addr = lookup_host(&addr)
|
||||||
return Ok(Self::Direct(UdpFramed::new(
|
.await?
|
||||||
UdpSocket::from_std(new_socket(addr, false, buf_size)?.into_udp_socket())?,
|
.next()
|
||||||
|
.context("could not resolve to any address")?;
|
||||||
|
Ok(Self::Direct(UdpFramed::new(
|
||||||
|
UdpSocket::from_std(new_socket(addr, reuse, buf_size)?.into_udp_socket())?,
|
||||||
BytesCodec::new(),
|
BytesCodec::new(),
|
||||||
)));
|
)))
|
||||||
}
|
|
||||||
bail!("could not resolve to any address");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>(
|
pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>(
|
||||||
@ -104,11 +96,12 @@ impl FramedSocket {
|
|||||||
) -> ResultType<()> {
|
) -> ResultType<()> {
|
||||||
let addr = addr.into_target_addr()?.to_owned();
|
let addr = addr.into_target_addr()?.to_owned();
|
||||||
let send_data = Bytes::from(msg.write_to_bytes()?);
|
let send_data = Bytes::from(msg.write_to_bytes()?);
|
||||||
let _ = match self {
|
match self {
|
||||||
Self::Direct(f) => match addr {
|
Self::Direct(f) => {
|
||||||
TargetAddr::Ip(addr) => f.send((send_data, addr)).await?,
|
if let TargetAddr::Ip(addr) = addr {
|
||||||
_ => {}
|
f.send((send_data, addr)).await?
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Self::ProxySocks(f) => f.send((send_data, addr)).await?,
|
Self::ProxySocks(f) => f.send((send_data, addr)).await?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -123,11 +116,12 @@ impl FramedSocket {
|
|||||||
) -> ResultType<()> {
|
) -> ResultType<()> {
|
||||||
let addr = addr.into_target_addr()?.to_owned();
|
let addr = addr.into_target_addr()?.to_owned();
|
||||||
|
|
||||||
let _ = match self {
|
match self {
|
||||||
Self::Direct(f) => match addr {
|
Self::Direct(f) => {
|
||||||
TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?,
|
if let TargetAddr::Ip(addr) = addr {
|
||||||
_ => {}
|
f.send((Bytes::from(msg), addr)).await?
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
|
Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -165,12 +159,12 @@ impl FramedSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ipv4(&self) -> bool {
|
pub fn local_addr(&self) -> Option<SocketAddr> {
|
||||||
if let FramedSocket::Direct(x) = self {
|
if let FramedSocket::Direct(x) = self {
|
||||||
if let Ok(v) = x.get_ref().local_addr() {
|
if let Ok(v) = x.get_ref().local_addr() {
|
||||||
return v.is_ipv4();
|
return Some(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2083,6 +2083,7 @@ pub fn check_if_retry(msgtype: &str, title: &str, text: &str, retry_for_relay: b
|
|||||||
&& !text.to_lowercase().contains("mismatch")
|
&& !text.to_lowercase().contains("mismatch")
|
||||||
&& !text.to_lowercase().contains("manually")
|
&& !text.to_lowercase().contains("manually")
|
||||||
&& !text.to_lowercase().contains("not allowed")
|
&& !text.to_lowercase().contains("not allowed")
|
||||||
|
&& !text.to_lowercase().contains("as expected")
|
||||||
&& !text.to_lowercase().contains("reset by the peer")))
|
&& !text.to_lowercase().contains("reset by the peer")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +245,14 @@ pub fn session_get_keyboard_mode(id: String) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn session_set_keyboard_mode(id: String, value: String) {
|
pub fn session_set_keyboard_mode(id: String, value: String) {
|
||||||
|
let mut _mode_updated = false;
|
||||||
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) {
|
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) {
|
||||||
session.save_keyboard_mode(value);
|
session.save_keyboard_mode(value);
|
||||||
|
_mode_updated = true;
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
if _mode_updated {
|
||||||
|
crate::keyboard::update_grab_get_key_name();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,7 +1188,9 @@ pub fn main_update_me() -> SyncReturn<bool> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cur_session_id(id: String) {
|
pub fn set_cur_session_id(id: String) {
|
||||||
super::flutter::set_cur_session_id(id)
|
super::flutter::set_cur_session_id(id);
|
||||||
|
#[cfg(windows)]
|
||||||
|
crate::keyboard::update_grab_get_key_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_show_run_without_install() -> SyncReturn<bool> {
|
pub fn install_show_run_without_install() -> SyncReturn<bool> {
|
||||||
|
@ -64,6 +64,8 @@ pub mod client {
|
|||||||
match state {
|
match state {
|
||||||
GrabState::Ready => {}
|
GrabState::Ready => {}
|
||||||
GrabState::Run => {
|
GrabState::Run => {
|
||||||
|
#[cfg(windows)]
|
||||||
|
update_grab_get_key_name();
|
||||||
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||||
KEYBOARD_HOOKED.swap(true, Ordering::SeqCst);
|
KEYBOARD_HOOKED.swap(true, Ordering::SeqCst);
|
||||||
|
|
||||||
@ -184,6 +186,15 @@ pub mod client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn update_grab_get_key_name() {
|
||||||
|
match get_keyboard_mode_enum() {
|
||||||
|
KeyboardMode::Map => rdev::set_get_key_name(false),
|
||||||
|
KeyboardMode::Translate => rdev::set_get_key_name(true),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_grab_loop() {
|
pub fn start_grab_loop() {
|
||||||
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "添加到地址簿"),
|
("Add to Address Book", "添加到地址簿"),
|
||||||
("Group", "小组"),
|
("Group", "小组"),
|
||||||
("Search", "搜索"),
|
("Search", "搜索"),
|
||||||
("Closed manually by the web console", "被web控制台手动关闭"),
|
("Closed manually by web console", "被web控制台手动关闭"),
|
||||||
("Local keyboard type", "本地键盘类型"),
|
("Local keyboard type", "本地键盘类型"),
|
||||||
("Select local keyboard type", "请选择本地键盘类型"),
|
("Select local keyboard type", "请选择本地键盘类型"),
|
||||||
("software_render_tip", "如果你使用英伟达显卡, 并且远程窗口在会话建立后会立刻关闭, 那么安装nouveau驱动并且选择使用软件渲染可能会有帮助。重启软件后生效。"),
|
("software_render_tip", "如果你使用英伟达显卡, 并且远程窗口在会话建立后会立刻关闭, 那么安装nouveau驱动并且选择使用软件渲染可能会有帮助。重启软件后生效。"),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "强"),
|
("Strong", "强"),
|
||||||
("Switch Sides", "反转访问方向"),
|
("Switch Sides", "反转访问方向"),
|
||||||
("Please confirm if you want to share your desktop?", "请确认要让对方访问你的桌面?"),
|
("Please confirm if you want to share your desktop?", "请确认要让对方访问你的桌面?"),
|
||||||
|
("Closed as expected", "正常关闭"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Zum Adressbuch hinzufügen"),
|
("Add to Address Book", "Zum Adressbuch hinzufügen"),
|
||||||
("Group", "Gruppe"),
|
("Group", "Gruppe"),
|
||||||
("Search", "Suchen"),
|
("Search", "Suchen"),
|
||||||
("Closed manually by the web console", "Manuell über die Webkonsole beendet"),
|
("Closed manually by web console", "Manuell über die Webkonsole beendet"),
|
||||||
("Local keyboard type", "Lokaler Tastaturtyp"),
|
("Local keyboard type", "Lokaler Tastaturtyp"),
|
||||||
("Select local keyboard type", "Lokalen Tastaturtyp auswählen"),
|
("Select local keyboard type", "Lokalen Tastaturtyp auswählen"),
|
||||||
("software_render_tip", "Wenn Sie eine Nvidia-Grafikkarte haben und sich das entfernte Fenster sofort nach dem Herstellen der Verbindung schließt, kann es helfen, den Nouveau-Treiber zu installieren und Software-Rendering zu verwenden. Ein Neustart der Software ist erforderlich."),
|
("software_render_tip", "Wenn Sie eine Nvidia-Grafikkarte haben und sich das entfernte Fenster sofort nach dem Herstellen der Verbindung schließt, kann es helfen, den Nouveau-Treiber zu installieren und Software-Rendering zu verwenden. Ein Neustart der Software ist erforderlich."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "Stark"),
|
("Strong", "Stark"),
|
||||||
("Switch Sides", "Seiten wechseln"),
|
("Switch Sides", "Seiten wechseln"),
|
||||||
("Please confirm if you want to share your desktop?", "Bitte bestätigen Sie, ob Sie Ihren Desktop freigeben möchten."),
|
("Please confirm if you want to share your desktop?", "Bitte bestätigen Sie, ob Sie Ihren Desktop freigeben möchten."),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Añadir a la libreta de direcciones"),
|
("Add to Address Book", "Añadir a la libreta de direcciones"),
|
||||||
("Group", "Grupo"),
|
("Group", "Grupo"),
|
||||||
("Search", "Búsqueda"),
|
("Search", "Búsqueda"),
|
||||||
("Closed manually by the web console", "Cerrado manualmente por la consola web"),
|
("Closed manually by web console", "Cerrado manualmente por la consola web"),
|
||||||
("Local keyboard type", "Tipo de teclado local"),
|
("Local keyboard type", "Tipo de teclado local"),
|
||||||
("Select local keyboard type", "Seleccionar tipo de teclado local"),
|
("Select local keyboard type", "Seleccionar tipo de teclado local"),
|
||||||
("software_render_tip", "Si tienes una gráfica Nvidia y la ventana remota se cierra inmediatamente, instalar el driver nouveau y elegir renderizado por software podría ayudar. Se requiere reiniciar la aplicación."),
|
("software_render_tip", "Si tienes una gráfica Nvidia y la ventana remota se cierra inmediatamente, instalar el driver nouveau y elegir renderizado por software podría ayudar. Se requiere reiniciar la aplicación."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "Fuerte"),
|
("Strong", "Fuerte"),
|
||||||
("Switch Sides", "Intercambiar lados"),
|
("Switch Sides", "Intercambiar lados"),
|
||||||
("Please confirm if you want to share your desktop?", "Por favor, confirma si quieres compartir tu escritorio"),
|
("Please confirm if you want to share your desktop?", "Por favor, confirma si quieres compartir tu escritorio"),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "افزودن به دفترچه آدرس"),
|
("Add to Address Book", "افزودن به دفترچه آدرس"),
|
||||||
("Group", "گروه"),
|
("Group", "گروه"),
|
||||||
("Search", "جستجو"),
|
("Search", "جستجو"),
|
||||||
("Closed manually by the web console", "به صورت دستی توسط کنسول وب بسته شد"),
|
("Closed manually by web console", "به صورت دستی توسط کنسول وب بسته شد"),
|
||||||
("Local keyboard type", "نوع صفحه کلید محلی"),
|
("Local keyboard type", "نوع صفحه کلید محلی"),
|
||||||
("Select local keyboard type", "نوع صفحه کلید محلی را انتخاب کنید"),
|
("Select local keyboard type", "نوع صفحه کلید محلی را انتخاب کنید"),
|
||||||
("software_render_tip", "اگر کارت گرافیک Nvidia دارید و پنجره راه دور بلافاصله پس از اتصال بسته می شود، درایور nouveau را نصب نمایید و انتخاب گزینه استفاده از رندر نرم افزار می تواند کمک کننده باشد. راه اندازی مجدد نرم افزار مورد نیاز است."),
|
("software_render_tip", "اگر کارت گرافیک Nvidia دارید و پنجره راه دور بلافاصله پس از اتصال بسته می شود، درایور nouveau را نصب نمایید و انتخاب گزینه استفاده از رندر نرم افزار می تواند کمک کننده باشد. راه اندازی مجدد نرم افزار مورد نیاز است."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "قوی"),
|
("Strong", "قوی"),
|
||||||
("Switch Sides", "طرفین را عوض کنید"),
|
("Switch Sides", "طرفین را عوض کنید"),
|
||||||
("Please confirm if you want to share your desktop?", "لطفاً تأیید کنید که آیا می خواهید دسکتاپ خود را به اشتراک بگذارید؟"),
|
("Please confirm if you want to share your desktop?", "لطفاً تأیید کنید که آیا می خواهید دسکتاپ خود را به اشتراک بگذارید؟"),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -77,10 +77,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."),
|
("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."),
|
||||||
("Name", "Nom"),
|
("Name", "Nom"),
|
||||||
("Type", "Type"),
|
("Type", "Type"),
|
||||||
("Modified", "Modifié"),
|
("Modified", "Modifié le"),
|
||||||
("Size", "Taille"),
|
("Size", "Taille"),
|
||||||
("Show Hidden Files", "Afficher les fichiers cachés"),
|
("Show Hidden Files", "Afficher les fichiers cachés"),
|
||||||
("Receive", "Accepter"),
|
("Receive", "Recevoir"),
|
||||||
("Send", "Envoyer"),
|
("Send", "Envoyer"),
|
||||||
("Refresh File", "Actualiser le fichier"),
|
("Refresh File", "Actualiser le fichier"),
|
||||||
("Local", "Local"),
|
("Local", "Local"),
|
||||||
@ -90,7 +90,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Confirm Delete", "Confirmer la suppression"),
|
("Confirm Delete", "Confirmer la suppression"),
|
||||||
("Delete", "Supprimer"),
|
("Delete", "Supprimer"),
|
||||||
("Properties", "Propriétés"),
|
("Properties", "Propriétés"),
|
||||||
("Multi Select", "Choix multiple"),
|
("Multi Select", "Sélection multiple"),
|
||||||
("Select All", "Tout sélectionner"),
|
("Select All", "Tout sélectionner"),
|
||||||
("Unselect All", "Tout déselectionner"),
|
("Unselect All", "Tout déselectionner"),
|
||||||
("Empty Directory", "Répertoire vide"),
|
("Empty Directory", "Répertoire vide"),
|
||||||
@ -208,7 +208,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Run without install", "Exécuter sans installer"),
|
("Run without install", "Exécuter sans installer"),
|
||||||
("Always connected via relay", "Forcer la connexion relais"),
|
("Always connected via relay", "Forcer la connexion relais"),
|
||||||
("Always connect via relay", "Forcer la connexion relais"),
|
("Always connect via relay", "Forcer la connexion relais"),
|
||||||
("whitelist_tip", "Seul l'IP dans la liste blanche peut accéder à mon appareil"),
|
("whitelist_tip", "Seule une IP de la liste blanche peut accéder à mon appareil"),
|
||||||
("Login", "Connexion"),
|
("Login", "Connexion"),
|
||||||
("Verify", "Vérifier"),
|
("Verify", "Vérifier"),
|
||||||
("Remember me", "Se souvenir de moi"),
|
("Remember me", "Se souvenir de moi"),
|
||||||
@ -269,7 +269,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Chat", "Discuter"),
|
("Chat", "Discuter"),
|
||||||
("Total", "Total"),
|
("Total", "Total"),
|
||||||
("items", "éléments"),
|
("items", "éléments"),
|
||||||
("Selected", "Choisi"),
|
("Selected", "Sélectionné"),
|
||||||
("Screen Capture", "Capture d'écran"),
|
("Screen Capture", "Capture d'écran"),
|
||||||
("Input Control", "Contrôle de saisie"),
|
("Input Control", "Contrôle de saisie"),
|
||||||
("Audio Capture", "Capture audio"),
|
("Audio Capture", "Capture audio"),
|
||||||
@ -303,7 +303,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("In privacy mode", "en mode privé"),
|
("In privacy mode", "en mode privé"),
|
||||||
("Out privacy mode", "hors mode de confidentialité"),
|
("Out privacy mode", "hors mode de confidentialité"),
|
||||||
("Language", "Langue"),
|
("Language", "Langue"),
|
||||||
("Keep RustDesk background service", "Gardez le service RustDesk service arrière plan"),
|
("Keep RustDesk background service", "Gardez le service RustDesk en arrière plan"),
|
||||||
("Ignore Battery Optimizations", "Ignorer les optimisations batterie"),
|
("Ignore Battery Optimizations", "Ignorer les optimisations batterie"),
|
||||||
("android_open_battery_optimizations_tip", "Conseil android d'optimisation de batterie"),
|
("android_open_battery_optimizations_tip", "Conseil android d'optimisation de batterie"),
|
||||||
("Connection not allowed", "Connexion non autorisée"),
|
("Connection not allowed", "Connexion non autorisée"),
|
||||||
@ -356,14 +356,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Clear", "Effacer"),
|
("Clear", "Effacer"),
|
||||||
("Audio Input Device", "Périphérique source audio"),
|
("Audio Input Device", "Périphérique source audio"),
|
||||||
("Deny remote access", "Interdir l'accès distant"),
|
("Deny remote access", "Interdir l'accès distant"),
|
||||||
("Use IP Whitelisting", "Utiliser liste blanche d'IP"),
|
("Use IP Whitelisting", "Utiliser une liste blanche d'IP"),
|
||||||
("Network", "Réseau"),
|
("Network", "Réseau"),
|
||||||
("Enable RDP", "Activer RDP"),
|
("Enable RDP", "Activer RDP"),
|
||||||
("Pin menubar", "Épingler la barre de menus"),
|
("Pin menubar", "Épingler la barre de menus"),
|
||||||
("Unpin menubar", "Détacher la barre de menu"),
|
("Unpin menubar", "Détacher la barre de menu"),
|
||||||
("Recording", "Enregistrement"),
|
("Recording", "Enregistrement"),
|
||||||
("Directory", "Répertoire"),
|
("Directory", "Répertoire"),
|
||||||
("Automatically record incoming sessions", "Enregistrement automatique des session entrantes"),
|
("Automatically record incoming sessions", "Enregistrement automatique des sessions entrantes"),
|
||||||
("Change", "Modifier"),
|
("Change", "Modifier"),
|
||||||
("Start session recording", "Commencer l'enregistrement"),
|
("Start session recording", "Commencer l'enregistrement"),
|
||||||
("Stop session recording", "Stopper l'enregistrement"),
|
("Stop session recording", "Stopper l'enregistrement"),
|
||||||
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Ajouter au carnet d'adresses"),
|
("Add to Address Book", "Ajouter au carnet d'adresses"),
|
||||||
("Group", "Groupe"),
|
("Group", "Groupe"),
|
||||||
("Search", "Rechercher"),
|
("Search", "Rechercher"),
|
||||||
("Closed manually by the web console", "Fermé manuellement par la console Web"),
|
("Closed manually by web console", "Fermé manuellement par la console Web"),
|
||||||
("Local keyboard type", "Disposition du clavier local"),
|
("Local keyboard type", "Disposition du clavier local"),
|
||||||
("Select local keyboard type", "Selectionner la disposition du clavier local"),
|
("Select local keyboard type", "Selectionner la disposition du clavier local"),
|
||||||
("software_render_tip", "Si vous avez une carte graphique NVIDIA et que la fenêtre distante se ferme immédiatement après la connexion, l'installation du pilote Nouveau et le choix d'utiliser le rendu du logiciel peuvent aider. Un redémarrage du logiciel est requis."),
|
("software_render_tip", "Si vous avez une carte graphique NVIDIA et que la fenêtre distante se ferme immédiatement après la connexion, l'installation du pilote Nouveau et le choix d'utiliser le rendu du logiciel peuvent aider. Un redémarrage du logiciel est requis."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "Fort"),
|
("Strong", "Fort"),
|
||||||
("Switch Sides", "Inverser la prise de contrôle"),
|
("Switch Sides", "Inverser la prise de contrôle"),
|
||||||
("Please confirm if you want to share your desktop?", "Veuillez confirmer le partager de votre bureau ?"),
|
("Please confirm if you want to share your desktop?", "Veuillez confirmer le partager de votre bureau ?"),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Προσθήκη στο Βιβλίο Διευθύνσεων"),
|
("Add to Address Book", "Προσθήκη στο Βιβλίο Διευθύνσεων"),
|
||||||
("Group", "Ομάδα"),
|
("Group", "Ομάδα"),
|
||||||
("Search", "Αναζήτηση"),
|
("Search", "Αναζήτηση"),
|
||||||
("Closed manually by the web console", "Κλειστό χειροκίνητα από την κονσόλα web"),
|
("Closed manually by web console", "Κλειστό χειροκίνητα από την κονσόλα web"),
|
||||||
("Local keyboard type", "Τύπος τοπικού πληκτρολογίου"),
|
("Local keyboard type", "Τύπος τοπικού πληκτρολογίου"),
|
||||||
("Select local keyboard type", "Επιλογή τύπου τοπικού πληκτρολογίου"),
|
("Select local keyboard type", "Επιλογή τύπου τοπικού πληκτρολογίου"),
|
||||||
("software_render_tip", "Εάν έχετε κάρτα γραφικών Nvidia και το παράθυρο σύνδεσης κλείνει αμέσως μετά τη σύνδεση, η εγκατάσταση του προγράμματος οδήγησης nouveau και η επιλογή χρήσης της επιτάχυνσης γραφικών μέσω λογισμικού μπορεί να βοηθήσει. Απαιτείται επανεκκίνηση."),
|
("software_render_tip", "Εάν έχετε κάρτα γραφικών Nvidia και το παράθυρο σύνδεσης κλείνει αμέσως μετά τη σύνδεση, η εγκατάσταση του προγράμματος οδήγησης nouveau και η επιλογή χρήσης της επιτάχυνσης γραφικών μέσω λογισμικού μπορεί να βοηθήσει. Απαιτείται επανεκκίνηση."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "Δυνατό"),
|
("Strong", "Δυνατό"),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", "Pencarian"),
|
("Search", "Pencarian"),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Aggiungi alla rubrica"),
|
("Add to Address Book", "Aggiungi alla rubrica"),
|
||||||
("Group", "Gruppo"),
|
("Group", "Gruppo"),
|
||||||
("Search", "Cerca"),
|
("Search", "Cerca"),
|
||||||
("Closed manually by the web console", "Chiudi manualmente dalla console Web"),
|
("Closed manually by web console", "Chiudi manualmente dalla console Web"),
|
||||||
("Local keyboard type", "Tipo di tastiera locale"),
|
("Local keyboard type", "Tipo di tastiera locale"),
|
||||||
("Select local keyboard type", "Seleziona il tipo di tastiera locale"),
|
("Select local keyboard type", "Seleziona il tipo di tastiera locale"),
|
||||||
("software_render_tip", "Se si dispone di una scheda grafica Nvidia e la finestra remota si chiude immediatamente dopo la connessione, l'installazione del driver nouveau e la scelta di utilizzare il rendering software possono aiutare. È necessario un riavvio del software."),
|
("software_render_tip", "Se si dispone di una scheda grafica Nvidia e la finestra remota si chiude immediatamente dopo la connessione, l'installazione del driver nouveau e la scelta di utilizzare il rendering software possono aiutare. È necessario un riavvio del software."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "Forte"),
|
("Strong", "Forte"),
|
||||||
("Switch Sides", "Cambia lato"),
|
("Switch Sides", "Cambia lato"),
|
||||||
("Please confirm if you want to share your desktop?", "Vuoi condividere il tuo desktop?"),
|
("Please confirm if you want to share your desktop?", "Vuoi condividere il tuo desktop?"),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Dodaj do Książki Adresowej"),
|
("Add to Address Book", "Dodaj do Książki Adresowej"),
|
||||||
("Group", "Grypy"),
|
("Group", "Grypy"),
|
||||||
("Search", "Szukaj"),
|
("Search", "Szukaj"),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Change ID", "Schimbă ID"),
|
("Change ID", "Schimbă ID"),
|
||||||
("Website", "Site web"),
|
("Website", "Site web"),
|
||||||
("About", "Despre"),
|
("About", "Despre"),
|
||||||
|
("Slogan_tip", ""),
|
||||||
|
("Privacy Statement", ""),
|
||||||
("Mute", "Fără sunet"),
|
("Mute", "Fără sunet"),
|
||||||
("Audio Input", "Intrare audio"),
|
("Audio Input", "Intrare audio"),
|
||||||
("Enhancements", "Îmbunătățiri"),
|
("Enhancements", "Îmbunătățiri"),
|
||||||
@ -116,7 +118,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Good image quality", "Calitate bună a imaginii"),
|
("Good image quality", "Calitate bună a imaginii"),
|
||||||
("Balanced", "Calitate normală a imaginii"),
|
("Balanced", "Calitate normală a imaginii"),
|
||||||
("Optimize reaction time", "Optimizează timpul de reacție"),
|
("Optimize reaction time", "Optimizează timpul de reacție"),
|
||||||
("Custom", "Personalizare"),
|
("Custom", "Personalizat"),
|
||||||
("Show remote cursor", "Afișează cursor la distanță"),
|
("Show remote cursor", "Afișează cursor la distanță"),
|
||||||
("Show quality monitor", "Afișează indicator de calitate"),
|
("Show quality monitor", "Afișează indicator de calitate"),
|
||||||
("Disable clipboard", "Dezactivează clipboard"),
|
("Disable clipboard", "Dezactivează clipboard"),
|
||||||
@ -208,6 +210,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Always connect via relay", "Se conectează mereu prin retransmisie"),
|
("Always connect via relay", "Se conectează mereu prin retransmisie"),
|
||||||
("whitelist_tip", "Doar adresele IP autorizate pot accesa acest dispozitiv"),
|
("whitelist_tip", "Doar adresele IP autorizate pot accesa acest dispozitiv"),
|
||||||
("Login", "Conectare"),
|
("Login", "Conectare"),
|
||||||
|
("Verify", ""),
|
||||||
|
("Remember me", ""),
|
||||||
|
("Trust this device", ""),
|
||||||
|
("Verification code", ""),
|
||||||
|
("verification_tip", ""),
|
||||||
("Logout", "Deconectare"),
|
("Logout", "Deconectare"),
|
||||||
("Tags", "Etichetare"),
|
("Tags", "Etichetare"),
|
||||||
("Search ID", "Caută după ID"),
|
("Search ID", "Caută după ID"),
|
||||||
@ -332,7 +339,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Scale adaptive", "Scală adaptivă"),
|
("Scale adaptive", "Scală adaptivă"),
|
||||||
("General", "General"),
|
("General", "General"),
|
||||||
("Security", "Securitate"),
|
("Security", "Securitate"),
|
||||||
("Account", "Cont"),
|
|
||||||
("Theme", "Temă"),
|
("Theme", "Temă"),
|
||||||
("Dark Theme", "Temă întunecată"),
|
("Dark Theme", "Temă întunecată"),
|
||||||
("Dark", "Întunecat"),
|
("Dark", "Întunecat"),
|
||||||
@ -345,7 +351,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Server", "Server"),
|
("Server", "Server"),
|
||||||
("Direct IP Access", "Acces direct IP"),
|
("Direct IP Access", "Acces direct IP"),
|
||||||
("Proxy", "Proxy"),
|
("Proxy", "Proxy"),
|
||||||
("Port", "Port"),
|
|
||||||
("Apply", "Aplică"),
|
("Apply", "Aplică"),
|
||||||
("Disconnect all devices?", "Vrei să deconectezi toate dispozitivele?"),
|
("Disconnect all devices?", "Vrei să deconectezi toate dispozitivele?"),
|
||||||
("Clear", "Golește"),
|
("Clear", "Golește"),
|
||||||
@ -374,7 +379,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Other", "Altele"),
|
("Other", "Altele"),
|
||||||
("Confirm before closing multiple tabs", "Confirmă înainte de a închide mai multe file"),
|
("Confirm before closing multiple tabs", "Confirmă înainte de a închide mai multe file"),
|
||||||
("Keyboard Settings", "Configurare tastatură"),
|
("Keyboard Settings", "Configurare tastatură"),
|
||||||
("Custom", "Personalizat"),
|
|
||||||
("Full Access", "Acces total"),
|
("Full Access", "Acces total"),
|
||||||
("Screen Share", "Partajare ecran"),
|
("Screen Share", "Partajare ecran"),
|
||||||
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland necesită Ubuntu 21.04 sau o versiune superioară."),
|
("Wayland requires Ubuntu 21.04 or higher version.", "Wayland necesită Ubuntu 21.04 sau o versiune superioară."),
|
||||||
@ -397,5 +401,38 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Request access to your device", "Solicită acces la dispozitivul tău"),
|
("Request access to your device", "Solicită acces la dispozitivul tău"),
|
||||||
("Hide connection management window", "Ascunde fereastra de gestionare a conexiunilor"),
|
("Hide connection management window", "Ascunde fereastra de gestionare a conexiunilor"),
|
||||||
("hide_cm_tip", "Permite ascunderea ferestrei de gestionare doar dacă accepți începerea sesiunilor folosind parola permanentă"),
|
("hide_cm_tip", "Permite ascunderea ferestrei de gestionare doar dacă accepți începerea sesiunilor folosind parola permanentă"),
|
||||||
|
("wayland_experiment_tip", ""),
|
||||||
|
("Right click to select tabs", ""),
|
||||||
|
("Skipped", ""),
|
||||||
|
("Add to Address Book", ""),
|
||||||
|
("Group", ""),
|
||||||
|
("Search", ""),
|
||||||
|
("Closed manually by web console", ""),
|
||||||
|
("Local keyboard type", ""),
|
||||||
|
("Select local keyboard type", ""),
|
||||||
|
("software_render_tip", ""),
|
||||||
|
("Always use software rendering", ""),
|
||||||
|
("config_input", ""),
|
||||||
|
("request_elevation_tip", ""),
|
||||||
|
("Wait", ""),
|
||||||
|
("Elevation Error", ""),
|
||||||
|
("Ask the remote user for authentication", ""),
|
||||||
|
("Choose this if the remote account is administrator", ""),
|
||||||
|
("Transmit the username and password of administrator", ""),
|
||||||
|
("still_click_uac_tip", ""),
|
||||||
|
("Request Elevation", ""),
|
||||||
|
("wait_accept_uac_tip", ""),
|
||||||
|
("Elevate successfully", ""),
|
||||||
|
("uppercase", ""),
|
||||||
|
("lowercase", ""),
|
||||||
|
("digit", ""),
|
||||||
|
("special character", ""),
|
||||||
|
("length>=8", ""),
|
||||||
|
("Weak", ""),
|
||||||
|
("Medium", ""),
|
||||||
|
("Strong", ""),
|
||||||
|
("Switch Sides", ""),
|
||||||
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Добавить в адресную книгу"),
|
("Add to Address Book", "Добавить в адресную книгу"),
|
||||||
("Group", "Группа"),
|
("Group", "Группа"),
|
||||||
("Search", "Поиск"),
|
("Search", "Поиск"),
|
||||||
("Closed manually by the web console", "Закрыто вручную через веб-консоль"),
|
("Closed manually by web console", "Закрыто вручную через веб-консоль"),
|
||||||
("Local keyboard type", "Тип локальной клавиатуры"),
|
("Local keyboard type", "Тип локальной клавиатуры"),
|
||||||
("Select local keyboard type", "Выберите тип локальной клавиатуры"),
|
("Select local keyboard type", "Выберите тип локальной клавиатуры"),
|
||||||
("software_render_tip", "Если у вас видеокарта Nvidia и удалённое окно закрывается сразу после подключения, может помочь установка драйвера Nouveau и выбор использования программной визуализации. Потребуется перезапуск."),
|
("software_render_tip", "Если у вас видеокарта Nvidia и удалённое окно закрывается сразу после подключения, может помочь установка драйвера Nouveau и выбор использования программной визуализации. Потребуется перезапуск."),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "Стойкий"),
|
("Strong", "Стойкий"),
|
||||||
("Switch Sides", "Переключить стороны"),
|
("Switch Sides", "Переключить стороны"),
|
||||||
("Please confirm if you want to share your desktop?", "Подтвердите, что хотите поделиться своим рабочим столом?"),
|
("Please confirm if you want to share your desktop?", "Подтвердите, что хотите поделиться своим рабочим столом?"),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Dodaj v adresar"),
|
("Add to Address Book", "Dodaj v adresar"),
|
||||||
("Group", "Skupina"),
|
("Group", "Skupina"),
|
||||||
("Search", "Iskanje"),
|
("Search", "Iskanje"),
|
||||||
("Closed manually by the web console", "Ročno zaprto iz spletne konzole"),
|
("Closed manually by web console", "Ročno zaprto iz spletne konzole"),
|
||||||
("Local keyboard type", "Lokalna vrsta tipkovnice"),
|
("Local keyboard type", "Lokalna vrsta tipkovnice"),
|
||||||
("Select local keyboard type", "Izberite lokalno vrsto tipkovnice"),
|
("Select local keyboard type", "Izberite lokalno vrsto tipkovnice"),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Dodaj u adresar"),
|
("Add to Address Book", "Dodaj u adresar"),
|
||||||
("Group", "Grupa"),
|
("Group", "Grupa"),
|
||||||
("Search", "Pretraga"),
|
("Search", "Pretraga"),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "เพิ่มไปยังสมุดรายชื่อ"),
|
("Add to Address Book", "เพิ่มไปยังสมุดรายชื่อ"),
|
||||||
("Group", "กลุ่ม"),
|
("Group", "กลุ่ม"),
|
||||||
("Search", "ค้นหา"),
|
("Search", "ค้นหา"),
|
||||||
("Closed manually by the web console", "ถูกปิดโดยเว็บคอนโซล"),
|
("Closed manually by web console", "ถูกปิดโดยเว็บคอนโซล"),
|
||||||
("Local keyboard type", "ประเภทคีย์บอร์ด"),
|
("Local keyboard type", "ประเภทคีย์บอร์ด"),
|
||||||
("Select local keyboard type", "เลือกประเภทคีย์บอร์ด"),
|
("Select local keyboard type", "เลือกประเภทคีย์บอร์ด"),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "添加到地址簿"),
|
("Add to Address Book", "添加到地址簿"),
|
||||||
("Group", "小組"),
|
("Group", "小組"),
|
||||||
("Search", "搜索"),
|
("Search", "搜索"),
|
||||||
("Closed manually by the web console", "被web控制台手動關閉"),
|
("Closed manually by web console", "被web控制台手動關閉"),
|
||||||
("Local keyboard type", "本地鍵盤類型"),
|
("Local keyboard type", "本地鍵盤類型"),
|
||||||
("Select local keyboard type", "請選擇本地鍵盤類型"),
|
("Select local keyboard type", "請選擇本地鍵盤類型"),
|
||||||
("software_render_tip", "如果你使用英偉達顯卡, 並且遠程窗口在會話建立後會立刻關閉, 那麼安裝nouveau驅動並且選擇使用軟件渲染可能會有幫助。重啟軟件後生效。"),
|
("software_render_tip", "如果你使用英偉達顯卡, 並且遠程窗口在會話建立後會立刻關閉, 那麼安裝nouveau驅動並且選擇使用軟件渲染可能會有幫助。重啟軟件後生效。"),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", "強"),
|
("Strong", "強"),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", "正常關閉"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", "Додати IP до Адресної книги"),
|
("Add to Address Book", "Додати IP до Адресної книги"),
|
||||||
("Group", "Група"),
|
("Group", "Група"),
|
||||||
("Search", "Пошук"),
|
("Search", "Пошук"),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Add to Address Book", ""),
|
("Add to Address Book", ""),
|
||||||
("Group", ""),
|
("Group", ""),
|
||||||
("Search", ""),
|
("Search", ""),
|
||||||
("Closed manually by the web console", ""),
|
("Closed manually by web console", ""),
|
||||||
("Local keyboard type", ""),
|
("Local keyboard type", ""),
|
||||||
("Select local keyboard type", ""),
|
("Select local keyboard type", ""),
|
||||||
("software_render_tip", ""),
|
("software_render_tip", ""),
|
||||||
@ -433,5 +433,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Strong", ""),
|
("Strong", ""),
|
||||||
("Switch Sides", ""),
|
("Switch Sides", ""),
|
||||||
("Please confirm if you want to share your desktop?", ""),
|
("Please confirm if you want to share your desktop?", ""),
|
||||||
|
("Closed as expected", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -839,6 +839,11 @@ pub fn check_update_broker_process() -> ResultType<()> {
|
|||||||
let cur_dir = exe_file.parent().unwrap();
|
let cur_dir = exe_file.parent().unwrap();
|
||||||
let cur_exe = cur_dir.join(process_exe);
|
let cur_exe = cur_dir.join(process_exe);
|
||||||
|
|
||||||
|
if !std::path::Path::new(&cur_exe).exists() {
|
||||||
|
std::fs::copy(origin_process_exe, cur_exe)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let ori_modified = fs::metadata(origin_process_exe)?.modified()?;
|
let ori_modified = fs::metadata(origin_process_exe)?.modified()?;
|
||||||
if let Ok(metadata) = fs::metadata(&cur_exe) {
|
if let Ok(metadata) = fs::metadata(&cur_exe) {
|
||||||
if let Ok(cur_modified) = metadata.modified() {
|
if let Ok(cur_modified) = metadata.modified() {
|
||||||
|
@ -101,7 +101,6 @@ pub struct Connection {
|
|||||||
lr: LoginRequest,
|
lr: LoginRequest,
|
||||||
last_recv_time: Arc<Mutex<Instant>>,
|
last_recv_time: Arc<Mutex<Instant>>,
|
||||||
chat_unanswered: bool,
|
chat_unanswered: bool,
|
||||||
close_manually: bool,
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
elevation_requested: bool,
|
elevation_requested: bool,
|
||||||
from_switch: bool,
|
from_switch: bool,
|
||||||
@ -200,7 +199,6 @@ impl Connection {
|
|||||||
lr: Default::default(),
|
lr: Default::default(),
|
||||||
last_recv_time: Arc::new(Mutex::new(Instant::now())),
|
last_recv_time: Arc::new(Mutex::new(Instant::now())),
|
||||||
chat_unanswered: false,
|
chat_unanswered: false,
|
||||||
close_manually: false,
|
|
||||||
elevation_requested: false,
|
elevation_requested: false,
|
||||||
from_switch: false,
|
from_switch: false,
|
||||||
};
|
};
|
||||||
@ -271,7 +269,9 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ipc::Data::Close => {
|
ipc::Data::Close => {
|
||||||
conn.on_close_manually("connection manager", "peer").await;
|
conn.chat_unanswered = false; // seen
|
||||||
|
conn.send_close_reason_no_retry("").await;
|
||||||
|
conn.on_close("connection manager", true).await;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ipc::Data::ChatMessage{text} => {
|
ipc::Data::ChatMessage{text} => {
|
||||||
@ -411,7 +411,8 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
Ok(conns) = hbbs_rx.recv() => {
|
Ok(conns) = hbbs_rx.recv() => {
|
||||||
if conns.contains(&id) {
|
if conns.contains(&id) {
|
||||||
conn.on_close_manually("web console", "web console").await;
|
conn.send_close_reason_no_retry("Closed manually by web console").await;
|
||||||
|
conn.on_close("web console", true).await;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,7 +442,8 @@ impl Connection {
|
|||||||
Some(message::Union::Misc(m)) => {
|
Some(message::Union::Misc(m)) => {
|
||||||
match &m.union {
|
match &m.union {
|
||||||
Some(misc::Union::StopService(_)) => {
|
Some(misc::Union::StopService(_)) => {
|
||||||
conn.on_close_manually("stop service", "peer").await;
|
conn.send_close_reason_no_retry("").await;
|
||||||
|
conn.on_close("stop service", true).await;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -540,6 +542,9 @@ impl Connection {
|
|||||||
"action": "close",
|
"action": "close",
|
||||||
}));
|
}));
|
||||||
ALIVE_CONNS.lock().unwrap().retain(|&c| c != id);
|
ALIVE_CONNS.lock().unwrap().retain(|&c| c != id);
|
||||||
|
if let Some(s) = conn.server.upgrade() {
|
||||||
|
s.write().unwrap().remove_connection(&conn.inner);
|
||||||
|
}
|
||||||
log::info!("#{} connection loop exited", id);
|
log::info!("#{} connection loop exited", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1274,7 +1279,7 @@ impl Connection {
|
|||||||
.retain(|_, v| v.0.elapsed() < SWITCH_SIDES_TIMEOUT);
|
.retain(|_, v| v.0.elapsed() < SWITCH_SIDES_TIMEOUT);
|
||||||
let uuid_old = SWITCH_SIDES_UUID.lock().unwrap().remove(&lr.my_id);
|
let uuid_old = SWITCH_SIDES_UUID.lock().unwrap().remove(&lr.my_id);
|
||||||
if let Ok(uuid) = uuid::Uuid::from_slice(_s.uuid.to_vec().as_ref()) {
|
if let Ok(uuid) = uuid::Uuid::from_slice(_s.uuid.to_vec().as_ref()) {
|
||||||
if let Some((instant, uuid_old)) = uuid_old {
|
if let Some((_instant, uuid_old)) = uuid_old {
|
||||||
if uuid == uuid_old {
|
if uuid == uuid_old {
|
||||||
self.from_switch = true;
|
self.from_switch = true;
|
||||||
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), true);
|
self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), true);
|
||||||
@ -1583,6 +1588,8 @@ impl Connection {
|
|||||||
uuid.to_string().as_ref(),
|
uuid.to_string().as_ref(),
|
||||||
])
|
])
|
||||||
.ok();
|
.ok();
|
||||||
|
self.send_close_reason_no_retry("Closed as expected");
|
||||||
|
self.on_close("switch sides", false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1756,16 +1763,13 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn on_close(&mut self, reason: &str, lock: bool) {
|
async fn on_close(&mut self, reason: &str, lock: bool) {
|
||||||
if let Some(s) = self.server.upgrade() {
|
|
||||||
s.write().unwrap().remove_connection(&self.inner);
|
|
||||||
}
|
|
||||||
log::info!("#{} Connection closed: {}", self.inner.id(), reason);
|
log::info!("#{} Connection closed: {}", self.inner.id(), reason);
|
||||||
if lock && self.lock_after_session_end && self.keyboard {
|
if lock && self.lock_after_session_end && self.keyboard {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
lock_screen().await;
|
lock_screen().await;
|
||||||
}
|
}
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
let data = if self.chat_unanswered && !self.close_manually {
|
let data = if self.chat_unanswered {
|
||||||
ipc::Data::Disconnected
|
ipc::Data::Disconnected
|
||||||
} else {
|
} else {
|
||||||
ipc::Data::Close
|
ipc::Data::Close
|
||||||
@ -1776,15 +1780,17 @@ impl Connection {
|
|||||||
self.port_forward_socket.take();
|
self.port_forward_socket.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_close_manually(&mut self, close_from: &str, close_by: &str) {
|
// The `reason` should be consistent with `check_if_retry` if not empty
|
||||||
self.close_manually = true;
|
async fn send_close_reason_no_retry(&mut self, reason: &str) {
|
||||||
let mut misc = Misc::new();
|
let mut misc = Misc::new();
|
||||||
misc.set_close_reason(format!("Closed manually by the {}", close_by));
|
if reason.is_empty() {
|
||||||
|
misc.set_close_reason("Closed manually by the peer".to_string());
|
||||||
|
} else {
|
||||||
|
misc.set_close_reason(reason.to_string());
|
||||||
|
}
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_misc(misc);
|
msg_out.set_misc(misc);
|
||||||
self.send(msg_out).await;
|
self.send(msg_out).await;
|
||||||
self.on_close(&format!("Close requested from {}", close_from), false)
|
|
||||||
.await;
|
|
||||||
SESSIONS.lock().unwrap().remove(&self.lr.my_id);
|
SESSIONS.lock().unwrap().remove(&self.lr.my_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,15 +449,12 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
log::info!("try create privacy mode window");
|
log::info!("try create privacy mode window");
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
if let Err(e) = crate::platform::windows::check_update_broker_process() {
|
if let Err(e) = crate::platform::windows::check_update_broker_process() {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Failed to check update broker process. Privacy mode may not work properly. {}",
|
"Failed to check update broker process. Privacy mode may not work properly. {}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
allow_err!(crate::ui::win_privacy::start());
|
allow_err!(crate::ui::win_privacy::start());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user