Merge remote-tracking branch 'github/master' into sigma

This commit is contained in:
sjpark
2023-02-28 16:00:31 +09:00
87 changed files with 3236 additions and 584 deletions

View File

@@ -56,6 +56,7 @@ pub struct Remote<T: InvokeUiSession> {
data_count: Arc<AtomicUsize>,
frame_count: Arc<AtomicUsize>,
video_format: CodecFormat,
elevation_requested: bool,
}
impl<T: InvokeUiSession> Remote<T> {
@@ -87,6 +88,7 @@ impl<T: InvokeUiSession> Remote<T> {
video_format: CodecFormat::Unknown,
stop_voice_call_sender: None,
voice_call_request_timestamp: None,
elevation_requested: false,
}
}
@@ -686,6 +688,7 @@ impl<T: InvokeUiSession> Remote<T> {
let mut msg = Message::new();
msg.set_misc(misc);
allow_err!(peer.send(&msg).await);
self.elevation_requested = true;
}
Data::ElevateWithLogon(username, password) => {
let mut request = ElevationRequest::new();
@@ -699,6 +702,7 @@ impl<T: InvokeUiSession> Remote<T> {
let mut msg = Message::new();
msg.set_misc(misc);
allow_err!(peer.send(&msg).await);
self.elevation_requested = true;
}
Data::NewVoiceCall => {
let msg = new_voice_call_request(true);
@@ -1181,7 +1185,8 @@ impl<T: InvokeUiSession> Remote<T> {
}
}
Some(misc::Union::PortableServiceRunning(b)) => {
if b {
self.handler.portable_service_running(b);
if self.elevation_requested && b {
self.handler.msgbox(
"custom-nocancel-success",
"Successful",
@@ -1253,14 +1258,12 @@ impl<T: InvokeUiSession> Remote<T> {
}
}
}
Some(message::Union::PeerInfo(pi)) => {
match pi.conn_id {
crate::SYNC_PEER_INFO_DISPLAYS => {
self.handler.set_displays(&pi.displays);
}
_ => {}
Some(message::Union::PeerInfo(pi)) => match pi.conn_id {
crate::SYNC_PEER_INFO_DISPLAYS => {
self.handler.set_displays(&pi.displays);
}
}
_ => {}
},
_ => {}
}
}

View File

@@ -572,6 +572,13 @@ impl InvokeUiSession for FlutterHandler {
self.push_event("switch_back", [("peer_id", peer_id)].into());
}
fn portable_service_running(&self, running: bool) {
self.push_event(
"portable_service_running",
[("running", running.to_string().as_str())].into(),
);
}
fn on_voice_call_started(&self) {
self.push_event("on_voice_call_started", [].into());
}

View File

@@ -726,6 +726,10 @@ pub fn main_peer_has_password(id: String) -> bool {
peer_has_password(id)
}
pub fn main_is_in_recent_peers(id: String) -> bool {
PeerConfig::peers().iter().any(|e| e.0 == id)
}
pub fn main_load_recent_peers() {
if !config::APP_DIR.read().unwrap().is_empty() {
let peers: Vec<HashMap<&str, String>> = PeerConfig::peers()
@@ -796,6 +800,10 @@ pub fn main_load_lan_peers() {
};
}
pub fn main_remove_discovered(id: String) {
remove_discovered(id);
}
fn main_broadcast_message(data: &HashMap<&str, &str>) {
let apps = vec![
flutter::APP_TYPE_DESKTOP_REMOTE,
@@ -832,6 +840,10 @@ pub fn main_get_user_default_option(key: String) -> SyncReturn<String> {
SyncReturn(get_user_default_option(key))
}
pub fn main_handle_relay_id(id: String) -> String {
handle_relay_id(id)
}
pub fn session_add_port_forward(
id: String,
local_port: i32,

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -38,7 +38,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop service", "停止服务"),
("Change ID", "更改 ID"),
("Your new ID", "你的新 ID"),
("length %min% to %max%", "长度在 %min 与 %max 之间"),
("length %min% to %max%", "长度在 %min% 与 %max% 之间"),
("starts with a letter", "以字母开头"),
("allowed characters", "使用允许的字符"),
("id_change_tip", "只可以使用字母 a-z, A-Z, 0-9, _ (下划线)。首字母必须是 a-z, A-Z。长度在 6 与 16 之间。"),
@@ -137,7 +137,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Failed to connect to rendezvous server", "连接注册服务器失败"),
("Please try later", "请稍后再试"),
("Remote desktop is offline", "远程电脑处于离线状态"),
("Key mismatch", "密钥不匹配"),
("Key mismatch", "Key 不匹配"),
("Timeout", "连接超时"),
("Failed to connect to relay server", "无法连接到中继服务器"),
("Failed to connect via rendezvous server", "无法通过注册服务器建立连接"),
@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", "重连"),
("Codec", "编解码"),
("Resolution", "分辨率"),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -454,6 +454,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", ""),
("relay_hint_tip", ""),
("Reconnect", ""),
("No transfers in progress", ""),
("Codec", ""),
("Resolution", ""),
].iter().cloned().collect();

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -454,7 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", "Sprachanruf beenden"),
("relay_hint_tip", "Wenn eine direkte Verbindung nicht möglich ist, können Sie versuchen, eine Verbindung über einen Relay-Server herzustellen. \nWenn Sie eine Relay-Verbindung beim ersten Versuch herstellen möchten, können Sie das Suffix \"/r\" an die ID anhängen oder die Option \"Immer über Relay-Server verbinden\" auf der Gegenstelle auswählen."),
("Reconnect", "Erneut verbinden"),
("Codec", ""),
("Resolution", ""),
].iter().cloned().collect();
("Codec", "Codec"),
("Resolution", "Auflösung"),
("No transfers in progress", "Keine Übertragungen im Gange"),
].iter().cloned().collect();
}

View File

@@ -39,10 +39,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("verification_tip", "A new device has been detected, and a verification code has been sent to the registered email address, enter the verification code to continue logging in."),
("software_render_tip", "If you have an Nvidia graphics card and the remote window closes immediately after connecting, installing the nouveau driver and choosing to use software rendering may help. A software restart is required."),
("config_input", "In order to control remote desktop with keyboard, you need to grant RustDesk \"Input Monitoring\" permissions."),
("request_elevation_tip","You can also request elevation if there is someone on the remote side."),
("wait_accept_uac_tip","Please wait for the remote user to accept the UAC dialog."),
("request_elevation_tip", "You can also request elevation if there is someone on the remote side."),
("wait_accept_uac_tip", "Please wait for the remote user to accept the UAC dialog."),
("still_click_uac_tip", "Still requires the remote user to click OK on the UAC window of running RustDesk."),
("config_microphone", "In order to speak remotely, you need to grant RustDesk \"Record Audio\" permissions."),
("relay_hint_tip", "It may not be possible to connect directly, you can try to connect via relay. \nIn addition, if you want to use relay on your first try, you can add the \"/r\" suffix to the ID, or select the option \"Always connect via relay\" in the peer card."),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -454,7 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", "Detener llamada de voz"),
("relay_hint_tip", "Puede que no sea posible conectar directamente. Puedes tratar de conectar a través de relay. \nAdicionalmente, si quieres usar relay en el primer intento, puedes añadir el sufijo \"/r\" a la ID o seleccionar la opción \"Conectar siempre a través de relay\" en la tarjeta del par."),
("Reconnect", "Reconectar"),
("Codec", ""),
("Resolution", ""),
("Codec", "Códec"),
("Resolution", "Resolución"),
("No transfers in progress", "No hay transferencias en curso"),
].iter().cloned().collect();
}

