diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 270913ee8..6c5f3e2fb 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1522,7 +1522,7 @@ class LastWindowPosition { } String get windowFramePrefix => - bind.isQs() ? "${kWindowPrefix}qs_" : kWindowPrefix; + bind.isIncomingOnly() ? "${kWindowPrefix}qs_" : kWindowPrefix; /// Save window position and size on exit /// Note that windowId must be provided if it's subwindow @@ -1793,11 +1793,11 @@ Future restoreWindowPosition(WindowType type, } if (lpos.isMaximized == true) { await restorePos(); - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { await windowManager.maximize(); } } else { - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { await windowManager.setSize(size); } await restorePos(); diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 7ed9bbd8d..500a074f5 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -134,7 +134,7 @@ class _OnlineStatusWidgetState extends State { ) ], )), - ).paddingOnly(right: bind.isQs() ? 8 : 0); + ).paddingOnly(right: bind.isIncomingOnly() ? 8 : 0); } updateStatus() async { diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index a05afaf23..7a78c3a6b 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -58,7 +58,7 @@ class _DesktopHomePageState extends State super.build(context); final children = [buildLeftPane(context)]; - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { children.addAll([ const VerticalDivider(width: 1), Expanded(child: buildRightPane(context)), @@ -79,7 +79,7 @@ class _DesktopHomePageState extends State future: buildHelpCards(), builder: (_, data) { if (data.hasData) { - if (bind.isQs()) { + if (bind.isIncomingOnly()) { Future.delayed(Duration(milliseconds: 300), () { _updateWindowSize(); }); @@ -92,7 +92,7 @@ class _DesktopHomePageState extends State ), buildPluginEntry(), ]; - if (bind.isQs()) { + if (bind.isIncomingOnly()) { children.addAll([ Divider(), Container( @@ -104,7 +104,7 @@ class _DesktopHomePageState extends State return ChangeNotifierProvider.value( value: gFFI.serverModel, child: Container( - width: bind.isQs() ? 280.0 : 200.0, + width: bind.isIncomingOnly() ? 280.0 : 200.0, color: Theme.of(context).colorScheme.background, child: DesktopScrollWrapper( scrollController: _leftPaneScrollController, @@ -474,7 +474,7 @@ class _DesktopHomePageState extends State children: [ Container( margin: - EdgeInsets.fromLTRB(0, marginTop, 0, bind.isQs() ? marginTop : 0), + EdgeInsets.fromLTRB(0, marginTop, 0, bind.isIncomingOnly() ? marginTop : 0), child: Container( decoration: BoxDecoration( gradient: LinearGradient( @@ -693,7 +693,7 @@ class _DesktopHomePageState extends State }); _uniLinksSubscription = listenUniLinks(); - if (bind.isQs()) { + if (bind.isIncomingOnly()) { WidgetsBinding.instance.addPostFrameCallback((_) { _updateWindowSize(); }); diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 65e55cbc8..98b019d05 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -112,7 +112,7 @@ class _DesktopSettingPageState extends State _TabInfo('Account', Icons.person_outline, Icons.person), _TabInfo('About', Icons.info_outline, Icons.info) ]; - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { settingTabs.insert( 3, _TabInfo('Display', Icons.desktop_windows_outlined, @@ -133,7 +133,7 @@ class _DesktopSettingPageState extends State _Account(), _About(), ]; - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { children.insert(3, _Display()); if (bind.pluginFeatureIsEnabled()) { children.insert(4, _Plugin()); @@ -325,7 +325,7 @@ class _GeneralState extends State<_General> { Widget other() { final children = []; - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { children.add(_OptionCheckBox(context, 'Confirm before closing multiple tabs', 'enable-confirm-closing-tabs', isServer: false)); @@ -334,7 +334,7 @@ class _GeneralState extends State<_General> { _OptionCheckBox(context, 'Adaptive bitrate', 'enable-abr'), wallpaper() ]); - if (!bind.isQs()) { + if (!bind.isIncomingOnly()) { children.addAll([ _OptionCheckBox( context, diff --git a/flutter/lib/desktop/pages/desktop_tab_page.dart b/flutter/lib/desktop/pages/desktop_tab_page.dart index de3ed2ea2..668095df6 100644 --- a/flutter/lib/desktop/pages/desktop_tab_page.dart +++ b/flutter/lib/desktop/pages/desktop_tab_page.dart @@ -54,7 +54,7 @@ class _DesktopTabPageState extends State { page: DesktopHomePage( key: const ValueKey(kTabLabelHomePage), ))); - if (bind.isQs()) { + if (bind.isIncomingOnly()) { tabController.onSelected = (key) { if (key == kTabLabelHomePage) { windowManager.setSize(getDesktopQsHomeSize()); @@ -81,7 +81,7 @@ class _DesktopTabPageState extends State { body: DesktopTab( controller: tabController, tail: Offstage( - offstage: bind.isQs(), + offstage: bind.isIncomingOnly(), child: ActionIcon( message: 'Settings', icon: IconFont.menu, diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 6d53a3887..e290bcda3 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -165,7 +165,7 @@ class DesktopTabController { })); } }); - if ((isDesktop && bind.isQs()) || callOnSelected) { + if ((isDesktop && bind.isIncomingOnly()) || callOnSelected) { if (state.value.tabs.length > index) { final key = state.value.tabs[index].key; onSelected?.call(key); diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index e866e5386..dc2d97a47 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -142,7 +142,7 @@ void runMainApp(bool startService) async { } windowManager.setOpacity(1); windowManager.setTitle(getWindowName()); - windowManager.setResizable(!bind.isQs()); + windowManager.setResizable(!bind.isIncomingOnly()); }); } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 880d360a5..c8b1bc053 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -964,7 +964,13 @@ impl Config { } pub fn get_permanent_password() -> String { - CONFIG.read().unwrap().password.clone() + let mut password = CONFIG.read().unwrap().password.clone(); + if password.is_empty() { + if let Some(v) = HARD_SETTINGS.read().unwrap().get("password") { + password = v.to_owned(); + } + } + password } pub fn set_salt(salt: &str) { @@ -1857,6 +1863,58 @@ fn get_or( .cloned() } +#[inline] +pub fn is_incoming_only() -> bool { + HARD_SETTINGS + .read() + .unwrap() + .get("conn-type") + .map_or(false, |x| x == ("incoming")) +} + +#[inline] +pub fn is_outgoing_only() -> bool { + HARD_SETTINGS + .read() + .unwrap() + .get("conn-type") + .map_or(false, |x| x == ("outgoing")) +} + +#[inline] +fn is_some_hard_opton(name: &str) -> bool { + HARD_SETTINGS + .read() + .unwrap() + .get(name) + .map_or(false, |x| x == ("Y")) +} + +#[inline] +pub fn is_disable_tcp_listen() -> bool { + is_some_hard_opton("disable-tcp-listen") +} + +#[inline] +pub fn is_disable_settings() -> bool { + is_some_hard_opton("disable-settings") +} + +#[inline] +pub fn is_disable_ab() -> bool { + is_some_hard_opton("disable-ab") +} + +#[inline] +pub fn is_disable_account() -> bool { + is_some_hard_opton("disable-account") +} + +#[inline] +pub fn is_disable_installation() -> bool { + is_some_hard_opton("disable-installation") +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/common.rs b/src/common.rs index b5c0c2c8c..181ed8736 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1477,6 +1477,11 @@ impl ClipboardContext { } pub fn load_custom_client() { + #[cfg(debug_assertions)] + if let Ok(data) = std::fs::read_to_string("./custom.txt") { + read_custom_client(data.trim()); + return; + } let Ok(cmd) = std::env::current_exe() else { return; }; @@ -1488,7 +1493,7 @@ pub fn load_custom_client() { log::error!("Failed to read custom client config"); return; }; - read_custom_client(&data); + read_custom_client(&data.trim()); } } @@ -1512,7 +1517,13 @@ pub fn read_custom_client(config: &str) { log::error!("Failed to parse custom client config"); return; }; - if let Some(default_settings) = data.remove("default_settings") { + + if let Some(app_name) = data.remove("app-name") { + if let Some(app_name) = app_name.as_str() { + *config::APP_NAME.write().unwrap() = app_name.to_owned(); + } + } + if let Some(default_settings) = data.remove("default-settings") { if let Some(default_settings) = default_settings.as_object() { for (k, v) in default_settings { let Some(v) = v.as_str() else { @@ -1537,7 +1548,7 @@ pub fn read_custom_client(config: &str) { } } } - if let Some(overwrite_settings) = data.remove("overwrite_settings") { + if let Some(overwrite_settings) = data.remove("override-settings") { if let Some(overwrite_settings) = overwrite_settings.as_object() { for (k, v) in overwrite_settings { let Some(v) = v.as_str() else { diff --git a/src/core_main.rs b/src/core_main.rs index 324024ce3..70a3189a6 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -3,7 +3,7 @@ use crate::client::translate; #[cfg(not(debug_assertions))] #[cfg(not(any(target_os = "android", target_os = "ios")))] use crate::platform::breakdown_callback; -use hbb_common::log; +use hbb_common::{config, log}; #[cfg(not(debug_assertions))] #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::platform::register_breakdown_handler; @@ -63,7 +63,7 @@ pub fn core_main() -> Option> { ] .contains(&arg.as_str()) { - if crate::flutter_ffi::is_qs().0 { + if config::is_incoming_only() { return None; } else { _is_flutter_invoke_new_connection = true; @@ -96,7 +96,7 @@ pub fn core_main() -> Option> { #[cfg(feature = "flutter")] { let (k, v) = ("LIBGL_ALWAYS_SOFTWARE", "1"); - if !hbb_common::config::Config::get_option("allow-always-software-render").is_empty() { + if !config::Config::get_option("allow-always-software-render").is_empty() { std::env::set_var(k, v); } else { std::env::remove_var(k); @@ -111,7 +111,7 @@ pub fn core_main() -> Option> { return core_main_invoke_new_connection(std::env::args()); } let click_setup = cfg!(windows) && args.is_empty() && crate::common::is_setup(&arg_exe); - if click_setup { + if click_setup && !config::is_disable_installation(){ args.push("--install".to_owned()); flutter_args.push("--install".to_string()); } @@ -188,6 +188,9 @@ pub fn core_main() -> Option> { } return None; } else if args[0] == "--silent-install" { + if config::is_disable_installation() { + return None; + } let res = platform::install_me( "desktopicon startmenu", "".to_owned(), @@ -202,7 +205,7 @@ pub fn core_main() -> Option> { } }; Toast::new(Toast::POWERSHELL_APP_ID) - .title(&hbb_common::config::APP_NAME.read().unwrap()) + .title(&config::APP_NAME.read().unwrap()) .text1(&text) .sound(Some(Sound::Default)) .duration(Duration::Short) diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index f6611510b..4171d2be1 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -42,6 +42,8 @@ lazy_static::lazy_static! { fn initialize(app_dir: &str) { flutter::async_tasks::start_flutter_async_runner(); *config::APP_DIR.write().unwrap() = app_dir.to_owned(); + // core_main's load_custom_client does not work for flutter since it is only applied to its load_library in main.c + crate::load_custom_client(); #[cfg(target_os = "android")] { // flexi_logger can't work when android_logger initialized. @@ -62,7 +64,12 @@ fn initialize(app_dir: &str) { #[cfg(target_os = "ios")] { use hbb_common::env_logger::*; - init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "debug")); + init_fro_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "debug")); + } + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + // core_main's init_log does not work for flutter since it is only applied to its load_library in main.c + hbb_common::init_log(false, "flutter_ffi"); } } @@ -1813,8 +1820,29 @@ pub fn main_support_remove_wallpaper() -> bool { support_remove_wallpaper() } -pub fn is_qs() -> SyncReturn { - SyncReturn(get_hard_option("connection-type".to_owned()) == "incoming") +pub fn is_incoming_only() -> SyncReturn { + SyncReturn(config::is_incoming_only()) +} + +pub fn is_outgoing_only() -> SyncReturn { + SyncReturn(config::is_outgoing_only()) +} + +pub fn is_disable_settings() -> SyncReturn { + SyncReturn(config::is_disable_settings()) +} + +pub fn is_disable_ab() -> SyncReturn { + SyncReturn(config::is_disable_ab()) +} + +pub fn is_disable_account() -> SyncReturn { + SyncReturn(config::is_disable_account()) +} + +// windows only +pub fn is_disable_installation() -> SyncReturn { + SyncReturn(config::is_disable_installation()) } /// Send a url scheme throught the ipc. diff --git a/src/platform/windows.rs b/src/platform/windows.rs index c33976c9f..b24b1bcc0 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1205,6 +1205,15 @@ if exist \"{tmp_path}\\{app_name} Tray.lnk\" del /f /q \"{tmp_path}\\{app_name} Config::set_option("api-server".into(), lic.api); } + let tray_shortcuts = if config::is_outgoing_only() { + "".to_owned() + } else { + format!(" +cscript \"{tray_shortcut}\" +copy /Y \"{tmp_path}\\{app_name} Tray.lnk\" \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\\" +") + }; + let cmds = format!( " {uninstall_str} @@ -1227,8 +1236,7 @@ reg add {subkey} /f /v EstimatedSize /t REG_DWORD /d {size} reg add {subkey} /f /v WindowsInstaller /t REG_DWORD /d 0 cscript \"{mk_shortcut}\" cscript \"{uninstall_shortcut}\" -cscript \"{tray_shortcut}\" -copy /Y \"{tmp_path}\\{app_name} Tray.lnk\" \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\\" +{tray_shortcuts} {shortcuts} copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{path}\\\" {dels} @@ -1237,19 +1245,11 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{path}\\\" {after_install} {sleep} ", - version=crate::VERSION, - build_date=crate::BUILD_DATE, - after_install=get_after_install(&exe), - sleep=if debug { - "timeout 300" - } else { - "" - }, - dels=if debug { - "" - } else { - &dels - }, + version = crate::VERSION, + build_date = crate::BUILD_DATE, + after_install = get_after_install(&exe), + sleep = if debug { "timeout 300" } else { "" }, + dels = if debug { "" } else { &dels }, copy_exe = copy_exe_cmd(&src_exe, &exe, &path)?, import_config = get_import_config(&exe), ); @@ -2383,6 +2383,9 @@ oLink.Save } fn get_import_config(exe: &str) -> String { + if config::is_outgoing_only() { + return "".to_string(); + } format!(" sc stop {app_name} sc delete {app_name} @@ -2397,6 +2400,9 @@ sc delete {app_name} } fn get_create_service(exe: &str) -> String { + if config::is_outgoing_only() { + return "".to_string(); + } let stop = Config::get_option("stop-service") == "Y"; if stop { format!(" diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 07e45e77b..f89179633 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -12,7 +12,7 @@ use uuid::Uuid; use hbb_common::{ allow_err, anyhow::{self, bail}, - config::{Config, CONNECT_TIMEOUT, READ_TIMEOUT, REG_INTERVAL, RENDEZVOUS_PORT}, + config::{self, Config, CONNECT_TIMEOUT, READ_TIMEOUT, REG_INTERVAL, RENDEZVOUS_PORT}, futures::future::join_all, log, protobuf::Message as _, @@ -61,6 +61,11 @@ impl RendezvousMediator { } pub async fn start_all() { + if config::is_outgoing_only() { + loop { + sleep(1.).await; + } + } crate::hbbs_http::sync::start(); let mut nat_tested = false; check_zombie(); @@ -449,7 +454,7 @@ impl RendezvousMediator { async fn handle_intranet(&self, fla: FetchLocalAddr, server: ServerPtr) -> ResultType<()> { let relay_server = self.get_relay_server(fla.relay_server); - if !is_ipv4(&self.addr) { + if !is_ipv4(&self.addr) || config::is_disable_tcp_listen() { // nat64, go relay directly, because current hbbs will crash if demangle ipv6 address let uuid = Uuid::new_v4().to_string(); return self @@ -488,6 +493,7 @@ impl RendezvousMediator { let relay_server = self.get_relay_server(ph.relay_server); if ph.nat_type.enum_value() == Ok(NatType::SYMMETRIC) || Config::get_nat_type() == NatType::SYMMETRIC as i32 + || config::is_disable_tcp_listen() { let uuid = Uuid::new_v4().to_string(); return self