Merge pull request #5208 from dignow/fix/win_clipboard
fix, win file clipboard, when authorized by the remote
This commit is contained in:
commit
9b7e5b38ad
@ -410,18 +410,25 @@ class ServerModel with ChangeNotifier {
|
|||||||
updateClientState([String? json]) async {
|
updateClientState([String? json]) async {
|
||||||
if (isTest) return;
|
if (isTest) return;
|
||||||
var res = await bind.cmGetClientsState();
|
var res = await bind.cmGetClientsState();
|
||||||
|
List<dynamic> clientsJson;
|
||||||
try {
|
try {
|
||||||
final List clientsJson = jsonDecode(res);
|
clientsJson = jsonDecode(res);
|
||||||
_clients.clear();
|
} catch (e) {
|
||||||
tabController.state.value.tabs.clear();
|
debugPrint("Failed to decode clientsJson: '$res', error $e");
|
||||||
for (var clientJson in clientsJson) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_clients.clear();
|
||||||
|
tabController.state.value.tabs.clear();
|
||||||
|
|
||||||
|
for (var clientJson in clientsJson) {
|
||||||
|
try {
|
||||||
final client = Client.fromJson(clientJson);
|
final client = Client.fromJson(clientJson);
|
||||||
_clients.add(client);
|
_clients.add(client);
|
||||||
_addTab(client);
|
_addTab(client);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Failed to decode clientJson '$clientJson', error $e");
|
||||||
}
|
}
|
||||||
notifyListeners();
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint("Failed to updateClientState:$e");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ struct MsgChannel {
|
|||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref VEC_MSG_CHANNEL: RwLock<Vec<MsgChannel>> = Default::default();
|
static ref VEC_MSG_CHANNEL: RwLock<Vec<MsgChannel>> = Default::default();
|
||||||
static ref CLIENT_CONN_ID_COUNTER: Mutex<i32> = Mutex::new(0);
|
static ref CLIENT_CONN_ID_COUNTER: Mutex<i32> = Mutex::new(0);
|
||||||
|
static ref LAST_FILE_FORMAT_LIST: Arc<Mutex<Option<ClipboardFile>>> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClipboardFile {
|
impl ClipboardFile {
|
||||||
@ -90,6 +91,11 @@ impl ClipboardFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_last_file_format_list() -> Option<ClipboardFile> {
|
||||||
|
LAST_FILE_FORMAT_LIST.lock().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_client_conn_id(session_uuid: &SessionID) -> Option<i32> {
|
pub fn get_client_conn_id(session_uuid: &SessionID) -> Option<i32> {
|
||||||
VEC_MSG_CHANNEL
|
VEC_MSG_CHANNEL
|
||||||
.read()
|
.read()
|
||||||
@ -561,6 +567,7 @@ extern "C" fn client_format_list(
|
|||||||
}
|
}
|
||||||
log::debug!("client_format_list called, client id: {}, format_list: {:?}", conn_id, &format_list);
|
log::debug!("client_format_list called, client id: {}, format_list: {:?}", conn_id, &format_list);
|
||||||
let data = ClipboardFile::FormatList { format_list };
|
let data = ClipboardFile::FormatList { format_list };
|
||||||
|
*LAST_FILE_FORMAT_LIST.lock().unwrap() = Some(data.clone());
|
||||||
// no need to handle result here
|
// no need to handle result here
|
||||||
if conn_id == 0 {
|
if conn_id == 0 {
|
||||||
// msg_channel is used for debug, VEC_MSG_CHANNEL cannot be inspected by the debugger.
|
// msg_channel is used for debug, VEC_MSG_CHANNEL cannot be inspected by the debugger.
|
||||||
|
@ -6,7 +6,9 @@ use std::sync::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend};
|
use clipboard::{
|
||||||
|
cliprdr::CliprdrClientContext, empty_clipboard, get_last_file_format_list, ContextSend,
|
||||||
|
};
|
||||||
use crossbeam_queue::ArrayQueue;
|
use crossbeam_queue::ArrayQueue;
|
||||||
use hbb_common::config::{PeerConfig, TransferSerde};
|
use hbb_common::config::{PeerConfig, TransferSerde};
|
||||||
use hbb_common::fs::{
|
use hbb_common::fs::{
|
||||||
@ -56,6 +58,7 @@ pub struct Remote<T: InvokeUiSession> {
|
|||||||
remove_jobs: HashMap<i32, RemoveJob>,
|
remove_jobs: HashMap<i32, RemoveJob>,
|
||||||
timer: Interval,
|
timer: Interval,
|
||||||
last_update_jobs_status: (Instant, HashMap<i32, u64>),
|
last_update_jobs_status: (Instant, HashMap<i32, u64>),
|
||||||
|
is_connected: bool,
|
||||||
first_frame: bool,
|
first_frame: bool,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
client_conn_id: i32, // used for file clipboard
|
client_conn_id: i32, // used for file clipboard
|
||||||
@ -90,6 +93,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
remove_jobs: Default::default(),
|
remove_jobs: Default::default(),
|
||||||
timer: time::interval(SEC30),
|
timer: time::interval(SEC30),
|
||||||
last_update_jobs_status: (Instant::now(), Default::default()),
|
last_update_jobs_status: (Instant::now(), Default::default()),
|
||||||
|
is_connected: false,
|
||||||
first_frame: false,
|
first_frame: false,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
client_conn_id: 0,
|
client_conn_id: 0,
|
||||||
@ -195,28 +199,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
}
|
}
|
||||||
_msg = rx_clip_client.recv() => {
|
_msg = rx_clip_client.recv() => {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
match _msg {
|
self.handle_local_clipboard_msg(&mut peer, _msg).await;
|
||||||
Some(clip) => match clip {
|
|
||||||
clipboard::ClipboardFile::NotifyCallback{r#type, title, text} => {
|
|
||||||
self.handler.msgbox(&r#type, &title, &text, "");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let is_stopping_allowed = clip.is_stopping_allowed();
|
|
||||||
let server_file_transfer_enabled = *self.handler.server_file_transfer_enabled.read().unwrap();
|
|
||||||
let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v;
|
|
||||||
let stop = is_stopping_allowed && !(server_file_transfer_enabled && file_transfer_enabled);
|
|
||||||
log::debug!("Process clipboard message from system, stop: {}, is_stopping_allowed: {}, server_file_transfer_enabled: {}, file_transfer_enabled: {}", stop, is_stopping_allowed, server_file_transfer_enabled, file_transfer_enabled);
|
|
||||||
if stop {
|
|
||||||
ContextSend::set_is_stopped();
|
|
||||||
} else {
|
|
||||||
allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ = self.timer.tick() => {
|
_ = self.timer.tick() => {
|
||||||
if last_recv_time.elapsed() >= SEC30 {
|
if last_recv_time.elapsed() >= SEC30 {
|
||||||
@ -277,6 +260,44 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
async fn handle_local_clipboard_msg(
|
||||||
|
&self,
|
||||||
|
peer: &mut crate::client::FramedStream,
|
||||||
|
msg: Option<clipboard::ClipboardFile>,
|
||||||
|
) {
|
||||||
|
match msg {
|
||||||
|
Some(clip) => match clip {
|
||||||
|
clipboard::ClipboardFile::NotifyCallback {
|
||||||
|
r#type,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
} => {
|
||||||
|
self.handler.msgbox(&r#type, &title, &text, "");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let is_stopping_allowed = clip.is_stopping_allowed();
|
||||||
|
let server_file_transfer_enabled =
|
||||||
|
*self.handler.server_file_transfer_enabled.read().unwrap();
|
||||||
|
let file_transfer_enabled =
|
||||||
|
self.handler.lc.read().unwrap().enable_file_transfer.v;
|
||||||
|
let stop = is_stopping_allowed
|
||||||
|
&& (!self.is_connected
|
||||||
|
|| !(server_file_transfer_enabled && file_transfer_enabled));
|
||||||
|
log::debug!("Process clipboard message from system, stop: {}, is_stopping_allowed: {}, server_file_transfer_enabled: {}, file_transfer_enabled: {}", stop, is_stopping_allowed, server_file_transfer_enabled, file_transfer_enabled);
|
||||||
|
if stop {
|
||||||
|
ContextSend::set_is_stopped();
|
||||||
|
} else {
|
||||||
|
allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
// unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option<String>) {
|
fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option<String>) {
|
||||||
if let Some(job) = self.remove_jobs.get_mut(&id) {
|
if let Some(job) = self.remove_jobs.get_mut(&id) {
|
||||||
if job.no_confirm {
|
if job.no_confirm {
|
||||||
@ -1030,6 +1051,15 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
if self.handler.is_file_transfer() {
|
if self.handler.is_file_transfer() {
|
||||||
self.handler.load_last_jobs();
|
self.handler.load_last_jobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.is_connected = true;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
if self.handler.peer_platform() == crate::platform::PLATFORM_WINDOWS {
|
||||||
|
if let Some(last_file_format_list) = get_last_file_format_list() {
|
||||||
|
self.handle_local_clipboard_msg(peer, Some(last_file_format_list))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
@ -26,6 +26,11 @@ use hbb_common::{message_proto::CursorData, ResultType};
|
|||||||
#[cfg(not(any(target_os = "macos", target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "macos", target_os = "android", target_os = "ios")))]
|
||||||
const SERVICE_INTERVAL: u64 = 300;
|
const SERVICE_INTERVAL: u64 = 300;
|
||||||
|
|
||||||
|
pub const PLATFORM_WINDOWS: &str = "Windows";
|
||||||
|
pub const PLATFORM_LINUX: &str = "Linux";
|
||||||
|
pub const PLATFORM_MACOS: &str = "Mac OS";
|
||||||
|
pub const PLATFORM_ANDROID: &str = "Android";
|
||||||
|
|
||||||
pub fn is_xfce() -> bool {
|
pub fn is_xfce() -> bool {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
|
@ -68,7 +68,6 @@ struct IpcTaskRunner<T: InvokeUiCM> {
|
|||||||
rx: mpsc::UnboundedReceiver<Data>,
|
rx: mpsc::UnboundedReceiver<Data>,
|
||||||
close: bool,
|
close: bool,
|
||||||
running: bool,
|
running: bool,
|
||||||
authorized: bool,
|
|
||||||
conn_id: i32,
|
conn_id: i32,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
file_transfer_enabled: bool,
|
file_transfer_enabled: bool,
|
||||||
@ -162,6 +161,16 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
|
|||||||
self.ui_handler.add_connection(&client);
|
self.ui_handler.add_connection(&client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_authorized(&self, id: i32) -> bool {
|
||||||
|
CLIENTS
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get(&id)
|
||||||
|
.map(|c| c.authorized)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
fn remove_connection(&self, id: i32, close: bool) {
|
fn remove_connection(&self, id: i32, close: bool) {
|
||||||
if close {
|
if close {
|
||||||
CLIENTS.write().unwrap().remove(&id);
|
CLIENTS.write().unwrap().remove(&id);
|
||||||
@ -316,13 +325,14 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
|||||||
|
|
||||||
// for tmp use, without real conn id
|
// for tmp use, without real conn id
|
||||||
let mut write_jobs: Vec<fs::TransferJob> = Vec::new();
|
let mut write_jobs: Vec<fs::TransferJob> = Vec::new();
|
||||||
|
let is_authorized = self.cm.is_authorized(self.conn_id);
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let rx_clip1;
|
let rx_clip1;
|
||||||
let mut rx_clip;
|
let mut rx_clip;
|
||||||
let _tx_clip;
|
let _tx_clip;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if self.conn_id > 0 && self.authorized {
|
if is_authorized {
|
||||||
rx_clip1 = clipboard::get_rx_cliprdr_server(self.conn_id);
|
rx_clip1 = clipboard::get_rx_cliprdr_server(self.conn_id);
|
||||||
rx_clip = rx_clip1.lock().await;
|
rx_clip = rx_clip1.lock().await;
|
||||||
} else {
|
} else {
|
||||||
@ -361,7 +371,6 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
|||||||
Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled: _file_transfer_enabled, restart, recording, from_switch} => {
|
Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled: _file_transfer_enabled, restart, recording, from_switch} => {
|
||||||
log::debug!("conn_id: {}", id);
|
log::debug!("conn_id: {}", id);
|
||||||
self.cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, from_switch,self.tx.clone());
|
self.cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, from_switch,self.tx.clone());
|
||||||
self.authorized = authorized;
|
|
||||||
self.conn_id = id;
|
self.conn_id = id;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
@ -413,6 +422,10 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
|||||||
if stop {
|
if stop {
|
||||||
ContextSend::set_is_stopped();
|
ContextSend::set_is_stopped();
|
||||||
} else {
|
} else {
|
||||||
|
if !is_authorized {
|
||||||
|
log::debug!("Clipboard message from client peer, but not authorized");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let conn_id = self.conn_id;
|
let conn_id = self.conn_id;
|
||||||
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
|
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
|
||||||
clipboard::server_clip_file(context, conn_id, _clip)
|
clipboard::server_clip_file(context, conn_id, _clip)
|
||||||
@ -454,16 +467,24 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(data) = self.rx.recv() => {
|
Some(data) = self.rx.recv() => {
|
||||||
if let Data::SwitchPermission{name: _name, enabled: _enabled} = &data {
|
|
||||||
#[cfg(windows)]
|
|
||||||
if _name == "file" {
|
|
||||||
self.file_transfer_enabled = *_enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.stream.send(&data).await.is_err() {
|
if self.stream.send(&data).await.is_err() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
match &data {
|
||||||
|
Data::SwitchPermission{name: _name, enabled: _enabled} => {
|
||||||
|
#[cfg(windows)]
|
||||||
|
if _name == "file" {
|
||||||
|
self.file_transfer_enabled = *_enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Data::Authorize => {
|
||||||
|
self.running = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
clip_file = rx_clip.recv() => match clip_file {
|
clip_file = rx_clip.recv() => match clip_file {
|
||||||
Some(_clip) => {
|
Some(_clip) => {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -501,7 +522,6 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
|||||||
rx,
|
rx,
|
||||||
close: true,
|
close: true,
|
||||||
running: true,
|
running: true,
|
||||||
authorized: false,
|
|
||||||
conn_id: 0,
|
conn_id: 0,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
file_transfer_enabled: false,
|
file_transfer_enabled: false,
|
||||||
|
@ -412,7 +412,7 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
|
|
||||||
pub fn get_path_sep(&self, is_remote: bool) -> &'static str {
|
pub fn get_path_sep(&self, is_remote: bool) -> &'static str {
|
||||||
let p = self.get_platform(is_remote);
|
let p = self.get_platform(is_remote);
|
||||||
if &p == "Windows" {
|
if &p == crate::platform::PLATFORM_WINDOWS {
|
||||||
return "\\";
|
return "\\";
|
||||||
} else {
|
} else {
|
||||||
return "/";
|
return "/";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user