View File

@@ -454,6 +454,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", "توقف تماس صوتی"),
("relay_hint_tip", " را به شناسه اضافه کنید یا گزینه \"همیشه از طریق رله متصل شوید\" را در کارت همتا انتخاب کنید. همچنین، اگر می‌خواهید فوراً از سرور رله استفاده کنید، می‌توانید پسوند \"/r\".\n اتصال مستقیم ممکن است امکان پذیر نباشد. در این صورت می توانید سعی کنید از طریق سرور رله متصل شوید"),
("Reconnect", "اتصال مجدد"),
("No transfers in progress", ""),
("Codec", ""),
("Resolution", ""),
].iter().cloned().collect();

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -454,7 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", "Interrompi la chiamata vocale"),
("relay_hint_tip", "Se non è possibile connettersi direttamente, si può provare a farlo tramite relay.\nInoltre, se si desidera utilizzare il relay al primo tentativo, è possibile aggiungere il suffisso \"/r\" all'ID o selezionare l'opzione \"Collegati sempre tramite relay\" nella scheda peer."),
("Reconnect", "Riconnetti"),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", "Nessun trasferimento in corso"),
("Codec", "Codec"),
("Resolution", "Risoluzione"),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -444,7 +444,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Default View Style", "Standaard Weergave Stijl"),
("Default Scroll Style", "Standaard Scroll Stijl"),
("Default Image Quality", "Standaard Beeldkwaliteit"),
("Default Codec", "tandaard Codec"),
("Default Codec", "Standaard Codec"),
("Bitrate", "Bitrate"),
("FPS", "FPS"),
("Auto", "Auto"),
@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -284,13 +284,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Do you accept?", "Akceptujesz?"),
("Open System Setting", "Otwórz ustawienia systemowe"),
("How to get Android input permission?", "Jak uzyskać uprawnienia do wprowadzania danych w systemie Android?"),
("android_input_permission_tip1", "android_input_permission_tip1"),
("android_input_permission_tip2", "android_input_permission_tip2"),
("android_new_connection_tip", "android_new_connection_tip"),
("android_service_will_start_tip", "android_service_will_start_tip"),
("android_stop_service_tip", "android_stop_service_tip"),
("android_version_audio_tip", "android_version_audio_tip"),
("android_start_service_tip", "android_start_service_tip"),
("android_input_permission_tip1", "Aby można było sterować Twoim urządzeniem za pomocą myszy lub dotyku, musisz zezwolić RustDesk na korzystanie z usługi \"Ułatwienia dostępu\"."),
("android_input_permission_tip2", "Przejdź do następnej strony ustawień systemowych, znajdź i wejdź w [Zainstalowane usługi], włącz usługę [RustDesk Input]."),
("android_new_connection_tip", "Otrzymano nowe żądanie zdalnego dostępu, które chce przejąć kontrolę nad Twoim urządzeniem."),
("android_service_will_start_tip", "Włączenie opcji „Przechwytywanie ekranu” spowoduje automatyczne uruchomienie usługi, umożliwiając innym urządzeniom żądanie połączenia z Twoim urządzeniem."),
("android_stop_service_tip", "Zamknięcie usługi spowoduje automatyczne zamknięcie wszystkich nawiązanych połączeń."),
("android_version_audio_tip", "Bieżąca wersja systemu Android nie obsługuje przechwytywania dźwięku, zaktualizuj system do wersji Android 10 lub nowszej."),
("android_start_service_tip", "Kliknij [Uruchom usługę] lub Otwórz [Przechwytywanie ekranu], aby uruchomić usługę udostępniania ekranu."),
("Account", "Konto"),
("Overwrite", "Nadpisz"),
("This file exists, skip or overwrite this file?", "Ten plik istnieje, pominąć czy nadpisać ten plik?"),
@@ -311,7 +311,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Language", "Język"),
("Keep RustDesk background service", "Zachowaj usługę RustDesk w tle"),
("Ignore Battery Optimizations", "Ignoruj optymalizację baterii"),
("android_open_battery_optimizations_tip", "android_open_battery_optimizations_tip"),
("android_open_battery_optimizations_tip", "Jeśli chcesz wyłączyć tę funkcję, przejdź do następnej strony ustawień aplikacji RustDesk, znajdź i wprowadź [Bateria], odznacz [Bez ograniczeń]"),
("Connection not allowed", "Połączenie niedozwolone"),
("Legacy mode", "Tryb kompatybilności wstecznej (legacy)"),
("Map mode", "Tryb mapowania"),
@@ -449,12 +449,16 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("FPS", "FPS"),
("Auto", "Auto"),
("Other Default Options", "Inne opcje domyślne"),
("Voice call", ""),
("Text chat", ""),
("Stop voice call", ""),
("relay_hint_tip", ""),
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("Voice call", "Rozmowa głosowa"),
("Text chat", "Chat tekstowy"),
("Stop voice call", "Rozłącz"),
("relay_hint_tip", "Bezpośrednie połączenie może nie być możliwe, możesz spróbować połączyć się przez serwer przekazujący. \nDodatkowo, jeśli chcesz użyć serwera przekazującego przy pierwszej próbie, możesz dodać sufiks \"/r\" do identyfikatora lub wybrać opcję \"Zawsze łącz przez serwer przekazujący\" na karcie peer-ów."),
("Reconnect", "Połącz ponownie"),
("Codec", "Kodek"),
("Resolution", "Rozdzielczość"),
("Use temporary password", "Użyj hasła tymczasowego"),
("Set temporary password length", "Ustaw długość hasła tymczasowego"),
("Key", "Klucz"),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -454,6 +454,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", ""),
("relay_hint_tip", ""),
("Reconnect", ""),
("No transfers in progress", ""),
("Codec", ""),
("Resolution", ""),
].iter().cloned().collect();

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -454,7 +454,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Stop voice call", "Завершить голосовой вызов"),
("relay_hint_tip", "Прямое подключение может оказаться невозможным. В этом случае можно попытаться подключиться через сервер ретрансляции. \nКроме того, если вы хотите сразу использовать сервер ретрансляции, можно добавить к ID суффикс \"/r\" или включить \"Всегда подключаться через ретранслятор\" в настройках удалённого узла."),
("Reconnect", "Переподключить"),
("Codec", ""),
("Resolution", ""),
("Codec", "Кодек"),
("Resolution", "Разрешение"),
("No transfers in progress", "Передача не осуществляется"),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -37,19 +37,19 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Clipboard is empty", "剪貼簿是空的"),
("Stop service", "停止服務"),
("Change ID", "更改 ID"),
("Your new ID", ""),
("length %min% to %max%", ""),
("starts with a letter", ""),
("allowed characters", ""),
("Your new ID", "你的新 ID"),
("length %min% to %max%", "長度在 %min% 與 %max% 之間"),
("starts with a letter", "以字母開頭"),
("allowed characters", "使用允許的字元"),
("id_change_tip", "僅能使用以下字元a-z、A-Z、0-9、_ (底線)。首字元必須為 a-z 或 A-Z。長度介於 6 到 16 之間。"),
("Website", "網站"),
("About", "關於"),
("Slogan_tip", ""),
("Privacy Statement", ""),
("Privacy Statement", "隱私聲明"),
("Mute", "靜音"),
("Build Date", ""),
("Version", ""),
("Home", ""),
("Build Date", "建構日期"),
("Version", "版本"),
("Home", "主頁"),
("Audio Input", "音訊輸入"),
("Enhancements", "增強功能"),
("Hardware Codec", "硬件編解碼"),
@@ -213,15 +213,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Closed manually by the peer", "由對方手動關閉"),
("Enable remote configuration modification", "啟用遠端更改設定"),
("Run without install", "跳過安裝直接執行"),
("Connect via relay", ""),
("Connect via relay", "中繼連線"),
("Always connect via relay", "一律透過轉送連線"),
("whitelist_tip", "只有白名單中的 IP 可以存取"),
("Login", "登入"),
("Verify", ""),
("Remember me", ""),
("Trust this device", ""),
("Verification code", ""),
("verification_tip", ""),
("Verify", "驗證"),
("Remember me", "記住我"),
("Trust this device", "信任此設備"),
("Verification code", "驗證碼"),
("verification_tip", "檢測到新設備登錄,已向註冊郵箱發送了登入驗證碼,請輸入驗證碼繼續登錄"),
("Logout", "登出"),
("Tags", "標籤"),
("Search ID", "搜尋 ID"),
@@ -391,12 +391,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 發行版。 請嘗試 X11 桌面或更改您的操作系統。"),
("JumpLink", "查看"),
("Please Select the screen to be shared(Operate on the peer side).", "請選擇要分享的畫面(在對端操作)。"),
("Show RustDesk", ""),
("This PC", ""),
("or", ""),
("Continue with", ""),
("Show RustDesk", "顯示 RustDesk"),
("This PC", "此電腦"),
("or", ""),
("Continue with", "使用"),
("Elevate", "提權"),
("Zoom cursor", ""),
("Zoom cursor", "縮放游標"),
("Accept sessions via password", "只允許密碼訪問"),
("Accept sessions via click", "只允許點擊訪問"),
("Accept sessions via both", "允許密碼或點擊訪問"),
@@ -407,9 +407,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Request access to your device", "請求訪問你的設備"),
("Hide connection management window", "隱藏連接管理窗口"),
("hide_cm_tip", "在只允許密碼連接並且只用固定密碼的情況下才允許隱藏"),
("wayland_experiment_tip", ""),
("wayland_experiment_tip", "Wayland 支持處於實驗階段,如果你需要使用無人值守訪問,請使用 X11。"),
("Right click to select tabs", "右鍵選擇選項卡"),
("Skipped", ""),
("Skipped", "已略過"),
("Add to Address Book", "添加到地址簿"),
("Group", "小組"),
("Search", "搜索"),
@@ -418,8 +418,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Select local keyboard type", "請選擇本地鍵盤類型"),
("software_render_tip", "如果你使用英偉達顯卡, 並且遠程窗口在會話建立後會立刻關閉, 那麼安裝nouveau驅動並且選擇使用軟件渲染可能會有幫助。重啟軟件後生效。"),
("Always use software rendering", "使用軟件渲染"),
("config_input", ""),
("config_microphone", ""),
("config_input", "為了能夠通過鍵盤控制遠程桌面, 請給予 RustDesk \"輸入監控\" 權限。"),
("config_microphone", "為了支持通過麥克風進行音訊傳輸,請給予 RustDesk \"錄音\"權限。"),
("request_elevation_tip", "如果對面有人, 也可以請求提升權限。"),
("Wait", "等待"),
("Elevation Error", "提權失敗"),
@@ -438,8 +438,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Weak", ""),
("Medium", ""),
("Strong", ""),
("Switch Sides", ""),
("Please confirm if you want to share your desktop?", ""),
("Switch Sides", "反轉訪問方向"),
("Please confirm if you want to share your desktop?", "請確認是否要讓對方訪問你的桌面?"),
("Display", "顯示"),
("Default View Style", "默認顯示方式"),
("Default Scroll Style", "默認滾動方式"),
@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", "重連"),
("Codec", "編解碼"),
("Resolution", "分辨率"),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -456,5 +456,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Reconnect", ""),
("Codec", ""),
("Resolution", ""),
("No transfers in progress", ""),
].iter().cloned().collect();
}

