Merge translate mode

This commit is contained in:
Asura
2022-08-04 16:11:37 +08:00
91 changed files with 2869 additions and 1419 deletions

View File

@@ -104,6 +104,10 @@ icon.file {
background:url('data: image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAH+CAESEN8jyZkcIb5N/ONy3vmHhmiGjUm7UwS+YAAAHZSURBVGje7dnbboMwDIBhBwgQoFAO7Ta//4NOqCAXYZQstatq4r+r5ubrgQSpg8iyC4ZURa+PlIpQYGiwrzyeHtYZjAL8T05O4H8BbbKvFgRa4NoBU8pXeYEkDDgaaLQBcwJrmeErJQB/7wes3QBWGnCIX0+AQycL1PO6BMwPa0nA4ZxbgTvOjUYMGPHRnZkQAY4mxPZBjmy53E7ukSkFKYB/D4XsWZQx64sCeYebOogGsoOBYvv6/UCb8F0IOBZ0TlP6lEYdANY350AJqB9/qPVuOI5evw4A1hgLigAlepnyxW80bcCcwN++A2s82Vcu02ta+ceq9BoL5KGTTRwQPlpqA3gCnwWU2kCDgeWRQPj2jAPCDxgCMjhI6uZnToDpvd/BJeFrJQB/fsAa02gCt3mi1wNuy8GgBNDZlysBNNSrADVSjcJl6vCpUn6jOdx0kz0q6PMhQRa4465SFKhx35cgUCBTwj2/NHwZAb71qR8GEP2H1XcmAtBPTEO67GP6FUUAIKGABbDLQ0EArhN2sAIGesRO+iyy+RMAjckVTlMCKFVAbh/4Af9OPgG61SkDVco3BQGT3GXaDAnTIAcYZDuBTwGsAGDxuBFeAQqIqwoFMlAVLrHr/wId5MPt0nilGgAAAABJRU5ErkJggg==');
}
icon.restart {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAB7BAAAewQHDaVRTAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAbhJREFUWIXVlrFqFGEUhb+7UYxaWCQKlrKKxaZSQVGDJih2tj6MD2DnMwiWvoAIRnENIpZiYxEro6IooiS7SPwsMgNLkk3mjmYmnmb45/73nMNwz/x/qH3gMu2gH6rAU+Blw+Lngau4jpmGxVF7qp1iPWjaQKnZ2WnXbuP/NqAeUPc3ZkA9XDwvqc+BVWCgPlJ7tRwUKThZce819b46VH+pfXVRXVO/q2cSul3VOgZUl0ejq86r39TXI8mqZKDuDEwCw3IREQvAbWAGmMsQZQ0sAl3gHPB1Q+0e8BuYzRDuy2yOiFVgaUxtRf0ETGc4syk4rc6PqU0Cx9j8Zf6dAeAK8Fi9sUXtFjABvEgxJlNwRP2svlNPjbw/q35U36oTFbnyMSwabxb/gB/qA3VBHagrauV7RW0DRfP1IvMlXqkXkhz1DYyQTKtHa/Z2VVMx3IiI+PI3/bCHjuOpFrSnAMpL6QfgTcMGesDx0kBr2BMzsNyi/vtQu8CJlgwsRbZDnWP90NkKaxHxJMOXMqAeAn5u0ydwMCKGY+qbkB3C2W3EKWoXk5zVoHbUZ+6Mh7tl4G4F8RJ3qvL+AfV3r5Vdpj70AAAAAElFTkSuQmCC');
}
div.buttons {
width: *;
border-spacing: 0.5em;

View File

@@ -14,7 +14,7 @@ use hbb_common::{
fs, get_version_number, log,
message_proto::*,
protobuf::Message as _,
tokio::{self, sync::mpsc, task::spawn_blocking}
tokio::{self, sync::mpsc, task::spawn_blocking},
};
use sciter::{make_args, Element, Value, HELEMENT};
use std::{
@@ -90,6 +90,7 @@ impl ConnectionManager {
clipboard: bool,
audio: bool,
file: bool,
restart: bool,
tx: mpsc::UnboundedSender<Data>,
) {
self.call(
@@ -104,7 +105,8 @@ impl ConnectionManager {
keyboard,
clipboard,
audio,
file
file,
restart
),
);
self.write().unwrap().senders.insert(id, tx);
@@ -158,8 +160,8 @@ impl ConnectionManager {
id,
file_num,
mut files,
overwrite_detection
} => {
let od = can_enable_overwrite_detection(get_version_number(VERSION));
// cm has no show_hidden context
// dummy remote, show_hidden, is_remote
write_jobs.push(fs::TransferJob::new_write(
@@ -177,7 +179,7 @@ impl ConnectionManager {
..Default::default()
})
.collect(),
od,
overwrite_detection,
));
}
ipc::FS::CancelWrite { id } => {
@@ -489,11 +491,11 @@ async fn start_ipc(cm: ConnectionManager) {
}
Ok(Some(data)) => {
match data {
Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled} => {
Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart} => {
log::debug!("conn_id: {}", id);
conn_id = id;
tx_file.send(ClipboardFileData::Enable((id, file_transfer_enabled))).ok();
cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, tx.clone());
cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, tx.clone());
}
Data::Close => {
tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok();

View File

@@ -46,6 +46,7 @@ class Body: Reactor.Component
<div class={!c.clipboard ? "disabled" : ""} title={translate('Allow using clipboard')}><icon .clipboard /></div>
<div class={!c.audio ? "disabled" : ""} title={translate('Allow hearing sound')}><icon .audio /></div>
<div class={!c.file ? "disabled" : ""} title={translate('Allow file copy and paste')}><icon .file /></div>
<div class={!c.restart ? "disabled" : ""} title={translate('Allow remote restart')}><icon .restart /></div>
</div>}
{c.port_forward ? <div>Port Forwarding: {c.port_forward}</div> : ""}
<div style="size:*"/>
@@ -108,6 +109,15 @@ class Body: Reactor.Component
});
}
event click $(icon.restart) {
var { cid, connection } = this;
checkClickTime(function() {
connection.restart = !connection.restart;
body.update();
handler.switch_permission(cid, "restart", connection.restart);
});
}
event click $(button#accept) {
var { cid, connection } = this;
checkClickTime(function() {
@@ -266,7 +276,7 @@ function bring_to_top(idx=-1) {
}
}
handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file) {
handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart) {
stdout.println("new connection #" + id + ": " + peer_id);
var conn;
connections.map(function(c) {
@@ -283,7 +293,7 @@ handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, na
port_forward: port_forward,
name: name, authorized: authorized, time: new Date(),
keyboard: keyboard, clipboard: clipboard, msgs: [], unreaded: 0,
audio: audio, file: file
audio: audio, file: file, restart: restart
});
body.cur = connections.length - 1;
bring_to_top();

View File

@@ -199,6 +199,7 @@ class Header: Reactor.Component {
{handler.get_audit_server() && <li #note>{translate('Note')}</li>}
<div .separator />
{keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ? <li #ctrl-alt-del>{translate('Insert')} Ctrl + Alt + Del</li> : ""}
{restart_enabled && (pi.platform == "Linux" || pi.platform == "Windows" || pi.platform == "Mac OS") ? <li #restart_remote_device>{translate('Restart Remote Device')}</li> : ""}
{keyboard_enabled ? <li #lock-screen>{translate('Insert Lock')}</li> : ""}
{keyboard_enabled && pi.platform == "Windows" && pi.sas_enabled ? <li #block-input>{translate("Block user input")}</li> : ""}
<li #refresh>{translate('Refresh')}</li>
@@ -317,6 +318,12 @@ class Header: Reactor.Component {
handler.ctrl_alt_del();
}
event click $(#restart_remote_device) {
msgbox("restart-confirmation", translate("Restart Remote Device"), translate("Are you sure you want to restart") + " " + pi.username + "@" + pi.hostname + "(" + get_id() + ") ?", function(res=null) {
if (res != null) handler.restart_remote_device();
});
}
event click $(#lock-screen) {
handler.lock_screen();
}

View File

@@ -3,7 +3,7 @@ stdout.println("current platform:", OS);
stdout.println("is_xfce: ", is_xfce);
// html min-width, min-height not working on mac, below works for all
view.windowMinSize = (scaleIt(500), scaleIt(300));
view.windowMinSize = (scaleIt(560), scaleIt(300));
var app;
var tmp = handler.get_connect_status();
@@ -212,8 +212,8 @@ class Enhancements: Reactor.Component {
self.timer(1ms, function() { me.toggleMenuState() });
return <li>{translate('Enhancements')}
<menu #enhancements-menu>
{has_hwcodec ? <li #enable-hwcodec><span>{svg_checkmark}</span>{translate("Hardware Codec")}{"(beta)"}</li> : ""}
<li #enable-abr><span>{svg_checkmark}</span>{translate("Adaptive Bitrate")}{"(beta)"}</li>
{has_hwcodec ? <li #enable-hwcodec><span>{svg_checkmark}</span>{translate("Hardware Codec")} (beta)</li> : ""}
<li #enable-abr><span>{svg_checkmark}</span>{translate("Adaptive Bitrate")} (beta)</li>
</menu>
</li>;
}
@@ -274,6 +274,7 @@ class MyIdMenu: Reactor.Component {
<li #enable-keyboard><span>{svg_checkmark}</span>{translate('Enable Keyboard/Mouse')}</li>
<li #enable-clipboard><span>{svg_checkmark}</span>{translate('Enable Clipboard')}</li>
<li #enable-file-transfer><span>{svg_checkmark}</span>{translate('Enable File Transfer')}</li>
<li #enable-remote-restart><span>{svg_checkmark}</span>{translate('Enable Remote Restart')}</li>
<li #enable-tunnel><span>{svg_checkmark}</span>{translate('Enable TCP Tunneling')}</li>
<AudioInputs />
<Enhancements />
@@ -529,9 +530,7 @@ class App: Reactor.Component
<MyIdMenu />
{key_confirmed ? <input type="text" readonly value={formatId(get_id())}/> : translate("Generating ...")}
</div>
<div .your-desktop>
<PasswordArea />
</div>
<PasswordArea />
</div>
{!is_win || handler.is_installed() ? "": <InstallMe />}
{software_update_url ? <UpdateMe /> : ""}
@@ -802,8 +801,8 @@ function watch_screen_recording() {
class PasswordEyeArea : Reactor.Component {
render() {
var show = handler.is_random_password_valid();
var value = show ? handler.get_random_password() : "-";
var method = handler.get_option('verification-method');
var value = method != 'use-permanent-password' ? password_cache[0] : "-";
return
<div .eye-area style="width: *">
<input|text @{this.input} readonly value={value} />
@@ -812,95 +811,49 @@ class PasswordEyeArea : Reactor.Component {
}
event click $(svg#refresh-password) (_, me) {
if (handler.is_random_password_valid()) handler.update_random_password();
handler.update_temporary_password();
this.update();
}
}
var verificationMethodMenu;
class VerificationMethodMenu: Reactor.Component {
var temporaryPasswordLengthMenu;
class TemporaryPasswordLengthMenu: Reactor.Component {
function this() {
verificationMethodMenu = this;
temporaryPasswordLengthMenu = this;
}
function render() {
if (!this.show) return <li />;
var me = this;
var method = handler.get_option('verification-method');
self.timer(1ms, function() { me.toggleMenuState() });
return <li>{translate('Verification Method')}
<menu #verification-method>
<li #verification-method-security><span>{svg_checkmark}</span>{translate('Enable security password')}</li>
<li #verification-method-random><span>{svg_checkmark}</span>{translate('Enable random password')}</li>
return <li disabled={ method == 'use-permanent-password' ? "true" : "false" }>{translate("Set temporary password length")}
<menu #temporary-password-length>
<li #temporary-password-length-6><span>{svg_checkmark}</span>6</li>
<li #temporary-password-length-8><span>{svg_checkmark}</span>8</li>
<li #temporary-password-length-10><span>{svg_checkmark}</span>10</li>
</menu>
</li>;
}
function toggleMenuState() {
var security_enabled = handler.is_security_password_enabled();
var random_enabled = handler.is_random_password_enabled();
var onetime_enabled = handler.is_onetime_password_enabled();
for (var (index, el) in this.$$(menu#verification-method>li)) {
if (index == 0) el.attributes.toggleClass("selected", security_enabled);
if (index == 1) el.attributes.toggleClass("selected", random_enabled);
var length = handler.get_option("temporary-password-length");
var index = ['6', '8', '10'].indexOf(length);
if (index < 0) index = 0;
for (var (i, el) in this.$$(menu#temporary-password-length>li)) {
el.attributes.toggleClass("selected", i == index);
}
}
event click $(menu#verification-method>li) (_, me) {
switch (me.id.substring('verification-method-'.length)) {
case 'security':
{
var security_enabled = handler.is_security_password_enabled();
handler.set_security_password_enabled(!security_enabled);
}
break;
case 'random':
{
var random_enabled = handler.is_random_password_enabled();
handler.set_random_password_enabled(!random_enabled);
}
break;
event click $(menu#temporary-password-length>li) (_, me) {
var length = me.id.substring('temporary-password-length-'.length);
var old_length = handler.get_option('temporary-password-length');
if (length != old_length) {
handler.set_option('temporary-password-length', length);
handler.update_temporary_password();
this.toggleMenuState();
passwordArea.update();
}
this.toggleMenuState();
passwordArea.update();
}
}
var randomPasswordUpdateMethodMenu;
class RandomPasswordUpdateMethodMenu: Reactor.Component {
function this() {
randomPasswordUpdateMethodMenu = this;
}
function render() {
if (!this.show) return <li />;
var me = this;
var random_enabled = handler.is_random_password_enabled();
self.timer(1ms, function() { me.toggleMenuState() });
return <li disabled={ random_enabled ? "false" : "true" }>{translate('Random Password After Session')}
<menu #random-password-update-method>
<li #random-password-update-method-keep><span>{svg_checkmark}</span>{translate('Keep')}</li>
<li #random-password-update-method-update><span>{svg_checkmark}</span>{translate('Update')}</li>
<li #random-password-update-method-disable><span>{svg_checkmark}</span>{translate('Disable')}</li>
</menu>
</li>;
}
function toggleMenuState() {
var method = handler.random_password_update_method();
for (var (index, el) in this.$$(menu#random-password-update-method>li)) {
if (index == 0) el.attributes.toggleClass("selected", method == "KEEP");
if (index == 1) el.attributes.toggleClass("selected", method == "UPDATE");
if (index == 2) el.attributes.toggleClass("selected", method == "DISABLE");
}
}
event click $(menu#random-password-update-method>li) (_, me) {
if (me.id === 'random-password-update-method-keep') handler.set_random_password_update_method("KEEP");
if (me.id === 'random-password-update-method-update') handler.set_random_password_update_method("UPDATE");
if (me.id === 'random-password-update-method-disable') handler.set_random_password_update_method("DISABLE");
this.toggleMenuState();
passwordArea.update();
}
}
@@ -911,11 +864,11 @@ class PasswordArea: Reactor.Component {
}
function render() {
var onetime_enabled = handler.is_onetime_password_enabled();
var me = this;
self.timer(1ms, function() { me.toggleMenuState() });
return
<div>
<div>{translate(onetime_enabled ? 'Onetime Password' : 'Password')}</div>
<div .your-desktop>
<div>{translate('Password')}</div>
<div .password style="flow:horizontal">
{this.renderPop()}
<PasswordEyeArea />
@@ -925,35 +878,39 @@ class PasswordArea: Reactor.Component {
}
function renderPop() {
var security_enabled = handler.is_security_password_enabled();
var random_enabled = handler.is_random_password_enabled();
var onetime_enabled = handler.is_onetime_password_enabled();
var onetime_activated = handler.is_onetime_password_activated();
var method = handler.get_option('verification-method');
return <popup><menu.context #edit-password-context>
<li #enable-onetime-password disabled={ random_enabled ? "false" : "true" }>{translate(onetime_enabled ? "Disable onetime password" : "Enable onetime password")}</li>
<li #activate-onetime-password disabled={ !random_enabled || !onetime_enabled || onetime_activated ? "true" : "false" }>{translate('Activate onetime password')}</li>
<li #use-temporary-password><span>{svg_checkmark}</span>{translate('Use temporary password')}</li>
<li #use-permanent-password><span>{svg_checkmark}</span>{translate('Use permanent password')}</li>
<li #use-both-passwords><span>{svg_checkmark}</span>{translate('Use both passwords')}</li>
<div .separator />
<VerificationMethodMenu />
<div .separator />
<li #set-password disabled={ security_enabled ? "false" : "true" }>{translate('Set security password')}</li>
<div .separator />
<RandomPasswordUpdateMethodMenu />
<li #set-password disabled={ method == 'use-temporary-password' ? "true" : "false" }>{translate('Set permanent password')}</li>
<TemporaryPasswordLengthMenu />
</menu></popup>;
}
function toggleMenuState() {
var id = handler.get_option('verification-method');
if (id != 'use-temporary-password' && id != 'use-permanent-password')
id = 'use-both-passwords';
for (var el in [this.$(li#use-temporary-password), this.$(li#use-permanent-password), this.$(li#use-both-passwords)]) {
el.attributes.toggleClass("selected", el.id == id);
}
}
event click $(svg#edit) (_, me) {
randomPasswordUpdateMethodMenu.update({show: true });
verificationMethodMenu.update({show: true });
temporaryPasswordLengthMenu.update({show: true });
var menu = $(menu#edit-password-context);
me.popup(menu);
}
event click $(li#set-password) {
var me = this;
var password = handler.permanent_password();
var value_field = password.length == 0 ? "" : "value=" + password;
msgbox("custom-password", translate("Set Password"), "<div .form .set-password> \
<div><span>" + translate('Password') + ":</span><input|password(password) .outline-focus /></div> \
<div><span>" + translate('Confirmation') + ":</span><input|password(confirmation) /></div> \
<div><span>" + translate('Password') + ":</span><input|password(password) .outline-focus " + value_field + " /></div> \
<div><span>" + translate('Confirmation') + ":</span><input|password(confirmation) " + value_field + " /></div> \
</div> \
", function(res=null) {
if (!res) return;
@@ -965,31 +922,40 @@ class PasswordArea: Reactor.Component {
if (p0 != p1) {
return translate("The confirmation is not identical.");
}
handler.set_security_password(p0);
handler.set_permanent_password(p0);
me.update();
});
}
event click $(li#enable-onetime-password) {
var onetime_enabled = handler.is_onetime_password_enabled();
handler.set_onetime_password_enabled(!onetime_enabled);
passwordArea.update();
}
event click $(li#activate-onetime-password) {
handler.set_onetime_password_activated(true);
passwordArea.update();
event click $(menu#edit-password-context>li) (_, me) {
if (me.id.indexOf('use-') == 0) {
handler.set_option('verification-method', me.id);
this.toggleMenuState();
passwordArea.update();
}
}
}
var last_password_description = "";
var password_cache = ["","",""];
function updatePasswordArea() {
self.timer(1s, function() {
var description = handler.password_description();
if (last_password_description != description) {
last_password_description = description
passwordArea.update();
var temporary_password = handler.temporary_password();
var verification_method = handler.get_option('verification-method');
var temporary_password_length = handler.get_option('temporary-password-length');
var update = false;
if (password_cache[0] != temporary_password) {
password_cache[0] = temporary_password;
update = true;
}
if (password_cache[1] != verification_method) {
password_cache[1] = verification_method;
update = true;
}
if (password_cache[2] != temporary_password_length) {
password_cache[2] = temporary_password_length;
update = true;
}
if (update) passwordArea.update();
updatePasswordArea();
});
}

View File

@@ -192,7 +192,7 @@ pub fn make_menubar(host: Rc<Host>, is_index: bool) {
app_menu.addItem_(new_item);
} else {
// When app launched without argument, is the main panel.
let about_item = make_menu_item("About", "a", SHOW_ABOUT_TAG);
let about_item = make_menu_item("About", "", SHOW_ABOUT_TAG);
app_menu.addItem_(about_item);
let separator = NSMenuItem::separatorItem(nil).autorelease();
app_menu.addItem_(separator);

View File

@@ -91,7 +91,7 @@ class MsgboxComponent: Reactor.Component {
var color = this.getColor();
var icon = this.getIcon(color);
var content = this.getContent();
var hasCancel = this.type.indexOf("error") < 0 && this.type.indexOf("nocancel") < 0;
var hasCancel = this.type.indexOf("error") < 0 && this.type.indexOf("nocancel") < 0 && this.type != "restarting";
var hasOk = this.type != "connecting" && this.type != "success" && this.type.indexOf("nook") < 0;
var hasClose = this.type.indexOf("hasclose") >= 0;
var show_progress = this.type == "connecting";

View File

@@ -23,10 +23,6 @@ use clipboard::{
get_rx_clip_client, server_clip_file,
};
use enigo::{self, Enigo, KeyboardControllable};
use hbb_common::fs::{
can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult,
RemoveJobMeta,
};
use hbb_common::{
allow_err,
config::{Config, LocalConfig, PeerConfig},
@@ -44,6 +40,13 @@ use hbb_common::{
};
use hbb_common::{config::TransferSerde, fs::TransferJobMeta};
use rdev::{Event, EventType::*, Key as RdevKey};
use hbb_common::{
fs::{
can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult,
RemoveJobMeta,
},
get_version_number,
};
#[cfg(windows)]
use crate::clipboard_file::*;
@@ -89,6 +92,7 @@ pub struct Handler {
inner: Arc<RwLock<HandlerInner>>,
cmd: String,
id: String,
password: String,
args: Vec<String>,
lc: Arc<RwLock<LoginConfigHandler>>,
}
@@ -238,23 +242,16 @@ impl sciter::EventHandler for Handler {
fn has_hwcodec();
fn supported_hwcodec();
fn change_prefer_codec();
fn restart_remote_device();
}
}
#[derive(Debug, Default)]
struct QualityStatus {
speed: Option<String>,
fps: Option<i32>,
delay: Option<i32>,
target_bitrate: Option<i32>,
codec_format: Option<CodecFormat>,
}
impl Handler {
pub fn new(cmd: String, id: String, args: Vec<String>) -> Self {
pub fn new(cmd: String, id: String, password: String, args: Vec<String>) -> Self {
let me = Self {
cmd,
id: id.clone(),
password: password.clone(),
args,
..Default::default()
};
@@ -480,6 +477,17 @@ impl Handler {
self.send(Data::Message(msg));
}
fn restart_remote_device(&mut self) {
let mut lc = self.lc.write().unwrap();
lc.restarting_remote_device = true;
let msg = lc.restart_remote_device();
self.send(Data::Message(msg));
}
pub fn is_restarting_remote_device(&self) -> bool {
self.lc.read().unwrap().restarting_remote_device
}
fn t(&self, name: String) -> String {
crate::client::translate(name)
}
@@ -993,7 +1001,7 @@ impl Handler {
fn transfer_file(&mut self) {
let id = self.get_id();
let args = vec!["--file-transfer", &id];
let args = vec!["--file-transfer", &id, &self.password];
if let Err(err) = crate::run_me(args) {
log::error!("Failed to spawn file transfer: {}", err);
}
@@ -1001,7 +1009,7 @@ impl Handler {
fn tunnel(&mut self) {
let id = self.get_id();
let args = vec!["--port-forward", &id];
let args = vec!["--port-forward", &id, &self.password];
if let Err(err) = crate::run_me(args) {
log::error!("Failed to spawn IP tunneling: {}", err);
}
@@ -1390,6 +1398,7 @@ async fn start_one_port_forward(
handler.lc.write().unwrap().port_forward = (remote_host, remote_port);
if let Err(err) = crate::port_forward::listen(
handler.id.clone(),
handler.password.clone(),
port,
handler.clone(),
receiver,
@@ -1626,8 +1635,13 @@ impl Remote {
}
}
} else {
log::info!("Reset by the peer");
self.handler.msgbox("error", "Connection Error", "Reset by the peer");
if self.handler.is_restarting_remote_device() {
log::info!("Restart remote device");
self.handler.msgbox("restarting", "Restarting Remote Device", "remote_restarting_tip");
} else {
log::info!("Reset by the peer");
self.handler.msgbox("error", "Connection Error", "Reset by the peer");
}
break;
}
}
@@ -1808,7 +1822,6 @@ impl Remote {
}
async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool {
// log::info!("new msg from ui, {}",data);
match data {
Data::Close => {
let mut misc = Misc::new();
@@ -2197,6 +2210,22 @@ impl Remote {
true
}
async fn send_opts_after_login(&self, peer: &mut Stream) {
if let Some(opts) = self
.handler
.lc
.read()
.unwrap()
.get_option_message_after_login()
{
let mut misc = Misc::new();
misc.set_option(opts);
let mut msg_out = Message::new();
msg_out.set_misc(misc);
allow_err!(peer.send(&msg_out).await);
}
}
async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool {
if let Ok(msg_in) = Message::parse_from_bytes(&data) {
match msg_in.union {
@@ -2205,6 +2234,7 @@ impl Remote {
self.first_frame = true;
self.handler.call2("closeSuccess", &make_args!());
self.handler.call("adaptSize", &make_args!());
self.send_opts_after_login(peer).await;
}
let incomming_format = CodecFormat::from(&vf);
if self.video_format != incomming_format {
@@ -2217,7 +2247,9 @@ impl Remote {
self.video_sender.send(MediaData::VideoFrame(vf)).ok();
}
Some(message::Union::Hash(hash)) => {
self.handler.handle_hash(hash, peer).await;
self.handler
.handle_hash(&self.handler.password.clone(), hash, peer)
.await;
}
Some(message::Union::LoginResponse(lr)) => match lr.union {
Some(login_response::Union::Error(err)) => {
@@ -2458,6 +2490,10 @@ impl Remote {
self.handler
.call2("setPermission", &make_args!("file", p.enabled));
}
Permission::Restart => {
self.handler
.call2("setPermission", &make_args!("restart", p.enabled));
}
}
}
Some(misc::Union::SwitchDisplay(s)) => {
@@ -2513,14 +2549,14 @@ impl Remote {
match notification.union {
Some(back_notification::Union::BlockInputState(state)) => {
self.handle_back_msg_block_input(
state.enum_value_or(back_notification::BlockInputState::StateUnknown),
state.enum_value_or(back_notification::BlockInputState::BlkStateUnknown),
)
.await;
}
Some(back_notification::Union::PrivacyModeState(state)) => {
if !self
.handle_back_msg_privacy_mode(
state.enum_value_or(back_notification::PrivacyModeState::StateUnknown),
state.enum_value_or(back_notification::PrivacyModeState::PrvStateUnknown),
)
.await
{
@@ -2539,18 +2575,18 @@ impl Remote {
async fn handle_back_msg_block_input(&mut self, state: back_notification::BlockInputState) {
match state {
back_notification::BlockInputState::OnSucceeded => {
back_notification::BlockInputState::BlkOnSucceeded => {
self.update_block_input_state(true);
}
back_notification::BlockInputState::OnFailed => {
back_notification::BlockInputState::BlkOnFailed => {
self.handler
.msgbox("custom-error", "Block user input", "Failed");
self.update_block_input_state(false);
}
back_notification::BlockInputState::OffSucceeded => {
back_notification::BlockInputState::BlkOffSucceeded => {
self.update_block_input_state(false);
}
back_notification::BlockInputState::OffFailed => {
back_notification::BlockInputState::BlkOffFailed => {
self.handler
.msgbox("custom-error", "Unblock user input", "Failed");
}
@@ -2572,7 +2608,7 @@ impl Remote {
state: back_notification::PrivacyModeState,
) -> bool {
match state {
back_notification::PrivacyModeState::OnByOther => {
back_notification::PrivacyModeState::PrvOnByOther => {
self.handler.msgbox(
"error",
"Connecting...",
@@ -2580,46 +2616,46 @@ impl Remote {
);
return false;
}
back_notification::PrivacyModeState::NotSupported => {
back_notification::PrivacyModeState::PrvNotSupported => {
self.handler
.msgbox("custom-error", "Privacy mode", "Unsupported");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::OnSucceeded => {
back_notification::PrivacyModeState::PrvOnSucceeded => {
self.handler
.msgbox("custom-nocancel", "Privacy mode", "In privacy mode");
self.update_privacy_mode(true);
}
back_notification::PrivacyModeState::OnFailedDenied => {
back_notification::PrivacyModeState::PrvOnFailedDenied => {
self.handler
.msgbox("custom-error", "Privacy mode", "Peer denied");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::OnFailedPlugin => {
back_notification::PrivacyModeState::PrvOnFailedPlugin => {
self.handler
.msgbox("custom-error", "Privacy mode", "Please install plugins");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::OnFailed => {
back_notification::PrivacyModeState::PrvOnFailed => {
self.handler
.msgbox("custom-error", "Privacy mode", "Failed");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::OffSucceeded => {
back_notification::PrivacyModeState::PrvOffSucceeded => {
self.handler
.msgbox("custom-nocancel", "Privacy mode", "Out privacy mode");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::OffByPeer => {
back_notification::PrivacyModeState::PrvOffByPeer => {
self.handler
.msgbox("custom-error", "Privacy mode", "Peer exit");
self.update_privacy_mode(false);
}
back_notification::PrivacyModeState::OffFailed => {
back_notification::PrivacyModeState::PrvOffFailed => {
self.handler
.msgbox("custom-error", "Privacy mode", "Failed to turn off");
}
back_notification::PrivacyModeState::OffUnknown => {
back_notification::PrivacyModeState::PrvOffUnknown => {
self.handler
.msgbox("custom-error", "Privacy mode", "Turned off");
// log::error!("Privacy mode is turned off with unknown reason");
@@ -2710,6 +2746,9 @@ impl Interface for Handler {
pi_sciter.set_item("hostname", pi.hostname.clone());
pi_sciter.set_item("platform", pi.platform.clone());
pi_sciter.set_item("sas_enabled", pi.sas_enabled);
if get_version_number(&pi.version) < get_version_number("1.1.10") {
self.call2("setPermission", &make_args!("restart", false));
}
if self.is_file_transfer() {
if pi.username.is_empty() {
self.on_error("No active console user logged on, please connect and logon first.");
@@ -2777,8 +2816,8 @@ impl Interface for Handler {
self.start_keyboard_hook();
}
async fn handle_hash(&mut self, hash: Hash, peer: &mut Stream) {
handle_hash(self.lc.clone(), hash, self, peer).await;
async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream) {
handle_hash(self.lc.clone(), pass, hash, self, peer).await;
}
async fn handle_login_from_ui(&mut self, password: String, remember: bool, peer: &mut Stream) {

View File

@@ -11,6 +11,7 @@ var keyboard_enabled = true; // server side
var clipboard_enabled = true; // server side
var audio_enabled = true; // server side
var file_enabled = true; // server side
var restart_enabled = true; // server side
var scroll_body = $(body);
handler.setDisplay = function(x, y, w, h) {
@@ -505,6 +506,7 @@ handler.setPermission = function(name, enabled) {
if (name == "audio") audio_enabled = enabled;
if (name == "file") file_enabled = enabled;
if (name == "clipboard") clipboard_enabled = enabled;
if (name == "restart") restart_enabled = enabled;
input_blocked = false;
header.update();
});