From 8834251eec3fa2ef1009a26df1ff62ecfbb0e08d Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 22 Feb 2022 14:17:50 +0800 Subject: [PATCH] move clipboard file service to cm module Signed-off-by: fufesou --- Cargo.lock | 2 + libs/clipboard/Cargo.toml | 2 + libs/clipboard/src/lib.rs | 600 ++++++++++++++---------- libs/clipboard/src/windows/wf_cliprdr.c | 26 +- src/clipboard_file.rs | 207 ++++++++ src/ipc.rs | 2 + src/lib.rs | 3 + src/server.rs | 4 - src/server/clipboard_file_service.rs | 104 ---- src/server/connection.rs | 36 +- src/ui/cm.rs | 81 +++- src/ui/remote.rs | 44 +- 12 files changed, 720 insertions(+), 391 deletions(-) create mode 100644 src/clipboard_file.rs delete mode 100644 src/server/clipboard_file_service.rs diff --git a/Cargo.lock b/Cargo.lock index 32e50572e..72bc94475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,6 +395,8 @@ dependencies = [ "cc", "hbb_common", "lazy_static", + "serde 1.0.135", + "serde_derive", "thiserror", ] diff --git a/libs/clipboard/Cargo.toml b/libs/clipboard/Cargo.toml index 3d2b5ef77..3a27833cc 100644 --- a/libs/clipboard/Cargo.toml +++ b/libs/clipboard/Cargo.toml @@ -12,4 +12,6 @@ cc = "1.0" [dependencies] thiserror = "1.0.30" lazy_static = "1.4" +serde = "1.0" +serde_derive = "1.0" hbb_common = { path = "../hbb_common" } diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index bf5a0f140..37db74549 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -1,14 +1,13 @@ use cliprdr::*; use hbb_common::{ log, - message_proto::cliprdr as msg_cliprdr, - message_proto::*, tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, }, ResultType, }; +use serde_derive::{Deserialize, Serialize}; use std::{ boxed::Box, ffi::{CStr, CString}, @@ -22,111 +21,241 @@ pub struct ConnID { pub remote_conn_id: u32, } +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "t", content = "c")] +pub enum ClipbaordFile { + ServerFormatList { + server_conn_id: i32, + remote_conn_id: i32, + format_list: Vec<(i32, String)>, + }, + ServerFormatListResponse { + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + }, + ServerFormatDataRequest { + server_conn_id: i32, + remote_conn_id: i32, + requested_format_id: i32, + }, + ServerFormatDataResponse { + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + format_data: Vec, + }, + FileContentsRequest { + server_conn_id: i32, + remote_conn_id: i32, + stream_id: i32, + list_index: i32, + dw_flags: i32, + n_position_low: i32, + n_position_high: i32, + cb_requested: i32, + have_clip_data_id: bool, + clip_data_id: i32, + }, + FileContentsResponse { + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + stream_id: i32, + requested_data: Vec, + }, +} + lazy_static::lazy_static! { - static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, Message)>, TokioMutex>) = { + static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, ClipbaordFile)>, TokioMutex>) = { let (tx, rx) = unbounded_channel(); (tx, TokioMutex::new(rx)) }; } #[inline(always)] -pub fn get_rx_client_msg<'a>() -> &'a TokioMutex> { +pub fn get_rx_clip_client<'a>() -> &'a TokioMutex> { &MSG_CHANNEL_CLIENT.1 } -pub fn server_msg(context: &mut Box, conn_id: ConnID, msg: Cliprdr) -> u32 { - match msg.union { - Some(msg_cliprdr::Union::ready(_)) => { - // proc ready - 0 - } - Some(msg_cliprdr::Union::format_list(req)) => { +pub fn server_clip_file( + context: &mut Box, + conn_id: ConnID, + msg: ClipbaordFile, +) -> u32 { + match msg { + ClipbaordFile::ServerFormatList { + mut server_conn_id, + mut remote_conn_id, + format_list, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("server_format_list called"); - let ret = server_format_list(context, conn_id, req); + let ret = server_format_list(context, server_conn_id, remote_conn_id, format_list); log::debug!("server_format_list called, return {}", ret); ret } - Some(msg_cliprdr::Union::format_list_response(req)) => { + ClipbaordFile::ServerFormatListResponse { + mut server_conn_id, + mut remote_conn_id, + msg_flags, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("format_list_response called"); - let ret = server_format_list_response(context, conn_id, req); + let ret = + server_format_list_response(context, server_conn_id, remote_conn_id, msg_flags); log::debug!("server_format_list_response called, return {}", ret); ret } - Some(msg_cliprdr::Union::format_data_request(req)) => { + ClipbaordFile::ServerFormatDataRequest { + mut server_conn_id, + mut remote_conn_id, + requested_format_id, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("format_data_request called"); - let ret = server_format_data_request(context, conn_id, req); + let ret = server_format_data_request( + context, + server_conn_id, + remote_conn_id, + requested_format_id, + ); log::debug!("server_format_data_request called, return {}", ret); ret } - Some(msg_cliprdr::Union::format_data_response(req)) => { + ClipbaordFile::ServerFormatDataResponse { + mut server_conn_id, + mut remote_conn_id, + msg_flags, + format_data, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("format_data_response called"); - let ret = server_format_data_response(context, conn_id, req); + let ret = server_format_data_response( + context, + server_conn_id, + remote_conn_id, + msg_flags, + format_data, + ); log::debug!("server_format_data_response called, return {}", ret); ret } - Some(msg_cliprdr::Union::file_contents_request(req)) => { + ClipbaordFile::FileContentsRequest { + mut server_conn_id, + mut remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("file_contents_request called"); - let ret = server_file_contents_request(context, conn_id, req); + let ret = server_file_contents_request( + context, + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ); log::debug!("server_file_contents_request called, return {}", ret); ret } - Some(msg_cliprdr::Union::file_contents_response(req)) => { + ClipbaordFile::FileContentsResponse { + mut server_conn_id, + mut remote_conn_id, + msg_flags, + stream_id, + requested_data, + } => { + if conn_id.server_conn_id != 0 { + server_conn_id = conn_id.server_conn_id as i32; + } + if conn_id.remote_conn_id != 0 { + remote_conn_id = conn_id.remote_conn_id as i32; + } log::debug!("file_contents_response called"); - let ret = server_file_contents_response(context, conn_id, req); + let ret = server_file_contents_response( + context, + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + ); log::debug!("server_file_contents_response called, return {}", ret); ret } - None => { - // unreachable!() - 0 - } } } -fn server_format_list( +pub fn server_format_list( context: &mut Box, - conn_id: ConnID, - data: CliprdrServerFormatList, + server_conn_id: i32, + remote_conn_id: i32, + format_list: Vec<(i32, String)>, ) -> u32 { - // do not check msgFlags for now unsafe { - let num_formats = data.formats.len() as UINT32; - let mut formats = data - .formats + let num_formats = format_list.len() as UINT32; + let mut formats = format_list .into_iter() .map(|format| { - if format.format.is_empty() { + if format.1.is_empty() { CLIPRDR_FORMAT { - formatId: format.id as UINT32, + formatId: format.0 as UINT32, formatName: 0 as *mut _, } } else { - let n = match CString::new(format.format) { + let n = match CString::new(format.1) { Ok(n) => n, Err(_) => CString::new("").unwrap(), }; CLIPRDR_FORMAT { - formatId: format.id as UINT32, + formatId: format.0 as UINT32, formatName: n.into_raw(), } } }) .collect::>(); - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; - let format_list = CLIPRDR_FORMAT_LIST { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, msgFlags: 0 as UINT16, dataLen: 0 as UINT32, @@ -146,28 +275,18 @@ fn server_format_list( ret as u32 } } -fn server_format_list_response( +pub fn server_format_list_response( context: &mut Box, - conn_id: ConnID, - data: CliprdrServerFormatListResponse, + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; - let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: data.msg_flags as UINT16, + msgFlags: msg_flags as UINT16, dataLen: 0 as UINT32, }; @@ -177,59 +296,41 @@ fn server_format_list_response( ret as u32 } } -fn server_format_data_request( +pub fn server_format_data_request( context: &mut Box, - conn_id: ConnID, - data: CliprdrServerFormatDataRequest, + server_conn_id: i32, + remote_conn_id: i32, + requested_format_id: i32, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; - let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, msgFlags: 0 as UINT16, dataLen: 0 as UINT32, - requestedFormatId: data.requested_format_id as UINT32, + requestedFormatId: requested_format_id as UINT32, }; let ret = ((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request); ret as u32 } } -fn server_format_data_response( +pub fn server_format_data_response( context: &mut Box, - conn_id: ConnID, - mut data: CliprdrServerFormatDataResponse, + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + mut format_data: Vec, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: data.msg_flags as UINT16, - dataLen: data.format_data.len() as UINT32, - requestedFormatData: data.format_data.as_mut_ptr(), + msgFlags: msg_flags as UINT16, + dataLen: format_data.len() as UINT32, + requestedFormatData: format_data.as_mut_ptr(), }; let ret = ((**context).ServerFormatDataResponse.unwrap())( &mut (**context), @@ -238,36 +339,34 @@ fn server_format_data_response( ret as u32 } } -fn server_file_contents_request( +pub fn server_file_contents_request( context: &mut Box, - conn_id: ConnID, - data: CliprdrFileContentsRequest, + server_conn_id: i32, + remote_conn_id: i32, + stream_id: i32, + list_index: i32, + dw_flags: i32, + n_position_low: i32, + n_position_high: i32, + cb_requested: i32, + have_clip_data_id: bool, + clip_data_id: i32, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, msgFlags: 0 as UINT16, dataLen: 0 as UINT32, - streamId: data.stream_id as UINT32, - listIndex: data.list_index as UINT32, - dwFlags: data.dw_flags as UINT32, - nPositionLow: data.n_position_low as UINT32, - nPositionHigh: data.n_position_high as UINT32, - cbRequested: data.cb_requested as UINT32, - haveClipDataId: if data.have_clip_data_id { TRUE } else { FALSE }, - clipDataId: data.clip_data_id as UINT32, + streamId: stream_id as UINT32, + listIndex: list_index as UINT32, + dwFlags: dw_flags as UINT32, + nPositionLow: n_position_low as UINT32, + nPositionHigh: n_position_high as UINT32, + cbRequested: cb_requested as UINT32, + haveClipDataId: if have_clip_data_id { TRUE } else { FALSE }, + clipDataId: clip_data_id as UINT32, }; let ret = ((**context).ServerFileContentsRequest.unwrap())( &mut (**context), @@ -276,31 +375,24 @@ fn server_file_contents_request( ret as u32 } } -fn server_file_contents_response( +pub fn server_file_contents_response( context: &mut Box, - conn_id: ConnID, - mut data: CliprdrFileContentsResponse, + server_conn_id: i32, + remote_conn_id: i32, + msg_flags: i32, + stream_id: i32, + mut requested_data: Vec, ) -> u32 { unsafe { - let server_conn_id = if conn_id.server_conn_id != 0 { - conn_id.server_conn_id as UINT32 - } else { - data.server_conn_id as UINT32 - }; - let remote_conn_id = if conn_id.remote_conn_id != 0 { - conn_id.remote_conn_id as UINT32 - } else { - data.remote_conn_id as UINT32 - }; let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE { - serverConnID: server_conn_id, - remoteConnID: remote_conn_id, + serverConnID: server_conn_id as UINT32, + remoteConnID: remote_conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: data.msg_flags as UINT16, - dataLen: 4 + data.requested_data.len() as UINT32, - streamId: data.stream_id as UINT32, - cbRequested: data.requested_data.len() as UINT32, - requestedData: data.requested_data.as_mut_ptr(), + msgFlags: msg_flags as UINT16, + dataLen: 4 + requested_data.len() as UINT32, + streamId: stream_id as UINT32, + cbRequested: requested_data.len() as UINT32, + requestedData: requested_data.as_mut_ptr(), }; let ret = ((**context).ServerFileContentsResponse.unwrap())( &mut (**context), @@ -310,7 +402,10 @@ fn server_file_contents_response( } } -pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> ResultType> { +pub fn create_cliprdr_context( + enable_files: bool, + enable_others: bool, +) -> ResultType> { Ok(CliprdrClientContext::create( enable_files, enable_others, @@ -325,21 +420,19 @@ pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> Result extern "C" fn client_format_list( _context: *mut CliprdrClientContext, - format_list: *const CLIPRDR_FORMAT_LIST, + clip_format_list: *const CLIPRDR_FORMAT_LIST, ) -> UINT { log::debug!("client_format_list called"); - let mut data = CliprdrServerFormatList::default(); + let server_conn_id; + let remote_conn_id; + let mut format_list: Vec<(i32, String)> = Vec::new(); unsafe { let mut i = 0u32; - while i < (*format_list).numFormats { - let format_data = &(*(*format_list).formats.offset(i as isize)); + while i < (*clip_format_list).numFormats { + let format_data = &(*(*clip_format_list).formats.offset(i as isize)); if format_data.formatName.is_null() { - data.formats.push(CliprdrFormat { - id: format_data.formatId as i32, - format: "".to_owned(), - ..Default::default() - }); + format_list.push((format_data.formatId as i32, "".to_owned())); } else { let format_name = CStr::from_ptr(format_data.formatName).to_str(); let format_name = match format_name { @@ -349,30 +442,25 @@ extern "C" fn client_format_list( "".to_owned() } }; - data.formats.push(CliprdrFormat { - id: format_data.formatId as i32, - format: format_name, - ..Default::default() - }); + format_list.push((format_data.formatId as i32, format_name)); } + // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name); i += 1; } - - data.server_conn_id = (*format_list).serverConnID as i32; - data.remote_conn_id = (*format_list).remoteConnID as i32; + server_conn_id = (*clip_format_list).serverConnID as i32; + remote_conn_id = (*clip_format_list).remoteConnID as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatList { + server_conn_id, + remote_conn_id, + format_list, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_list(data); - msg.set_cliprdr(cliprdr); - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -383,23 +471,25 @@ extern "C" fn client_format_list_response( ) -> UINT { log::debug!("client_format_list_response called"); - let mut data = CliprdrServerFormatListResponse::default(); + let server_conn_id; + let remote_conn_id; + let msg_flags; unsafe { - data.server_conn_id = (*format_list_response).serverConnID as i32; - data.remote_conn_id = (*format_list_response).remoteConnID as i32; - data.msg_flags = (*format_list_response).msgFlags as i32; + server_conn_id = (*format_list_response).serverConnID as i32; + remote_conn_id = (*format_list_response).remoteConnID as i32; + msg_flags = (*format_list_response).msgFlags as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatListResponse { + server_conn_id, + remote_conn_id, + msg_flags, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_list_response(data); - msg.set_cliprdr(cliprdr); // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -410,23 +500,25 @@ extern "C" fn client_format_data_request( ) -> UINT { log::debug!("client_format_data_request called"); - let mut data = CliprdrServerFormatDataRequest::default(); + let server_conn_id; + let remote_conn_id; + let requested_format_id; unsafe { - data.server_conn_id = (*format_data_request).serverConnID as i32; - data.remote_conn_id = (*format_data_request).remoteConnID as i32; - data.requested_format_id = (*format_data_request).requestedFormatId as i32; + server_conn_id = (*format_data_request).serverConnID as i32; + remote_conn_id = (*format_data_request).remoteConnID as i32; + requested_format_id = (*format_data_request).requestedFormatId as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatDataRequest { + server_conn_id, + remote_conn_id, + requested_format_id, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_data_request(data); - msg.set_cliprdr(cliprdr); // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -437,28 +529,32 @@ extern "C" fn client_format_data_response( ) -> UINT { log::debug!("client_format_data_response called"); - let mut data = CliprdrServerFormatDataResponse::default(); + let server_conn_id; + let remote_conn_id; + let msg_flags; + let format_data; unsafe { - data.server_conn_id = (*format_data_response).serverConnID as i32; - data.remote_conn_id = (*format_data_response).remoteConnID as i32; - data.msg_flags = (*format_data_response).msgFlags as i32; - data.format_data = std::slice::from_raw_parts( + server_conn_id = (*format_data_response).serverConnID as i32; + remote_conn_id = (*format_data_response).remoteConnID as i32; + msg_flags = (*format_data_response).msgFlags as i32; + format_data = std::slice::from_raw_parts( (*format_data_response).requestedFormatData, (*format_data_response).dataLen as usize, ) .to_vec(); } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, + }; + let data = ClipbaordFile::ServerFormatDataResponse { + server_conn_id, + remote_conn_id, + msg_flags, + format_data, }; - - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_format_data_response(data); - msg.set_cliprdr(cliprdr); // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -479,30 +575,47 @@ extern "C" fn client_file_contents_request( // return ERROR_INVALID_PARAMETER; // } - let mut data = CliprdrFileContentsRequest::default(); + let server_conn_id; + let remote_conn_id; + let stream_id; + let list_index; + let dw_flags; + let n_position_low; + let n_position_high; + let cb_requested; + let have_clip_data_id; + let clip_data_id; unsafe { - data.server_conn_id = (*file_contents_request).serverConnID as i32; - data.remote_conn_id = (*file_contents_request).remoteConnID as i32; - data.stream_id = (*file_contents_request).streamId as i32; - data.list_index = (*file_contents_request).listIndex as i32; - data.dw_flags = (*file_contents_request).dwFlags as i32; - data.n_position_low = (*file_contents_request).nPositionLow as i32; - data.n_position_high = (*file_contents_request).nPositionHigh as i32; - data.cb_requested = (*file_contents_request).cbRequested as i32; - data.have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; - data.clip_data_id = (*file_contents_request).clipDataId as i32; + server_conn_id = (*file_contents_request).serverConnID as i32; + remote_conn_id = (*file_contents_request).remoteConnID as i32; + stream_id = (*file_contents_request).streamId as i32; + list_index = (*file_contents_request).listIndex as i32; + dw_flags = (*file_contents_request).dwFlags as i32; + n_position_low = (*file_contents_request).nPositionLow as i32; + n_position_high = (*file_contents_request).nPositionHigh as i32; + cb_requested = (*file_contents_request).cbRequested as i32; + have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; + clip_data_id = (*file_contents_request).clipDataId as i32; } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, }; - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_file_contents_request(data); - msg.set_cliprdr(cliprdr); + let data = ClipbaordFile::FileContentsRequest { + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } @@ -513,29 +626,36 @@ extern "C" fn client_file_contents_response( ) -> UINT { log::debug!("client_file_contents_response called"); - let mut data = CliprdrFileContentsResponse::default(); + let server_conn_id; + let remote_conn_id; + let msg_flags; + let stream_id; + let requested_data; unsafe { - data.server_conn_id = (*file_contents_response).serverConnID as i32; - data.remote_conn_id = (*file_contents_response).remoteConnID as i32; - data.msg_flags = (*file_contents_response).msgFlags as i32; - data.stream_id = (*file_contents_response).streamId as i32; - data.requested_data = std::slice::from_raw_parts( + server_conn_id = (*file_contents_response).serverConnID as i32; + remote_conn_id = (*file_contents_response).remoteConnID as i32; + msg_flags = (*file_contents_response).msgFlags as i32; + stream_id = (*file_contents_response).streamId as i32; + requested_data = std::slice::from_raw_parts( (*file_contents_response).requestedData, (*file_contents_response).cbRequested as usize, ) .to_vec(); } let conn_id = ConnID { - server_conn_id: data.server_conn_id as u32, - remote_conn_id: data.remote_conn_id as u32, + server_conn_id: server_conn_id as u32, + remote_conn_id: remote_conn_id as u32, }; - let mut msg = Message::new(); - let mut cliprdr = Cliprdr::new(); - cliprdr.set_file_contents_response(data); - msg.set_cliprdr(cliprdr); + let data = ClipbaordFile::FileContentsResponse { + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap(); + MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 0 } diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 99fccfb18..26294df8a 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -1355,7 +1355,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) /* Ignore if other app is holding clipboard */ if (try_open_clipboard(clipboard->hwnd)) { + // If current process is running as service with SYSTEM user. + // Clipboard api works fine for text, but copying files works no good. + // GetLastError() returns various error codes count = CountClipboardFormats(); + if (count == 0) + { + CloseClipboard(); + return CHANNEL_RC_NULL_DATA; + } + numFormats = (UINT32)count; formats = (CLIPRDR_FORMAT *)calloc(numFormats, sizeof(CLIPRDR_FORMAT)); @@ -1377,7 +1386,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) } else { - while (formatId = EnumClipboardFormats(formatId)) + while (formatId = EnumClipboardFormats(formatId) && index < numFormats) formats[index++].formatId = formatId; } @@ -1395,6 +1404,10 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) { formats[index].formatName = _strdup(formatName); } + else + { + formats[index].formatName = NULL; + } } } @@ -1408,11 +1421,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) rc = clipboard->context->ClientFormatList(clipboard->context, &formatList); for (index = 0; index < numFormats; index++) - free(formats[index].formatName); - + { + if (formats[index].formatName != NULL) + { + free(formats[index].formatName); + formats[index].formatName = NULL; + } + } free(formats); + return rc; - // return 0; } static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *clipboard, UINT32 formatId) diff --git a/src/clipboard_file.rs b/src/clipboard_file.rs new file mode 100644 index 000000000..093dcd90a --- /dev/null +++ b/src/clipboard_file.rs @@ -0,0 +1,207 @@ +use clipboard::ClipbaordFile; +use hbb_common::message_proto::*; + +pub fn clip_2_msg(clip: ClipbaordFile) -> Message { + match clip { + ClipbaordFile::ServerFormatList { + server_conn_id, + remote_conn_id, + format_list, + } => { + let mut formats: Vec = Vec::new(); + for v in format_list.iter() { + formats.push(CliprdrFormat { + server_conn_id: 0, + remote_conn_id: 0, + id: v.0, + format: v.1.clone(), + ..Default::default() + }); + } + Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_list(CliprdrServerFormatList { + server_conn_id, + remote_conn_id, + formats, + ..Default::default() + })), + ..Default::default() + })), + ..Default::default() + } + } + ClipbaordFile::ServerFormatListResponse { + server_conn_id, + remote_conn_id, + msg_flags, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_list_response( + CliprdrServerFormatListResponse { + server_conn_id, + remote_conn_id, + msg_flags, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::ServerFormatDataRequest { + server_conn_id, + remote_conn_id, + requested_format_id, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_data_request( + CliprdrServerFormatDataRequest { + server_conn_id, + remote_conn_id, + requested_format_id, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::ServerFormatDataResponse { + server_conn_id, + remote_conn_id, + msg_flags, + format_data, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::format_data_response( + CliprdrServerFormatDataResponse { + server_conn_id, + remote_conn_id, + msg_flags, + format_data, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::FileContentsRequest { + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::file_contents_request( + CliprdrFileContentsRequest { + server_conn_id, + remote_conn_id, + stream_id, + list_index, + dw_flags, + n_position_low, + n_position_high, + cb_requested, + have_clip_data_id, + clip_data_id, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + ClipbaordFile::FileContentsResponse { + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + } => Message { + union: Some(message::Union::cliprdr(Cliprdr { + union: Some(cliprdr::Union::file_contents_response( + CliprdrFileContentsResponse { + server_conn_id, + remote_conn_id, + msg_flags, + stream_id, + requested_data, + ..Default::default() + }, + )), + ..Default::default() + })), + ..Default::default() + }, + } +} + +pub fn msg_2_clip(msg: Cliprdr) -> Option { + match msg.union { + Some(cliprdr::Union::format_list(data)) => { + let mut format_list: Vec<(i32, String)> = Vec::new(); + for v in data.formats.iter() { + format_list.push((v.id, v.format.clone())); + } + Some(ClipbaordFile::ServerFormatList { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + format_list, + }) + } + Some(cliprdr::Union::format_list_response(data)) => { + Some(ClipbaordFile::ServerFormatListResponse { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + msg_flags: data.msg_flags, + }) + } + Some(cliprdr::Union::format_data_request(data)) => { + Some(ClipbaordFile::ServerFormatDataRequest { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + requested_format_id: data.requested_format_id, + }) + } + Some(cliprdr::Union::format_data_response(data)) => { + Some(ClipbaordFile::ServerFormatDataResponse { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + msg_flags: data.msg_flags, + format_data: data.format_data, + }) + } + Some(cliprdr::Union::file_contents_request(data)) => { + Some(ClipbaordFile::FileContentsRequest { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + stream_id: data.stream_id, + list_index: data.list_index, + dw_flags: data.dw_flags, + n_position_low: data.n_position_low, + n_position_high: data.n_position_high, + cb_requested: data.cb_requested, + have_clip_data_id: data.have_clip_data_id, + clip_data_id: data.clip_data_id, + }) + } + Some(cliprdr::Union::file_contents_response(data)) => { + Some(ClipbaordFile::FileContentsResponse { + server_conn_id: data.server_conn_id, + remote_conn_id: data.remote_conn_id, + msg_flags: data.msg_flags, + stream_id: data.stream_id, + requested_data: data.requested_data, + }) + } + _ => None, + } +} diff --git a/src/ipc.rs b/src/ipc.rs index 30c643ec5..fa48280bf 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,4 +1,5 @@ use crate::rendezvous_mediator::RendezvousMediator; +pub use clipboard::ClipbaordFile; use hbb_common::{ allow_err, bail, bytes, bytes_codec::BytesCodec, @@ -103,6 +104,7 @@ pub enum Data { to: String, }, SyncConfigToUserResp(bool), + ClipbaordFile(ClipbaordFile), } #[tokio::main(flavor = "current_thread")] diff --git a/src/lib.rs b/src/lib.rs index 2df657ab0..0f788cb67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,3 +28,6 @@ pub mod cli; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; mod lang; + +#[cfg(windows)] +pub mod clipboard_file; diff --git a/src/server.rs b/src/server.rs index a1d0454ae..ef0070d77 100644 --- a/src/server.rs +++ b/src/server.rs @@ -29,8 +29,6 @@ use std::{ pub mod audio_service; mod clipboard_service; -#[cfg(windows)] -pub mod clipboard_file_service; mod connection; pub mod input_service; mod service; @@ -63,8 +61,6 @@ pub fn new() -> ServerPtr { server.add_service(Box::new(audio_service::new())); server.add_service(Box::new(video_service::new())); server.add_service(Box::new(clipboard_service::new())); - #[cfg(windows)] - server.add_service(Box::new(clipboard_file_service::new())); server.add_service(Box::new(input_service::new_cursor())); server.add_service(Box::new(input_service::new_pos())); Arc::new(RwLock::new(server)) diff --git a/src/server/clipboard_file_service.rs b/src/server/clipboard_file_service.rs deleted file mode 100644 index 718f44434..000000000 --- a/src/server/clipboard_file_service.rs +++ /dev/null @@ -1,104 +0,0 @@ -use super::*; -use clipboard::{create_cliprdr_context, get_rx_client_msg, server_msg, ConnID}; -use hbb_common::{ - log, - tokio::sync::{ - mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, - Mutex as TokioMutex, - }, - tokio::time::{self, Duration, Instant}, - ResultType, -}; -use std::sync::atomic::{AtomicBool, Ordering}; - -pub const NAME: &'static str = "cliprdr"; - -lazy_static::lazy_static! { - static ref MSG_CHANNEL_SERVER: (UnboundedSender<(ConnID, Cliprdr)>, TokioMutex>) = { - let (tx, rx) = unbounded_channel(); - (tx, TokioMutex::new(rx)) - }; -} - -static RUNNING: AtomicBool = AtomicBool::new(false); - -pub fn new() -> GenericService { - let sp = GenericService::new(NAME, true); - sp.run::<_>(listen::run); - sp -} - -pub fn handle_serve_cliprdr_msg(id: i32, msg: Cliprdr) { - if RUNNING.load(Ordering::SeqCst) { - log::debug!("handle handle_serve_cliprdr_msg"); - MSG_CHANNEL_SERVER - .0 - .send(( - ConnID { - server_conn_id: id as u32, - remote_conn_id: 0, - }, - msg, - )) - .unwrap(); - } else { - // should not reach this branch - } -} - -mod listen { - use super::*; - - static WAIT: Duration = Duration::from_millis(1500); - - #[tokio::main] - pub async fn run(sp: GenericService) -> ResultType<()> { - let mut cliprdr_context = create_cliprdr_context(true, false)?; - - RUNNING.store(false, Ordering::SeqCst); - - let mut timer = time::interval_at(Instant::now() + WAIT, WAIT); - let mut client_rx = get_rx_client_msg().lock().await; - let mut server_rx = MSG_CHANNEL_SERVER.1.lock().await; - while sp.ok() { - RUNNING.store(true, Ordering::SeqCst); - - tokio::select! { - msg = client_rx.recv() => { - match msg { - Some((conn_id, msg)) => { - if conn_id.server_conn_id == 0 { - sp.send(msg) - } else { - sp.send_to(msg, conn_id.server_conn_id as i32) - } - } - None => { - // unreachable!() - } - } - } - msg = server_rx.recv() => { - match msg { - Some((conn_id, msg)) => { - let res = server_msg(&mut cliprdr_context, conn_id, msg); - if res != 0 { - // log::warn!("failed to process message for {}", id); - } - } - None => { - // unreachable!() - } - } - } - _ = timer.tick() => {}, - } - sp.snapshot(|_| Ok(()))?; - } - - RUNNING.store(false, Ordering::SeqCst); - log::info!("Clipboard listener stopped!"); - - Ok(()) - } -} diff --git a/src/server/connection.rs b/src/server/connection.rs index 2e4f40aa3..11c8815a7 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1,4 +1,7 @@ use super::{input_service::*, *}; +#[cfg(windows)] +use crate::{clipboard_file::*, common::update_clipboard, ipc}; +#[cfg(not(windows))] use crate::{common::update_clipboard, ipc}; use hbb_common::{ config::Config, @@ -243,17 +246,17 @@ impl Connection { } else if &name == "file" { conn.file = enabled; conn.send_permission(Permission::File, enabled).await; - #[cfg(windows)] - if let Some(s) = conn.server.upgrade() { - s.write().unwrap().subscribe( - super::clipboard_file_service::NAME, - conn.inner.clone(), conn.file_transfer_enabled()); - } } } ipc::Data::RawMessage(bytes) => { allow_err!(conn.stream.send_raw(bytes).await); } + ipc::Data::ClipbaordFile(_clip) => { + if conn.file_transfer_enabled() { + #[cfg(windows)] + allow_err!(conn.stream.send(&clip_2_msg(_clip)).await); + } + } _ => {} } }, @@ -620,10 +623,6 @@ impl Connection { if !self.audio_enabled() { noperms.push(super::audio_service::NAME); } - if !self.file_transfer_enabled() { - #[cfg(windows)] - noperms.push(super::clipboard_file_service::NAME); - } s.write() .unwrap() .add_connection(self.inner.clone(), &noperms); @@ -849,9 +848,13 @@ impl Connection { update_clipboard(cb, None); } } - #[cfg(windows)] - Some(message::Union::cliprdr(clip)) => { - clipboard_file_service::handle_serve_cliprdr_msg(self.inner.id, clip) + Some(message::Union::cliprdr(_clip)) => { + if self.file_transfer_enabled() { + #[cfg(windows)] + if let Some(clip) = msg_2_clip(_clip) { + self.send_to_cm(ipc::Data::ClipbaordFile(clip)) + } + } } Some(message::Union::file_action(fa)) => { if self.file_transfer.is_some() { @@ -1017,13 +1020,6 @@ impl Connection { if let Ok(q) = o.enable_file_transfer.enum_value() { if q != BoolOption::NotSet { self.enable_file_transfer = q == BoolOption::Yes; - if let Some(s) = self.server.upgrade() { - s.write().unwrap().subscribe( - super::clipboard_file_service::NAME, - self.inner.clone(), - self.file_transfer_enabled(), - ); - } } } if let Ok(q) = o.disable_clipboard.enum_value() { diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 138324471..7b6663302 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -1,4 +1,6 @@ use crate::ipc::{self, new_listener, Connection, Data}; +#[cfg(windows)] +use clipboard::{create_cliprdr_context, get_rx_clip_client, server_clip_file, ConnID}; use hbb_common::{ allow_err, config::{Config, ICON}, @@ -106,6 +108,7 @@ impl ConnectionManager { &self, id: i32, data: Data, + _tx_clip_file: &mpsc::UnboundedSender<(i32, ipc::ClipbaordFile)>, write_jobs: &mut Vec, conn: &mut Connection, ) { @@ -186,6 +189,10 @@ impl ConnectionManager { } } }, + Data::ClipbaordFile(_clip) => { + #[cfg(windows)] + allow_err!(_tx_clip_file.send((id, _clip))); + } _ => {} } } @@ -326,6 +333,12 @@ impl sciter::EventHandler for ConnectionManager { #[tokio::main(flavor = "current_thread")] async fn start_ipc(cm: ConnectionManager) { + let (tx_file, _rx_file) = mpsc::unbounded_channel::<(i32, ipc::ClipbaordFile)>(); + #[cfg(windows)] + let cm_clip = cm.clone(); + #[cfg(windows)] + std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file)); + match new_listener("_cm").await { Ok(mut incoming) => { while let Some(result) = incoming.next().await { @@ -333,6 +346,7 @@ async fn start_ipc(cm: ConnectionManager) { Ok(stream) => { let mut stream = Connection::new(stream); let cm = cm.clone(); + let tx_file = tx_file.clone(); tokio::spawn(async move { let mut conn_id: i32 = 0; let (tx, mut rx) = mpsc::unbounded_channel::(); @@ -356,7 +370,7 @@ async fn start_ipc(cm: ConnectionManager) { break; } _ => { - cm.handle_data(conn_id, data, &mut write_jobs, &mut stream).await; + cm.handle_data(conn_id, data, &tx_file, &mut write_jobs, &mut stream).await; } } } @@ -465,3 +479,68 @@ async fn start_pa() { } } } + +#[cfg(windows)] +#[tokio::main(flavor = "current_thread")] +async fn start_clipboard_file( + cm: ConnectionManager, + mut rx: mpsc::UnboundedReceiver<(i32, ipc::ClipbaordFile)>, +) { + let mut cliprdr_context = match create_cliprdr_context(true, false) { + Ok(context) => { + log::info!("clipboard context for file transfer created."); + context + } + Err(err) => { + log::error!( + "Create clipboard context for file transfer: {}", + err.to_string() + ); + return; + } + }; + let mut rx_clip_client = get_rx_clip_client().lock().await; + + loop { + tokio::select! { + clip_file = rx_clip_client.recv() => match clip_file { + Some((conn_id, clip)) => { + cmd_inner_send( + &cm, + conn_id.server_conn_id as i32, + Data::ClipbaordFile(clip) + ); + } + None => { + // + } + }, + server_msg = rx.recv() => match server_msg { + Some((server_conn_id, clip)) => { + let conn_id = ConnID { + server_conn_id: server_conn_id as u32, + remote_conn_id: 0, + }; + server_clip_file(&mut cliprdr_context, conn_id, clip); + } + None => { + break + } + } + } + } +} + +#[cfg(windows)] +fn cmd_inner_send<'a>(cm: &'a ConnectionManager, id: i32, data: Data) { + let lock = cm.read().unwrap(); + if id != 0 { + if let Some(s) = lock.senders.get(&id) { + allow_err!(s.send(data)); + } + } else { + for s in lock.senders.values() { + allow_err!(s.send(data.clone())); + } + } +} diff --git a/src/ui/remote.rs b/src/ui/remote.rs index eb99fa302..d13715178 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -1,12 +1,18 @@ -use crate::client::*; -use crate::common::{ - self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL, +#[cfg(windows)] +use crate::{ + client::*, + clipboard_file::*, + common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}, +}; +#[cfg(not(windows))] +use crate::{ + client::*, + common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}, }; #[cfg(windows)] use clipboard::{ cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context, - get_rx_client_msg as get_clipboard_file_rx_client_msg, server_msg as clipboard_file_msg, - ConnID as ClipboardFileConnID, + get_rx_clip_client, server_clip_file, ConnID as ClipboardFileConnID, }; use enigo::{self, Enigo, KeyboardControllable}; use hbb_common::{ @@ -1313,9 +1319,9 @@ impl Remote { // just build for now #[cfg(not(windows))] - let (_, mut clipboard_file_client_rx) = mpsc::unbounded_channel::(); + let (_, mut rx_clip_client) = mpsc::unbounded_channel::(); #[cfg(windows)] - let mut clipboard_file_client_rx = get_clipboard_file_rx_client_msg().lock().await; + let mut rx_clip_client = get_rx_clip_client().lock().await; loop { tokio::select! { @@ -1347,12 +1353,12 @@ impl Remote { } } } - _msg = clipboard_file_client_rx.recv() => { + _msg = rx_clip_client.recv() => { #[cfg(windows)] match _msg { - Some((conn_id, msg)) => { + Some((conn_id, clip)) => { if conn_id.remote_conn_id == 0 || conn_id.remote_conn_id == self.pid { - allow_err!(peer.send(&msg).await); + allow_err!(peer.send(&clip_2_msg(clip)).await); } } None => { @@ -1740,14 +1746,16 @@ impl Remote { Some(message::Union::cliprdr(clip)) => { if !self.handler.lc.read().unwrap().disable_clipboard { if let Some(context) = &mut self.clipboard_file_context { - clipboard_file_msg( - context, - ClipboardFileConnID { - server_conn_id: 0, - remote_conn_id: self.pid, - }, - clip, - ); + if let Some(clip) = msg_2_clip(clip) { + server_clip_file( + context, + ClipboardFileConnID { + server_conn_id: 0, + remote_conn_id: self.pid, + }, + clip, + ); + } } } }