mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge pull request #5638 from ClSlaid/feat/x11/clipboard-file/init
[feat] x11 clipboard copy and paste file
This commit is contained in:
@@ -7,14 +7,14 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend};
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use clipboard::ContextSend;
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use hbb_common::sleep;
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
use hbb_common::tokio::sync::mpsc::error::TryRecvError;
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use hbb_common::tokio::sync::Mutex as TokioMutex;
|
||||
use hbb_common::{
|
||||
allow_err,
|
||||
@@ -34,7 +34,7 @@ use hbb_common::{
|
||||
sync::mpsc,
|
||||
time::{self, Duration, Instant, Interval},
|
||||
},
|
||||
Stream,
|
||||
ResultType, Stream,
|
||||
};
|
||||
use scrap::CodecFormat;
|
||||
|
||||
@@ -66,7 +66,7 @@ pub struct Remote<T: InvokeUiSession> {
|
||||
last_update_jobs_status: (Instant, HashMap<i32, u64>),
|
||||
is_connected: bool,
|
||||
first_frame: bool,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
client_conn_id: i32, // used for file clipboard
|
||||
data_count: Arc<AtomicUsize>,
|
||||
frame_count_map: Arc<RwLock<HashMap<usize, usize>>>,
|
||||
@@ -101,7 +101,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
last_update_jobs_status: (Instant::now(), Default::default()),
|
||||
is_connected: false,
|
||||
first_frame: false,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
client_conn_id: 0,
|
||||
data_count: Arc::new(AtomicUsize::new(0)),
|
||||
frame_count_map,
|
||||
@@ -146,24 +146,25 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
|
||||
// just build for now
|
||||
#[cfg(not(windows))]
|
||||
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
|
||||
let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::<i32>();
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let (_tx_holder, rx) = mpsc::unbounded_channel();
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let mut rx_clip_client_lock = Arc::new(TokioMutex::new(rx));
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
{
|
||||
let is_conn_not_default = self.handler.is_file_transfer()
|
||||
|| self.handler.is_port_forward()
|
||||
|| self.handler.is_rdp();
|
||||
if !is_conn_not_default {
|
||||
log::debug!("get cliprdr client for conn_id {}", self.client_conn_id);
|
||||
(self.client_conn_id, rx_clip_client_lock) =
|
||||
clipboard::get_rx_cliprdr_client(&self.handler.id);
|
||||
};
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let mut rx_clip_client = rx_clip_client_lock.lock().await;
|
||||
|
||||
let mut status_timer = time::interval(Duration::new(1, 0));
|
||||
@@ -209,8 +210,8 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
}
|
||||
_msg = rx_clip_client.recv() => {
|
||||
#[cfg(windows)]
|
||||
self.handle_local_clipboard_msg(&mut peer, _msg).await;
|
||||
#[cfg(any(target_os="windows", target_os="linux", target_os = "macos"))]
|
||||
self.handle_local_clipboard_msg(&mut peer, _msg).await;
|
||||
}
|
||||
_ = self.timer.tick() => {
|
||||
if last_recv_time.elapsed() >= SEC30 {
|
||||
@@ -277,17 +278,18 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
Client::try_stop_clipboard(&self.handler.id);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
if _set_disconnected_ok {
|
||||
let conn_id = self.client_conn_id;
|
||||
ContextSend::proc(|context: &mut CliprdrClientContext| -> u32 {
|
||||
empty_clipboard(context, conn_id);
|
||||
0
|
||||
log::debug!("try empty cliprdr for conn_id {}", conn_id);
|
||||
let _ = ContextSend::proc(|context| -> ResultType<()> {
|
||||
context.empty_clipboard(conn_id)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
async fn handle_local_clipboard_msg(
|
||||
&self,
|
||||
peer: &mut crate::client::FramedStream,
|
||||
@@ -315,7 +317,12 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
if stop {
|
||||
ContextSend::set_is_stopped();
|
||||
} else {
|
||||
allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await);
|
||||
if let Err(e) = ContextSend::make_sure_enabled() {
|
||||
log::error!("failed to restart clipboard context: {}", e);
|
||||
};
|
||||
log::debug!("Send system clipboard message to remote");
|
||||
let msg = crate::clipboard_file::clip_2_msg(clip);
|
||||
allow_err!(peer.send(&msg).await);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1069,7 +1076,6 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
Some(login_response::Union::PeerInfo(pi)) => {
|
||||
self.handler.handle_peer_info(pi);
|
||||
#[cfg(not(feature = "flutter"))]
|
||||
self.check_clipboard_file_context();
|
||||
if !(self.handler.is_file_transfer() || self.handler.is_port_forward()) {
|
||||
#[cfg(feature = "flutter")]
|
||||
@@ -1140,7 +1146,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
Some(message::Union::Cliprdr(clip)) => {
|
||||
self.handle_cliprdr_msg(clip);
|
||||
}
|
||||
@@ -1700,9 +1706,14 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "flutter"))]
|
||||
fn check_clipboard_file_context(&self) {
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
feature = "unix-file-copy-paste",
|
||||
any(target_os = "linux", target_os = "macos")
|
||||
)
|
||||
))]
|
||||
{
|
||||
let enabled = *self.handler.server_file_transfer_enabled.read().unwrap()
|
||||
&& self.handler.lc.read().unwrap().enable_file_transfer.v;
|
||||
@@ -1710,8 +1721,9 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
fn handle_cliprdr_msg(&self, clip: hbb_common::message_proto::Cliprdr) {
|
||||
log::debug!("handling cliprdr msg from server peer");
|
||||
#[cfg(feature = "flutter")]
|
||||
if let Some(hbb_common::message_proto::cliprdr::Union::FormatList(_)) = &clip.union {
|
||||
if self.client_conn_id
|
||||
@@ -1721,18 +1733,26 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) {
|
||||
let is_stopping_allowed = clip.is_stopping_allowed_from_peer();
|
||||
let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v;
|
||||
let stop = is_stopping_allowed && !file_transfer_enabled;
|
||||
log::debug!(
|
||||
let Some(clip) = crate::clipboard_file::msg_2_clip(clip) else {
|
||||
log::warn!("failed to decode cliprdr msg from server peer");
|
||||
return;
|
||||
};
|
||||
|
||||
let is_stopping_allowed = clip.is_stopping_allowed_from_peer();
|
||||
let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v;
|
||||
let stop = is_stopping_allowed && !file_transfer_enabled;
|
||||
log::debug!(
|
||||
"Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}",
|
||||
stop, is_stopping_allowed, file_transfer_enabled);
|
||||
if !stop {
|
||||
ContextSend::proc(|context: &mut CliprdrClientContext| -> u32 {
|
||||
clipboard::server_clip_file(context, self.client_conn_id, clip)
|
||||
});
|
||||
}
|
||||
if !stop {
|
||||
if let Err(e) = ContextSend::make_sure_enabled() {
|
||||
log::error!("failed to restart clipboard context: {}", e);
|
||||
};
|
||||
let _ = ContextSend::proc(|context| -> ResultType<()> {
|
||||
context
|
||||
.server_clip_file(self.client_conn_id, clip)
|
||||
.map_err(|e| e.into())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
111
src/common.rs
111
src/common.rs
@@ -11,9 +11,118 @@ pub enum GrabState {
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "android",
|
||||
target_os = "ios",
|
||||
all(target_os = "linux", feature = "unix-file-copy-paste")
|
||||
)))]
|
||||
pub use arboard::Clipboard as ClipboardContext;
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))]
|
||||
static X11_CLIPBOARD: once_cell::sync::OnceCell<x11_clipboard::Clipboard> =
|
||||
once_cell::sync::OnceCell::new();
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))]
|
||||
fn get_clipboard() -> Result<&'static x11_clipboard::Clipboard, String> {
|
||||
X11_CLIPBOARD
|
||||
.get_or_try_init(|| x11_clipboard::Clipboard::new())
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))]
|
||||
pub struct ClipboardContext {
|
||||
string_setter: x11rb::protocol::xproto::Atom,
|
||||
string_getter: x11rb::protocol::xproto::Atom,
|
||||
text_uri_list: x11rb::protocol::xproto::Atom,
|
||||
|
||||
clip: x11rb::protocol::xproto::Atom,
|
||||
prop: x11rb::protocol::xproto::Atom,
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))]
|
||||
fn parse_plain_uri_list(v: Vec<u8>) -> Result<String, String> {
|
||||
let text = String::from_utf8(v).map_err(|_| "ConversionFailure".to_owned())?;
|
||||
let mut list = String::new();
|
||||
for line in text.lines() {
|
||||
if !line.starts_with("file://") {
|
||||
continue;
|
||||
}
|
||||
let decoded = percent_encoding::percent_decode_str(line)
|
||||
.decode_utf8()
|
||||
.map_err(|_| "ConversionFailure".to_owned())?;
|
||||
list = list + "\n" + decoded.trim_start_matches("file://");
|
||||
}
|
||||
list = list.trim().to_owned();
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))]
|
||||
impl ClipboardContext {
|
||||
pub fn new() -> Result<Self, String> {
|
||||
let clipboard = get_clipboard()?;
|
||||
let string_getter = clipboard
|
||||
.getter
|
||||
.get_atom("UTF8_STRING")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let string_setter = clipboard
|
||||
.setter
|
||||
.get_atom("UTF8_STRING")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let text_uri_list = clipboard
|
||||
.getter
|
||||
.get_atom("text/uri-list")
|
||||
.map_err(|e| e.to_string())?;
|
||||
let prop = clipboard.getter.atoms.property;
|
||||
let clip = clipboard.getter.atoms.clipboard;
|
||||
Ok(Self {
|
||||
text_uri_list,
|
||||
string_setter,
|
||||
string_getter,
|
||||
clip,
|
||||
prop,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_text(&mut self) -> Result<String, String> {
|
||||
let clip = self.clip;
|
||||
let prop = self.prop;
|
||||
|
||||
const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(120);
|
||||
|
||||
let text_content = get_clipboard()?
|
||||
.load(clip, self.string_getter, prop, TIMEOUT)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let file_urls = get_clipboard()?.load(clip, self.text_uri_list, prop, TIMEOUT);
|
||||
|
||||
if file_urls.is_err() || file_urls.as_ref().unwrap().is_empty() {
|
||||
log::trace!("clipboard get text, no file urls");
|
||||
return String::from_utf8(text_content).map_err(|e| e.to_string());
|
||||
}
|
||||
|
||||
let file_urls = parse_plain_uri_list(file_urls.unwrap())?;
|
||||
|
||||
let text_content = String::from_utf8(text_content).map_err(|e| e.to_string())?;
|
||||
|
||||
if text_content.trim() == file_urls.trim() {
|
||||
log::trace!("clipboard got text but polluted");
|
||||
return Err(String::from("polluted text"));
|
||||
}
|
||||
|
||||
Ok(text_content)
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, content: String) -> Result<(), String> {
|
||||
let clip = self.clip;
|
||||
|
||||
let value = content.clone().into_bytes();
|
||||
get_clipboard()?
|
||||
.store(clip, self.string_setter, value)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use hbb_common::compress::decompress;
|
||||
use hbb_common::{
|
||||
|
||||
@@ -1725,6 +1725,17 @@ pub fn main_use_texture_render() -> SyncReturn<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main_has_file_clipboard() -> SyncReturn<bool> {
|
||||
let ret = cfg!(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
feature = "unix-file-copy-paste",
|
||||
any(target_os = "linux", target_os = "macos")
|
||||
)
|
||||
));
|
||||
SyncReturn(ret)
|
||||
}
|
||||
|
||||
pub fn cm_init() {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
crate::flutter::connection_manager::cm_init();
|
||||
|
||||
@@ -58,7 +58,7 @@ mod ui_session_interface;
|
||||
|
||||
mod hbbs_http;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub mod clipboard_file;
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{input_service::*, *};
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use crate::clipboard_file::*;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use crate::common::update_clipboard;
|
||||
@@ -192,7 +192,7 @@ pub struct Connection {
|
||||
// by peer
|
||||
disable_audio: bool,
|
||||
// by peer
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
enable_file_transfer: bool,
|
||||
// by peer
|
||||
audio_sender: Option<MediaSender>,
|
||||
@@ -330,7 +330,7 @@ impl Connection {
|
||||
show_remote_cursor: false,
|
||||
ip: "".to_owned(),
|
||||
disable_audio: false,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
enable_file_transfer: false,
|
||||
disable_clipboard: false,
|
||||
disable_keyboard: false,
|
||||
@@ -479,7 +479,7 @@ impl Connection {
|
||||
ipc::Data::RawMessage(bytes) => {
|
||||
allow_err!(conn.stream.send_raw(bytes).await);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os="windows", target_os="linux"))]
|
||||
ipc::Data::ClipboardFile(clip) => {
|
||||
allow_err!(conn.stream.send(&clip_2_msg(clip)).await);
|
||||
}
|
||||
@@ -1032,7 +1032,7 @@ impl Connection {
|
||||
pi.hostname = DEVICE_NAME.lock().unwrap().clone();
|
||||
pi.platform = "Android".into();
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
let mut platform_additions = serde_json::Map::new();
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
@@ -1062,7 +1062,18 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
any(target_os = "linux", target_os = "macos"),
|
||||
feature = "unix-file-copy-paste"
|
||||
)
|
||||
))]
|
||||
{
|
||||
platform_additions.insert("has_file_clipboard".into(), json!(true));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
if !platform_additions.is_empty() {
|
||||
pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into());
|
||||
}
|
||||
@@ -1236,7 +1247,7 @@ impl Connection {
|
||||
self.audio && !self.disable_audio
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
fn file_transfer_enabled(&self) -> bool {
|
||||
self.file && self.enable_file_transfer
|
||||
}
|
||||
@@ -1806,8 +1817,9 @@ impl Connection {
|
||||
}
|
||||
Some(message::Union::Cliprdr(_clip)) =>
|
||||
{
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
if let Some(clip) = msg_2_clip(_clip) {
|
||||
log::debug!("got clipfile from client peer");
|
||||
self.send_to_cm(ipc::Data::ClipboardFile(clip))
|
||||
}
|
||||
}
|
||||
@@ -2389,7 +2401,7 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
if let Ok(q) = o.enable_file_transfer.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.enable_file_transfer = q == BoolOption::Yes;
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
</header>
|
||||
<body #handler>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -196,7 +196,7 @@ class Header: Reactor.Component {
|
||||
{!cursor_embedded && <li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>}
|
||||
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
|
||||
{audio_enabled ? <li #disable-audio .toggle-option><span>{svg_checkmark}</span>{translate('Mute')}</li> : ""}
|
||||
{is_win && pi.platform == 'Windows' && file_enabled ? <li #enable-file-transfer .toggle-option><span>{svg_checkmark}</span>{translate('Allow file copy and paste')}</li> : ""}
|
||||
{(is_win && pi.platform == "Windows") && file_enabled ? <li #enable-file-transfer .toggle-option><span>{svg_checkmark}</span>{translate('Allow file copy and paste')}</li> : ""}
|
||||
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
|
||||
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
|
||||
{keyboard_enabled && pi.platform == "Windows" ? <li #privacy-mode><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
|
||||
use std::iter::FromIterator;
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@@ -15,11 +15,11 @@ use std::{
|
||||
use crate::ipc::Connection;
|
||||
#[cfg(not(any(target_os = "ios")))]
|
||||
use crate::ipc::{self, Data};
|
||||
#[cfg(windows)]
|
||||
use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend};
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use clipboard::ContextSend;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use hbb_common::tokio::sync::mpsc::unbounded_channel;
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use hbb_common::tokio::sync::Mutex as TokioMutex;
|
||||
use hbb_common::{
|
||||
allow_err,
|
||||
@@ -34,6 +34,7 @@ use hbb_common::{
|
||||
sync::mpsc::{self, UnboundedSender},
|
||||
task::spawn_blocking,
|
||||
},
|
||||
ResultType,
|
||||
};
|
||||
use serde_derive::Serialize;
|
||||
|
||||
@@ -69,9 +70,9 @@ struct IpcTaskRunner<T: InvokeUiCM> {
|
||||
close: bool,
|
||||
running: bool,
|
||||
conn_id: i32,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
file_transfer_enabled: bool,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
file_transfer_enabled_peer: bool,
|
||||
}
|
||||
|
||||
@@ -164,7 +165,7 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
fn is_authorized(&self, id: i32) -> bool {
|
||||
CLIENTS
|
||||
.read()
|
||||
@@ -185,11 +186,11 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
|
||||
.map(|c| c.disconnected = true);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
{
|
||||
ContextSend::proc(|context: &mut CliprdrClientContext| -> u32 {
|
||||
empty_clipboard(context, id);
|
||||
0
|
||||
let _ = ContextSend::proc(|context| -> ResultType<()> {
|
||||
context.empty_clipboard(id)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
@@ -328,31 +329,35 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
|
||||
// for tmp use, without real conn id
|
||||
let mut write_jobs: Vec<fs::TransferJob> = Vec::new();
|
||||
#[cfg(windows)]
|
||||
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let is_authorized = self.cm.is_authorized(self.conn_id);
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let rx_clip1;
|
||||
let mut rx_clip;
|
||||
let _tx_clip;
|
||||
#[cfg(windows)]
|
||||
if is_authorized {
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
if self.conn_id > 0 && is_authorized {
|
||||
log::debug!("Clipboard is enabled from client peer: type 1");
|
||||
rx_clip1 = clipboard::get_rx_cliprdr_server(self.conn_id);
|
||||
rx_clip = rx_clip1.lock().await;
|
||||
} else {
|
||||
log::debug!("Clipboard is enabled from client peer, actually useless: type 2");
|
||||
let rx_clip2;
|
||||
(_tx_clip, rx_clip2) = unbounded_channel::<clipboard::ClipboardFile>();
|
||||
rx_clip1 = Arc::new(TokioMutex::new(rx_clip2));
|
||||
rx_clip = rx_clip1.lock().await;
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
|
||||
{
|
||||
(_tx_clip, rx_clip) = unbounded_channel::<i32>();
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
{
|
||||
if ContextSend::is_enabled() {
|
||||
log::debug!("Clipboard is enabled");
|
||||
allow_err!(
|
||||
self.stream
|
||||
.send(&Data::ClipboardFile(clipboard::ClipboardFile::MonitorReady))
|
||||
@@ -377,7 +382,7 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
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.conn_id = id;
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
{
|
||||
self.file_transfer_enabled = _file_transfer_enabled;
|
||||
}
|
||||
@@ -420,7 +425,7 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
}
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
Data::ClipboardFile(_clip) => {
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os="linux", target_os = "macos"))]
|
||||
{
|
||||
let is_stopping_allowed = _clip.is_stopping_allowed_from_peer();
|
||||
let is_clipboard_enabled = ContextSend::is_enabled();
|
||||
@@ -437,14 +442,15 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
continue;
|
||||
}
|
||||
let conn_id = self.conn_id;
|
||||
ContextSend::proc(|context: &mut CliprdrClientContext| -> u32 {
|
||||
clipboard::server_clip_file(context, conn_id, _clip)
|
||||
let _ = ContextSend::proc(|context| -> ResultType<()> {
|
||||
context.server_clip_file(conn_id, _clip)
|
||||
.map_err(|e| e.into())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::ClipboardFileEnabled(_enabled) => {
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os= "windows",target_os ="linux"))]
|
||||
{
|
||||
self.file_transfer_enabled_peer = _enabled;
|
||||
}
|
||||
@@ -477,12 +483,13 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
}
|
||||
}
|
||||
Some(data) = self.rx.recv() => {
|
||||
if self.stream.send(&data).await.is_err() {
|
||||
if let Err(e) = self.stream.send(&data).await {
|
||||
log::error!("error encountered in IPC task, quitting: {}", e);
|
||||
break;
|
||||
}
|
||||
match &data {
|
||||
Data::SwitchPermission{name: _name, enabled: _enabled} => {
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os="linux", target_os="windows"))]
|
||||
if _name == "file" {
|
||||
self.file_transfer_enabled = *_enabled;
|
||||
}
|
||||
@@ -497,7 +504,7 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
},
|
||||
clip_file = rx_clip.recv() => match clip_file {
|
||||
Some(_clip) => {
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os ="linux", target_os = "macos"))]
|
||||
{
|
||||
let is_stopping_allowed = _clip.is_stopping_allowed();
|
||||
let is_clipboard_enabled = ContextSend::is_enabled();
|
||||
@@ -536,9 +543,9 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
||||
close: true,
|
||||
running: true,
|
||||
conn_id: 0,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
file_transfer_enabled: false,
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
file_transfer_enabled_peer: false,
|
||||
};
|
||||
|
||||
@@ -568,7 +575,13 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
any(target_os = "linux", target_os = "macos"),
|
||||
feature = "unix-file-copy-paste"
|
||||
),
|
||||
))]
|
||||
ContextSend::enable(Config::get_option("enable-file-transfer").is_empty());
|
||||
|
||||
match ipc::new_listener("_cm").await {
|
||||
|
||||
@@ -1007,7 +1007,8 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc:
|
||||
let mut mouse_time = 0;
|
||||
#[cfg(not(feature = "flutter"))]
|
||||
let mut id = "".to_owned();
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
#[allow(unused_mut, dead_code)]
|
||||
let mut enable_file_transfer = "".to_owned();
|
||||
|
||||
loop {
|
||||
@@ -1030,7 +1031,13 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc:
|
||||
*OPTIONS.lock().unwrap() = v;
|
||||
*OPTION_SYNCED.lock().unwrap() = true;
|
||||
|
||||
#[cfg(target_os="windows")]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
any(target_os="linux", target_os = "macos"),
|
||||
feature = "unix-file-copy-paste"
|
||||
)
|
||||
))]
|
||||
{
|
||||
let b = OPTIONS.lock().unwrap().get("enable-file-transfer").map(|x| x.to_string()).unwrap_or_default();
|
||||
if b != enable_file_transfer {
|
||||
|
||||
@@ -1420,7 +1420,13 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>, round: u32) {
|
||||
// It is ok to call this function multiple times.
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(
|
||||
any(target_os = "linux", target_os = "macos"),
|
||||
feature = "unix-file-copy-paste"
|
||||
)
|
||||
))]
|
||||
if !handler.is_file_transfer() && !handler.is_port_forward() {
|
||||
clipboard::ContextSend::enable(true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user