View File

@@ -1,6 +1,7 @@
// Specify the Windows subsystem to eliminate console window.
// Requires Rust 1.18.
//#![windows_subsystem = "windows"]
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use librustdesk::*;

View File

@@ -1,14 +1,22 @@
use super::{CursorData, ResultType};
use hbb_common::libc::{c_char, c_int, c_long, c_void};
pub use hbb_common::platform::linux::*;
use hbb_common::{allow_err, anyhow::anyhow, bail, log, message_proto::Resolution};
use hbb_common::{
allow_err,
anyhow::anyhow,
bail,
libc::{c_char, c_int, c_long, c_void},
log,
message_proto::Resolution,
};
use std::{
cell::RefCell,
path::PathBuf,
path::{Path, PathBuf},
process::{Child, Command},
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::{Duration, Instant},
};
use xrandr_parser::Parser;
@@ -162,10 +170,29 @@ fn start_uinput_service() {
});
}
fn stop_server(server: &mut Option<std::process::Child>) {
#[inline]
fn try_start_server_(user: Option<(String, String)>) -> ResultType<Option<Child>> {
if user.is_some() {
run_as_user(vec!["--server"], user)
} else {
Ok(Some(crate::run_me(vec!["--server"])?))
}
}
#[inline]
fn start_server(user: Option<(String, String)>, server: &mut Option<Child>) {
match try_start_server_(user) {
Ok(ps) => *server = ps,
Err(err) => {
log::error!("Failed to start server: {}", err);
}
}
}
fn stop_server(server: &mut Option<Child>) {
if let Some(mut ps) = server.take() {
allow_err!(ps.kill());
std::thread::sleep(std::time::Duration::from_millis(30));
std::thread::sleep(Duration::from_millis(30));
match ps.try_wait() {
Ok(Some(_status)) => {}
Ok(None) => {
@@ -182,7 +209,7 @@ fn set_x11_env(uid: &str) {
let mut auth = get_env_tries("XAUTHORITY", uid, 10);
// auth is another user's when uid = 0, https://github.com/rustdesk/rustdesk/issues/2468
if auth.is_empty() || uid == "0" {
auth = if std::path::Path::new(&gdm).exists() {
auth = if Path::new(&gdm).exists() {
gdm
} else {
let username = get_active_username();
@@ -190,7 +217,7 @@ fn set_x11_env(uid: &str) {
format!("/{}/.Xauthority", username)
} else {
let tmp = format!("/home/{}/.Xauthority", username);
if std::path::Path::new(&tmp).exists() {
if Path::new(&tmp).exists() {
tmp
} else {
format!("/var/lib/{}/.Xauthority", username)
@@ -223,8 +250,8 @@ fn should_start_server(
uid: &mut String,
cur_uid: String,
cm0: &mut bool,
last_restart: &mut std::time::Instant,
server: &mut Option<std::process::Child>,
last_restart: &mut Instant,
server: &mut Option<Child>,
) -> bool {
let cm = get_cm();
let mut start_new = false;
@@ -235,8 +262,8 @@ fn should_start_server(
}
if let Some(ps) = server.as_mut() {
allow_err!(ps.kill());
std::thread::sleep(std::time::Duration::from_millis(30));
*last_restart = std::time::Instant::now();
std::thread::sleep(Duration::from_millis(30));
*last_restart = Instant::now();
}
} else if !cm
&& ((*cm0 && last_restart.elapsed().as_secs() > 60)
@@ -247,8 +274,8 @@ fn should_start_server(
// and x server get displays failure issue
if let Some(ps) = server.as_mut() {
allow_err!(ps.kill());
std::thread::sleep(std::time::Duration::from_millis(30));
*last_restart = std::time::Instant::now();
std::thread::sleep(Duration::from_millis(30));
*last_restart = Instant::now();
log::info!("restart server");
}
}
@@ -267,6 +294,13 @@ fn should_start_server(
start_new
}
// to-do: stop_server(&mut user_server); may not stop child correctly
// stop_rustdesk_servers() is just a temp solution here.
fn force_stop_server() {
stop_rustdesk_servers();
std::thread::sleep(Duration::from_millis(super::SERVICE_INTERVAL));
}
pub fn start_os_service() {
stop_rustdesk_servers();
start_uinput_service();
@@ -274,8 +308,8 @@ pub fn start_os_service() {
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
let mut uid = "".to_owned();
let mut server: Option<std::process::Child> = None;
let mut user_server: Option<std::process::Child> = None;
let mut server: Option<Child> = None;
let mut user_server: Option<Child> = None;
if let Err(err) = ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
}) {
@@ -283,12 +317,13 @@ pub fn start_os_service() {
}
let mut cm0 = false;
let mut last_restart = std::time::Instant::now();
let mut last_restart = Instant::now();
while running.load(Ordering::SeqCst) {
let (cur_uid, cur_user) = get_active_user_id_name();
let is_wayland = current_is_wayland();
if cur_user == "root" || !is_wayland {
// try kill subprocess "--server"
stop_server(&mut user_server);
// try start subprocess "--server"
if should_start_server(
@@ -299,16 +334,8 @@ pub fn start_os_service() {
&mut last_restart,
&mut server,
) {
// to-do: stop_server(&mut user_server); may not stop child correctly
// stop_rustdesk_servers() is just a temp solution here.
stop_rustdesk_servers();
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
match crate::run_me(vec!["--server"]) {
Ok(ps) => server = Some(ps),
Err(err) => {
log::error!("Failed to start server: {}", err);
}
}
force_stop_server();
start_server(None, &mut server);
}
} else if cur_user != "" {
if cur_user != "gdm" {
@@ -324,23 +351,16 @@ pub fn start_os_service() {
&mut last_restart,
&mut user_server,
) {
stop_rustdesk_servers();
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
match run_as_user(vec!["--server"], Some((cur_uid, cur_user))) {
Ok(ps) => user_server = ps,
Err(err) => {
log::error!("Failed to start server: {}", err);
}
}
force_stop_server();
start_server(Some((cur_uid, cur_user)), &mut user_server);
}
}
} else {
stop_rustdesk_servers();
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
force_stop_server();
stop_server(&mut user_server);
stop_server(&mut server);
}
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
std::thread::sleep(Duration::from_millis(super::SERVICE_INTERVAL));
}
if let Some(ps) = user_server.take().as_mut() {
@@ -362,7 +382,7 @@ pub fn get_active_userid() -> String {
}
fn get_cm() -> bool {
if let Ok(output) = std::process::Command::new("ps").args(vec!["aux"]).output() {
if let Ok(output) = Command::new("ps").args(vec!["aux"]).output() {
for line in String::from_utf8_lossy(&output.stdout).lines() {
if line.contains(&format!(
"{} --cm",
@@ -380,7 +400,7 @@ fn get_cm() -> bool {
fn get_display() -> String {
let user = get_active_username();
log::debug!("w {}", &user);
if let Ok(output) = std::process::Command::new("w").arg(&user).output() {
if let Ok(output) = Command::new("w").arg(&user).output() {
for line in String::from_utf8_lossy(&output.stdout).lines() {
log::debug!(" {}", line);
let mut iter = line.split_whitespace();
@@ -395,7 +415,7 @@ fn get_display() -> String {
// above not work for gdm user
log::debug!("ls -l /tmp/.X11-unix/");
let mut last = "".to_owned();
if let Ok(output) = std::process::Command::new("ls")
if let Ok(output) = Command::new("ls")
.args(vec!["-l", "/tmp/.X11-unix/"])
.output()
{
@@ -474,10 +494,7 @@ fn is_opensuse() -> bool {
false
}
pub fn run_as_user(
arg: Vec<&str>,
user: Option<(String, String)>,
) -> ResultType<Option<std::process::Child>> {
pub fn run_as_user(arg: Vec<&str>, user: Option<(String, String)>) -> ResultType<Option<Child>> {
let (uid, username) = match user {
Some(id_name) => id_name,
None => get_active_user_id_name(),
@@ -491,7 +508,7 @@ pub fn run_as_user(
args.insert(0, "-E");
}
let task = std::process::Command::new("sudo").args(args).spawn()?;
let task = Command::new("sudo").args(args).spawn()?;
Ok(Some(task))
}
@@ -553,10 +570,7 @@ pub fn get_default_pa_source() -> Option<(String, String)> {
}
pub fn lock_screen() {
std::process::Command::new("xdg-screensaver")
.arg("lock")
.spawn()
.ok();
Command::new("xdg-screensaver").arg("lock").spawn().ok();
}
pub fn toggle_blank_screen(_v: bool) {
@@ -577,7 +591,7 @@ fn get_env_tries(name: &str, uid: &str, n: usize) -> String {
if !x.is_empty() {
return x;
}
std::thread::sleep(std::time::Duration::from_millis(300));
std::thread::sleep(Duration::from_millis(300));
}
"".to_owned()
}
@@ -604,12 +618,12 @@ pub fn quit_gui() {
pub fn check_super_user_permission() -> ResultType<bool> {
let file = "/usr/share/rustdesk/files/polkit";
let arg;
if std::path::Path::new(file).is_file() {
if Path::new(file).is_file() {
arg = file;
} else {
arg = "echo";
}
let status = std::process::Command::new("pkexec").arg(arg).status()?;
let status = Command::new("pkexec").arg(arg).status()?;
Ok(status.success() && status.code() == Some(0))
}
@@ -684,7 +698,7 @@ pub fn current_resolution(name: &str) -> ResultType<Resolution> {
}
pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<()> {
std::process::Command::new("xrandr")
Command::new("xrandr")
.args(vec![
"--output",
name,

View File

@@ -1,6 +1,9 @@
#import <AVFoundation/AVFoundation.h>
#import <AppKit/AppKit.h>
#import <IOKit/hidsystem/IOHIDLib.h>
#include <Security/Authorization.h>
#include <Security/AuthorizationTags.h>
// https://github.com/codebytere/node-mac-permissions/blob/main/permissions.mm
@@ -35,6 +38,33 @@ extern "C" bool InputMonitoringAuthStatus(bool prompt) {
return false;
}
extern "C" bool MacCheckAdminAuthorization() {
AuthorizationRef authRef;
OSStatus status;
status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults, &authRef);
if (status != errAuthorizationSuccess) {
printf("Failed to create AuthorizationRef\n");
return false;
}
AuthorizationItem authItem = {kAuthorizationRightExecute, 0, NULL, 0};
AuthorizationRights authRights = {1, &authItem};
AuthorizationFlags flags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
status = AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL);
if (status != errAuthorizationSuccess) {
printf("Failed to authorize\n");
return false;
}
AuthorizationFree(authRef, kAuthorizationFlagDefaults);
return true;
}
extern "C" float BackingScaleFactor() {
NSScreen* s = [NSScreen mainScreen];
if (s) return [s backingScaleFactor];
@@ -44,6 +74,33 @@ extern "C" float BackingScaleFactor() {
// https://github.com/jhford/screenresolution/blob/master/cg_utils.c
// https://github.com/jdoupe/screenres/blob/master/setgetscreen.m
size_t bitDepth(CGDisplayModeRef mode) {
size_t depth = 0;
// Deprecated, same display same bpp?
// https://stackoverflow.com/questions/8210824/how-to-avoid-cgdisplaymodecopypixelencoding-to-get-bpp
// https://github.com/libsdl-org/SDL/pull/6628
CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode);
// my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels
// are made up and possibly non-sensical
if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO32BitFloatPixels), kCFCompareCaseInsensitive)) {
depth = 96;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO64BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 64;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO16BitFloatPixels), kCFCompareCaseInsensitive)) {
depth = 48;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 32;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 30;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 16;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive)) {
depth = 8;
}
CFRelease(pixelEncoding);
return depth;
}
extern "C" bool MacGetModeNum(CGDirectDisplayID display, uint32_t *numModes) {
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
if (allModes == NULL) {
@@ -55,16 +112,28 @@ extern "C" bool MacGetModeNum(CGDirectDisplayID display, uint32_t *numModes) {
}
extern "C" bool MacGetModes(CGDirectDisplayID display, uint32_t *widths, uint32_t *heights, uint32_t max, uint32_t *numModes) {
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
if (allModes == NULL) {
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(display);
if (currentMode == NULL) {
return false;
}
*numModes = CFArrayGetCount(allModes);
for (int i = 0; i < *numModes && i < max; i++) {
CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
widths[i] = (uint32_t)CGDisplayModeGetWidth(mode);
heights[i] = (uint32_t)CGDisplayModeGetHeight(mode);
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
if (allModes == NULL) {
CGDisplayModeRelease(currentMode);
return false;
}
uint32_t allModeCount = CFArrayGetCount(allModes);
uint32_t realNum = 0;
for (uint32_t i = 0; i < allModeCount && realNum < max; i++) {
CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
if (CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode) &&
bitDepth(currentMode) == bitDepth(mode)) {
widths[realNum] = (uint32_t)CGDisplayModeGetWidth(mode);
heights[realNum] = (uint32_t)CGDisplayModeGetHeight(mode);
realNum++;
}
}
*numModes = realNum;
CGDisplayModeRelease(currentMode);
CFRelease(allModes);
return true;
}
@@ -80,31 +149,8 @@ extern "C" bool MacGetMode(CGDirectDisplayID display, uint32_t *width, uint32_t
return true;
}
size_t bitDepth(CGDisplayModeRef mode) {
size_t depth = 0;
CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode);
// my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels
// are made up and possibly non-sensical
if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO32BitFloatPixels), kCFCompareCaseInsensitive)) {
depth = 96;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO64BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 64;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO16BitFloatPixels), kCFCompareCaseInsensitive)) {
depth = 48;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 32;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 30;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)) {
depth = 16;
} else if (kCFCompareEqualTo == CFStringCompare(pixelEncoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive)) {
depth = 8;
}
CFRelease(pixelEncoding);
return depth;
}
bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) {
static bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) {
CGError rc;
CGDisplayConfigRef config;
rc = CGBeginDisplayConfiguration(&config);
@@ -122,7 +168,6 @@ bool setDisplayToMode(CGDirectDisplayID display, CGDisplayModeRef mode) {
return true;
}
extern "C" bool MacSetMode(CGDirectDisplayID display, uint32_t width, uint32_t height)
{
bool ret = false;
@@ -136,13 +181,12 @@ extern "C" bool MacSetMode(CGDirectDisplayID display, uint32_t width, uint32_t h
return ret;
}
int numModes = CFArrayGetCount(allModes);
CGDisplayModeRef bestMode = NULL;
for (int i = 0; i < numModes; i++) {
CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
if (width == CGDisplayModeGetWidth(mode) &&
height == CGDisplayModeGetHeight(mode) &&
bitDepth(currentMode) == bitDepth(mode) &&
CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode)) {
CGDisplayModeGetRefreshRate(currentMode) == CGDisplayModeGetRefreshRate(mode) &&
bitDepth(currentMode) == bitDepth(mode)) {
ret = setDisplayToMode(display, mode);
break;
}

View File

@@ -34,6 +34,7 @@ extern "C" {
static kAXTrustedCheckOptionPrompt: CFStringRef;
fn AXIsProcessTrustedWithOptions(options: CFDictionaryRef) -> BOOL;
fn InputMonitoringAuthStatus(_: BOOL) -> BOOL;
fn MacCheckAdminAuthorization() -> BOOL;
fn MacGetModeNum(display: u32, numModes: *mut u32) -> BOOL;
fn MacGetModes(
display: u32,
@@ -612,18 +613,18 @@ pub fn resolutions(name: &str) -> Vec<Resolution> {
unsafe {
if YES == MacGetModeNum(display, &mut num) {
let (mut widths, mut heights) = (vec![0; num as _], vec![0; num as _]);
let mut realNum = 0;
let mut real_num = 0;
if YES
== MacGetModes(
display,
widths.as_mut_ptr(),
heights.as_mut_ptr(),
num,
&mut realNum,
&mut real_num,
)
{
if realNum <= num {
for i in 0..realNum {
if real_num <= num {
for i in 0..real_num {
let resolution = Resolution {
width: widths[i as usize] as _,
height: heights[i as usize] as _,
@@ -665,3 +666,10 @@ pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<
}
Ok(())
}
pub fn check_super_user_permission() -> ResultType<bool> {
unsafe {
Ok(MacCheckAdminAuthorization() == YES)
}
}

View File

@@ -1236,6 +1236,15 @@ pub fn uninstall_me() -> ResultType<()> {
fn write_cmds(cmds: String, ext: &str, tip: &str) -> ResultType<std::path::PathBuf> {
let mut tmp = std::env::temp_dir();
// When dir contains these characters, the bat file will not execute in elevated mode.
if vec!["&", "@", "^"]
.drain(..)
.any(|s| tmp.to_string_lossy().to_string().contains(s))
{
if let Ok(dir) = user_accessible_folder() {
tmp = dir;
}
}
tmp.push(format!("{}_{}.{}", crate::get_app_name(), tip, ext));
let mut file = std::fs::File::create(&tmp)?;
// in case cmds mixed with \r\n and \n, make sure all ending with \r\n
@@ -1872,3 +1881,19 @@ pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<
Ok(())
}
}
pub fn user_accessible_folder() -> ResultType<PathBuf> {
let disk = std::env::var("SystemDrive").unwrap_or("C:".to_string());
let dir1 = PathBuf::from(format!("{}\\ProgramData", disk));
// NOTICE: "C:\Windows\Temp" requires permanent authorization.
let dir2 = PathBuf::from(format!("{}\\Windows\\Temp", disk));
let dir;
if dir1.exists() {
dir = dir1;
} else if dir2.exists() {
dir = dir2;
} else {
bail!("no vaild user accessible folder");
}
Ok(dir)
}

View File

@@ -126,6 +126,7 @@ pub struct Connection {
origin_resolution: HashMap<String, Resolution>,
voice_call_request_timestamp: Option<NonZeroI64>,
audio_input_device_before_voice_call: Option<String>,
options_in_login: Option<OptionMessage>,
}
impl ConnInner {
@@ -233,6 +234,7 @@ impl Connection {
audio_sender: None,
voice_call_request_timestamp: None,
audio_input_device_before_voice_call: None,
options_in_login: None,
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
tokio::spawn(async move {
@@ -921,6 +923,9 @@ impl Connection {
let mut msg_out = Message::new();
msg_out.set_login_response(res);
self.send(msg_out).await;
if let Some(o) = self.options_in_login.take() {
self.update_options(&o).await;
}
if let Some((dir, show_hidden)) = self.file_transfer.clone() {
let dir = if !dir.is_empty() && std::path::Path::new(&dir).is_dir() {
&dir
@@ -1106,8 +1111,7 @@ impl Connection {
async fn handle_login_request_without_validation(&mut self, lr: &LoginRequest) {
self.lr = lr.clone();
if let Some(o) = lr.option.as_ref() {
// It may not be a good practice to update all options here.
self.update_options(o).await;
self.options_in_login = Some(o.clone());
if let Some(q) = o.video_codec_state.clone().take() {
scrap::codec::Encoder::update_video_encoder(
self.inner.id(),
@@ -1552,7 +1556,6 @@ impl Connection {
.err()
.map_or("".to_string(), |e| e.to_string());
}
self.portable.elevation_requested = err.is_empty();
let mut misc = Misc::new();
misc.set_elevation_response(err);
let mut msg = Message::new();
@@ -1571,7 +1574,6 @@ impl Connection {
.err()
.map_or("".to_string(), |e| e.to_string());
}
self.portable.elevation_requested = err.is_empty();
let mut misc = Misc::new();
misc.set_elevation_response(err);
let mut msg = Message::new();
@@ -1699,7 +1701,8 @@ impl Connection {
self.send_to_cm(Data::CloseVoiceCall("".to_owned()));
}
async fn update_options_without_auth(&mut self, o: &OptionMessage) {
async fn update_options(&mut self, o: &OptionMessage) {
log::info!("Option update: {:?}", o);
if let Ok(q) = o.image_quality.enum_value() {
let image_quality;
if let ImageQuality::NotSet = q {
@@ -1730,12 +1733,6 @@ impl Connection {
scrap::codec::EncoderUpdate::State(q),
);
}
}
async fn update_options_with_auth(&mut self, o: &OptionMessage) {
if !self.authorized {
return;
}
if let Ok(q) = o.lock_after_session_end.enum_value() {
if q != BoolOption::NotSet {
self.lock_after_session_end = q == BoolOption::Yes;
@@ -1864,12 +1861,6 @@ impl Connection {
}
}
async fn update_options(&mut self, o: &OptionMessage) {
log::info!("Option update: {:?}", o);
self.update_options_without_auth(o).await;
self.update_options_with_auth(o).await;
}
async fn on_close(&mut self, reason: &str, lock: bool) {
log::info!("#{} Connection closed: {}", self.inner.id(), reason);
if lock && self.lock_after_session_end && self.keyboard {
@@ -1936,13 +1927,11 @@ impl Connection {
let p = &mut self.portable;
if running != p.last_running {
p.last_running = running;
if running && p.elevation_requested {
let mut misc = Misc::new();
misc.set_portable_service_running(running);
let mut msg = Message::new();
msg.set_misc(misc);
self.inner.send(msg.into());
}
let mut misc = Misc::new();
misc.set_portable_service_running(running);
let mut msg = Message::new();
msg.set_misc(misc);
self.inner.send(msg.into());
}
let uac = crate::video_service::IS_UAC_RUNNING.lock().unwrap().clone();
if p.last_uac != uac {
@@ -2166,7 +2155,6 @@ pub struct PortableState {
pub last_foreground_window_elevated: bool,
pub last_running: bool,
pub is_installed: bool,
pub elevation_requested: bool,
}
#[cfg(windows)]
@@ -2177,7 +2165,6 @@ impl Default for PortableState {
last_uac: Default::default(),
last_foreground_window_elevated: Default::default(),
last_running: Default::default(),
elevation_requested: Default::default(),
}
}
}

View File

@@ -117,17 +117,7 @@ impl SharedMemory {
}
fn flink(name: String) -> ResultType<String> {
let disk = std::env::var("SystemDrive").unwrap_or("C:".to_string());
let dir1 = PathBuf::from(format!("{}\\ProgramData", disk));
let dir2 = PathBuf::from(format!("{}\\Windows\\Temp", disk));
let mut dir;
if dir1.exists() {
dir = dir1;
} else if dir2.exists() {
dir = dir2;
} else {
bail!("no vaild flink directory");
}
let mut dir = crate::platform::user_accessible_folder()?;
dir = dir.join(hbb_common::config::APP_NAME.read().unwrap().clone());
if !dir.exists() {
std::fs::create_dir(&dir)?;

View File

@@ -577,6 +577,14 @@ fn run(sp: GenericService) -> ResultType<()> {
if last_check_displays.elapsed().as_millis() > 1000 {
last_check_displays = now;
// Capturer on macos does not return Err event the solution is changed.
#[cfg(target_os = "macos")]
if check_display_changed(c.ndisplay, c.current, c.width, c.height) {
log::info!("Displays changed");
*SWITCH.lock().unwrap() = true;
bail!("SWITCH");
}
if let Some(msg_out) = check_displays_changed() {
sp.send(msg_out);
}

View File

@@ -9,7 +9,7 @@ use sciter::Value;
use hbb_common::{
allow_err,
config::{self, LocalConfig, PeerConfig},
config::{LocalConfig, PeerConfig},
log,
};
@@ -413,17 +413,15 @@ impl UI {
}
fn remove_discovered(&mut self, id: String) {
let mut peers = config::LanPeers::load().peers;
peers.retain(|x| x.id != id);
config::LanPeers::store(&peers);
remove_discovered(id);
}
fn send_wol(&mut self, id: String) {
crate::lan::send_wol(id)
}
fn new_remote(&mut self, id: String, remote_type: String) {
new_remote(id, remote_type)
fn new_remote(&mut self, id: String, remote_type: String, force_relay: bool) {
new_remote(id, remote_type, force_relay)
}
fn is_process_trusted(&mut self, _prompt: bool) -> bool {
@@ -573,6 +571,10 @@ impl UI {
fn default_video_save_directory(&self) -> String {
default_video_save_directory()
}
fn handle_relay_id(&self, id: String) -> String {
handle_relay_id(id)
}
}
impl sciter::EventHandler for UI {
@@ -590,7 +592,7 @@ impl sciter::EventHandler for UI {
fn set_remote_id(String);
fn closing(i32, i32, i32, i32);
fn get_size();
fn new_remote(String, bool);
fn new_remote(String, String, bool);
fn send_wol(String);
fn remove_peer(String);
fn remove_discovered(String);
@@ -655,6 +657,7 @@ impl sciter::EventHandler for UI {
fn has_hwcodec();
fn get_langs();
fn default_video_save_directory();
fn handle_relay_id(String);
}
}
@@ -720,9 +723,13 @@ pub fn value_crash_workaround(values: &[Value]) -> Arc<Vec<Value>> {
}
#[inline]
pub fn new_remote(id: String, remote_type: String) {
pub fn new_remote(id: String, remote_type: String, force_relay: bool) {
let mut lock = CHILDREN.lock().unwrap();
let args = vec![format!("--{}", remote_type), id.clone()];
let mut args = vec![format!("--{}", remote_type), id.clone()];
if force_relay {
args.push("".to_string()); // password
args.push("--relay".to_string());
}
let key = (id.clone(), remote_type.clone());
if let Some(c) = lock.1.get_mut(&key) {
if let Ok(Some(_)) = c.try_wait() {

View File

@@ -62,12 +62,15 @@ function createNewConnect(id, type) {
id = id.replace(/\s/g, "");
app.remote_id.value = formatId(id);
if (!id) return;
var old_id = id;
id = handler.handle_relay_id(id);
var force_relay = old_id != id;
if (id == my_id) {
msgbox("custom-error", "Error", "You cannot connect to your own computer");
return;
}
handler.set_remote_id(id);
handler.new_remote(id, type);
handler.new_remote(id, type, force_relay);
}
class ShareRdp: Reactor.Component {

View File

@@ -277,6 +277,8 @@ impl InvokeUiSession for SciterHandler {
fn switch_back(&self, _id: &str) {}
fn portable_service_running(&self, _running: bool) {}
fn on_voice_call_started(&self) {
self.call("onVoiceCallStart", &make_args!());
}
@@ -460,6 +462,7 @@ impl sciter::EventHandler for SciterSession {
impl SciterSession {
pub fn new(cmd: String, id: String, password: String, args: Vec<String>) -> Self {
let force_relay = args.contains(&"--relay".to_string());
let session: Session<SciterHandler> = Session {
id: id.clone(),
password: password.clone(),
@@ -484,7 +487,7 @@ impl SciterSession {
.lc
.write()
.unwrap()
.initialize(id, conn_type, None, false);
.initialize(id, conn_type, None, force_relay);
Self(session)
}

View File

@@ -596,6 +596,13 @@ pub fn get_lan_peers() -> Vec<HashMap<&'static str, String>> {
.collect()
}
#[inline]
pub fn remove_discovered(id: String) {
let mut peers = config::LanPeers::load().peers;
peers.retain(|x| x.id != id);
config::LanPeers::store(&peers);
}
#[inline]
pub fn get_uuid() -> String {
base64::encode(hbb_common::get_uuid())
@@ -700,10 +707,10 @@ pub fn is_root() -> bool {
pub fn check_super_user_permission() -> bool {
#[cfg(feature = "flatpak")]
return true;
#[cfg(any(windows, target_os = "linux"))]
#[cfg(any(windows, target_os = "linux", target_os = "macos"))]
return crate::platform::check_super_user_permission().unwrap_or(false);
#[cfg(not(any(windows, target_os = "linux")))]
true
#[cfg(not(any(windows, target_os = "linux", target_os = "macos")))]
return true;
}
#[allow(dead_code)]
@@ -963,3 +970,12 @@ async fn check_id(
}
""
}
// if it's relay id, return id processed, otherwise return original id
pub fn handle_relay_id(id: String) -> String {
if id.ends_with(r"\r") || id.ends_with(r"/r") {
id[0..id.len() - 2].to_string()
} else {
id
}
}

View File

@@ -882,6 +882,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn clipboard(&self, content: String);
fn cancel_msgbox(&self, tag: &str);
fn switch_back(&self, id: &str);
fn portable_service_running(&self, running: bool);
fn on_voice_call_started(&self);
fn on_voice_call_closed(&self, reason: &str);
fn on_voice_call_waiting(&self);