Merge pull request #416 from fufesou/copy_paste

Move clipboard service to cm module
This commit is contained in:
RustDesk 2022-02-24 08:51:34 +08:00 committed by GitHub
commit 4fb8de9b68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1274 additions and 497 deletions

2
Cargo.lock generated
View File

@ -395,6 +395,8 @@ dependencies = [
"cc", "cc",
"hbb_common", "hbb_common",
"lazy_static", "lazy_static",
"serde 1.0.135",
"serde_derive",
"thiserror", "thiserror",
] ]

View File

@ -12,4 +12,6 @@ cc = "1.0"
[dependencies] [dependencies]
thiserror = "1.0.30" thiserror = "1.0.30"
lazy_static = "1.4" lazy_static = "1.4"
serde = "1.0"
serde_derive = "1.0"
hbb_common = { path = "../hbb_common" } hbb_common = { path = "../hbb_common" }

View File

@ -192,6 +192,8 @@ extern "C"
typedef UINT (*pcCliprdrServerFileContentsResponse)( typedef UINT (*pcCliprdrServerFileContentsResponse)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse); CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
typedef BOOL (*pcCheckEnabled)(UINT32 server_conn_id, UINT32 remote_conn_id);
// TODO: hide more members of clipboard context // TODO: hide more members of clipboard context
struct _cliprdr_client_context struct _cliprdr_client_context
{ {
@ -199,6 +201,7 @@ extern "C"
BOOL enableFiles; BOOL enableFiles;
BOOL enableOthers; BOOL enableOthers;
pcCheckEnabled CheckEnabled;
pcCliprdrServerCapabilities ServerCapabilities; pcCliprdrServerCapabilities ServerCapabilities;
pcCliprdrClientCapabilities ClientCapabilities; pcCliprdrClientCapabilities ClientCapabilities;
pcCliprdrMonitorReady MonitorReady; pcCliprdrMonitorReady MonitorReady;

View File

@ -456,6 +456,9 @@ pub type pcCliprdrServerFileContentsResponse = ::std::option::Option<
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE, fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT, ) -> UINT,
>; >;
pub type pcCheckEnabled = ::std::option::Option<
unsafe extern "C" fn(server_conn_id: UINT32, remote_conn_id: UINT32) -> BOOL,
>;
// TODO: hide more members of clipboard context // TODO: hide more members of clipboard context
#[repr(C)] #[repr(C)]
@ -464,6 +467,7 @@ pub struct _cliprdr_client_context {
pub custom: *mut ::std::os::raw::c_void, pub custom: *mut ::std::os::raw::c_void,
pub enableFiles: BOOL, pub enableFiles: BOOL,
pub enableOthers: BOOL, pub enableOthers: BOOL,
pub CheckEnabled: pcCheckEnabled,
pub ServerCapabilities: pcCliprdrServerCapabilities, pub ServerCapabilities: pcCliprdrServerCapabilities,
pub ClientCapabilities: pcCliprdrClientCapabilities, pub ClientCapabilities: pcCliprdrClientCapabilities,
pub MonitorReady: pcCliprdrMonitorReady, pub MonitorReady: pcCliprdrMonitorReady,
@ -492,6 +496,11 @@ pub struct _cliprdr_client_context {
extern "C" { extern "C" {
pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL; pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL; pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
pub(crate) fn empty_cliprdr(
context: *mut CliprdrClientContext,
server_conn_id: UINT32,
remote_conn_id: UINT32,
) -> BOOL;
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -508,6 +517,7 @@ impl CliprdrClientContext {
pub fn create( pub fn create(
enable_files: bool, enable_files: bool,
enable_others: bool, enable_others: bool,
check_enabled: pcCheckEnabled,
client_format_list: pcCliprdrClientFormatList, client_format_list: pcCliprdrClientFormatList,
client_format_list_response: pcCliprdrClientFormatListResponse, client_format_list_response: pcCliprdrClientFormatListResponse,
client_format_data_request: pcCliprdrClientFormatDataRequest, client_format_data_request: pcCliprdrClientFormatDataRequest,
@ -519,6 +529,7 @@ impl CliprdrClientContext {
custom: 0 as *mut _, custom: 0 as *mut _,
enableFiles: if enable_files { TRUE } else { FALSE }, enableFiles: if enable_files { TRUE } else { FALSE },
enableOthers: if enable_others { TRUE } else { FALSE }, enableOthers: if enable_others { TRUE } else { FALSE },
CheckEnabled: check_enabled,
ServerCapabilities: None, ServerCapabilities: None,
ClientCapabilities: None, ClientCapabilities: None,
MonitorReady: None, MonitorReady: None,

View File

@ -1,17 +1,18 @@
use cliprdr::*; use cliprdr::*;
use hbb_common::{ use hbb_common::{
log, log,
message_proto::cliprdr as msg_cliprdr,
message_proto::*,
tokio::sync::{ tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex, Mutex as TokioMutex,
}, },
ResultType, ResultType,
}; };
use serde_derive::{Deserialize, Serialize};
use std::{ use std::{
boxed::Box, boxed::Box,
collections::HashMap,
ffi::{CStr, CString}, ffi::{CStr, CString},
sync::Mutex,
}; };
pub mod cliprdr; pub mod cliprdr;
@ -22,111 +23,273 @@ pub struct ConnID {
pub remote_conn_id: u32, 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<u8>,
},
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<u8>,
},
}
#[derive(Default)]
struct ConnEnabled {
server_conn_enabled: HashMap<i32, bool>,
remote_conn_enabled: HashMap<i32, bool>,
}
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, Message)>, TokioMutex<UnboundedReceiver<(ConnID, Message)>>) = { static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, ClipbaordFile)>, TokioMutex<UnboundedReceiver<(ConnID, ClipbaordFile)>>) = {
let (tx, rx) = unbounded_channel(); let (tx, rx) = unbounded_channel();
(tx, TokioMutex::new(rx)) (tx, TokioMutex::new(rx))
}; };
static ref CLIP_CONN_ENABLED: Mutex<ConnEnabled> = Mutex::new(ConnEnabled::default());
} }
#[inline(always)] #[inline(always)]
pub fn get_rx_client_msg<'a>() -> &'a TokioMutex<UnboundedReceiver<(ConnID, Message)>> { pub fn get_rx_clip_client<'a>() -> &'a TokioMutex<UnboundedReceiver<(ConnID, ClipbaordFile)>> {
&MSG_CHANNEL_CLIENT.1 &MSG_CHANNEL_CLIENT.1
} }
pub fn server_msg(context: &mut Box<CliprdrClientContext>, conn_id: ConnID, msg: Cliprdr) -> u32 { pub fn set_conn_enabled(server_conn_id: i32, remote_conn_id: i32, enabled: bool) {
match msg.union { let mut lock = CLIP_CONN_ENABLED.lock().unwrap();
Some(msg_cliprdr::Union::ready(_)) => { if server_conn_id != 0 {
// proc ready let _ = lock.server_conn_enabled.insert(server_conn_id, enabled);
0 }
if remote_conn_id != 0 {
let _ = lock.remote_conn_enabled.insert(remote_conn_id, enabled);
}
}
pub fn empty_clipboard(
context: &mut Box<CliprdrClientContext>,
server_conn_id: i32,
remote_conn_id: i32,
) -> bool {
unsafe {
TRUE == cliprdr::empty_cliprdr(
&mut (**context),
server_conn_id as u32,
remote_conn_id as u32,
)
}
}
pub fn server_clip_file(
context: &mut Box<CliprdrClientContext>,
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;
} }
Some(msg_cliprdr::Union::format_list(req)) => {
log::debug!("server_format_list called"); 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); log::debug!("server_format_list called, return {}", ret);
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"); 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); log::debug!("server_format_list_response called, return {}", ret);
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"); 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); log::debug!("server_format_data_request called, return {}", ret);
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"); 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); log::debug!("server_format_data_response called, return {}", ret);
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"); 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); log::debug!("server_file_contents_request called, return {}", ret);
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"); 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); log::debug!("server_file_contents_response called, return {}", ret);
ret ret
} }
None => {
// unreachable!()
0
}
} }
} }
fn server_format_list( pub fn server_format_list(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: ConnID, server_conn_id: i32,
data: CliprdrServerFormatList, remote_conn_id: i32,
format_list: Vec<(i32, String)>,
) -> u32 { ) -> u32 {
// do not check msgFlags for now
unsafe { unsafe {
let num_formats = data.formats.len() as UINT32; let num_formats = format_list.len() as UINT32;
let mut formats = data let mut formats = format_list
.formats
.into_iter() .into_iter()
.map(|format| { .map(|format| {
if format.format.is_empty() { if format.1.is_empty() {
CLIPRDR_FORMAT { CLIPRDR_FORMAT {
formatId: format.id as UINT32, formatId: format.0 as UINT32,
formatName: 0 as *mut _, formatName: 0 as *mut _,
} }
} else { } else {
let n = match CString::new(format.format) { let n = match CString::new(format.1) {
Ok(n) => n, Ok(n) => n,
Err(_) => CString::new("").unwrap(), Err(_) => CString::new("").unwrap(),
}; };
CLIPRDR_FORMAT { CLIPRDR_FORMAT {
formatId: format.id as UINT32, formatId: format.0 as UINT32,
formatName: n.into_raw(), formatName: n.into_raw(),
} }
} }
}) })
.collect::<Vec<CLIPRDR_FORMAT>>(); .collect::<Vec<CLIPRDR_FORMAT>>();
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 { let format_list = CLIPRDR_FORMAT_LIST {
serverConnID: server_conn_id, serverConnID: server_conn_id as UINT32,
remoteConnID: remote_conn_id, remoteConnID: remote_conn_id as UINT32,
msgType: 0 as UINT16, msgType: 0 as UINT16,
msgFlags: 0 as UINT16, msgFlags: 0 as UINT16,
dataLen: 0 as UINT32, dataLen: 0 as UINT32,
@ -146,28 +309,18 @@ fn server_format_list(
ret as u32 ret as u32
} }
} }
fn server_format_list_response( pub fn server_format_list_response(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: ConnID, server_conn_id: i32,
data: CliprdrServerFormatListResponse, remote_conn_id: i32,
msg_flags: i32,
) -> u32 { ) -> u32 {
unsafe { 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 { let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE {
serverConnID: server_conn_id, serverConnID: server_conn_id as UINT32,
remoteConnID: remote_conn_id, remoteConnID: remote_conn_id as UINT32,
msgType: 0 as UINT16, msgType: 0 as UINT16,
msgFlags: data.msg_flags as UINT16, msgFlags: msg_flags as UINT16,
dataLen: 0 as UINT32, dataLen: 0 as UINT32,
}; };
@ -177,59 +330,41 @@ fn server_format_list_response(
ret as u32 ret as u32
} }
} }
fn server_format_data_request( pub fn server_format_data_request(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: ConnID, server_conn_id: i32,
data: CliprdrServerFormatDataRequest, remote_conn_id: i32,
requested_format_id: i32,
) -> u32 { ) -> u32 {
unsafe { 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 { let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST {
serverConnID: server_conn_id, serverConnID: server_conn_id as UINT32,
remoteConnID: remote_conn_id, remoteConnID: remote_conn_id as UINT32,
msgType: 0 as UINT16, msgType: 0 as UINT16,
msgFlags: 0 as UINT16, msgFlags: 0 as UINT16,
dataLen: 0 as UINT32, dataLen: 0 as UINT32,
requestedFormatId: data.requested_format_id as UINT32, requestedFormatId: requested_format_id as UINT32,
}; };
let ret = let ret =
((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request); ((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request);
ret as u32 ret as u32
} }
} }
fn server_format_data_response( pub fn server_format_data_response(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: ConnID, server_conn_id: i32,
mut data: CliprdrServerFormatDataResponse, remote_conn_id: i32,
msg_flags: i32,
mut format_data: Vec<u8>,
) -> u32 { ) -> u32 {
unsafe { 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 { let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE {
serverConnID: server_conn_id, serverConnID: server_conn_id as UINT32,
remoteConnID: remote_conn_id, remoteConnID: remote_conn_id as UINT32,
msgType: 0 as UINT16, msgType: 0 as UINT16,
msgFlags: data.msg_flags as UINT16, msgFlags: msg_flags as UINT16,
dataLen: data.format_data.len() as UINT32, dataLen: format_data.len() as UINT32,
requestedFormatData: data.format_data.as_mut_ptr(), requestedFormatData: format_data.as_mut_ptr(),
}; };
let ret = ((**context).ServerFormatDataResponse.unwrap())( let ret = ((**context).ServerFormatDataResponse.unwrap())(
&mut (**context), &mut (**context),
@ -238,36 +373,34 @@ fn server_format_data_response(
ret as u32 ret as u32
} }
} }
fn server_file_contents_request( pub fn server_file_contents_request(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: ConnID, server_conn_id: i32,
data: CliprdrFileContentsRequest, 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 { ) -> u32 {
unsafe { 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 { let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST {
serverConnID: server_conn_id, serverConnID: server_conn_id as UINT32,
remoteConnID: remote_conn_id, remoteConnID: remote_conn_id as UINT32,
msgType: 0 as UINT16, msgType: 0 as UINT16,
msgFlags: 0 as UINT16, msgFlags: 0 as UINT16,
dataLen: 0 as UINT32, dataLen: 0 as UINT32,
streamId: data.stream_id as UINT32, streamId: stream_id as UINT32,
listIndex: data.list_index as UINT32, listIndex: list_index as UINT32,
dwFlags: data.dw_flags as UINT32, dwFlags: dw_flags as UINT32,
nPositionLow: data.n_position_low as UINT32, nPositionLow: n_position_low as UINT32,
nPositionHigh: data.n_position_high as UINT32, nPositionHigh: n_position_high as UINT32,
cbRequested: data.cb_requested as UINT32, cbRequested: cb_requested as UINT32,
haveClipDataId: if data.have_clip_data_id { TRUE } else { FALSE }, haveClipDataId: if have_clip_data_id { TRUE } else { FALSE },
clipDataId: data.clip_data_id as UINT32, clipDataId: clip_data_id as UINT32,
}; };
let ret = ((**context).ServerFileContentsRequest.unwrap())( let ret = ((**context).ServerFileContentsRequest.unwrap())(
&mut (**context), &mut (**context),
@ -276,31 +409,24 @@ fn server_file_contents_request(
ret as u32 ret as u32
} }
} }
fn server_file_contents_response( pub fn server_file_contents_response(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: ConnID, server_conn_id: i32,
mut data: CliprdrFileContentsResponse, remote_conn_id: i32,
msg_flags: i32,
stream_id: i32,
mut requested_data: Vec<u8>,
) -> u32 { ) -> u32 {
unsafe { 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 { let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE {
serverConnID: server_conn_id, serverConnID: server_conn_id as UINT32,
remoteConnID: remote_conn_id, remoteConnID: remote_conn_id as UINT32,
msgType: 0 as UINT16, msgType: 0 as UINT16,
msgFlags: data.msg_flags as UINT16, msgFlags: msg_flags as UINT16,
dataLen: 4 + data.requested_data.len() as UINT32, dataLen: 4 + requested_data.len() as UINT32,
streamId: data.stream_id as UINT32, streamId: stream_id as UINT32,
cbRequested: data.requested_data.len() as UINT32, cbRequested: requested_data.len() as UINT32,
requestedData: data.requested_data.as_mut_ptr(), requestedData: requested_data.as_mut_ptr(),
}; };
let ret = ((**context).ServerFileContentsResponse.unwrap())( let ret = ((**context).ServerFileContentsResponse.unwrap())(
&mut (**context), &mut (**context),
@ -310,10 +436,14 @@ fn server_file_contents_response(
} }
} }
pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> ResultType<Box<CliprdrClientContext>> { pub fn create_cliprdr_context(
enable_files: bool,
enable_others: bool,
) -> ResultType<Box<CliprdrClientContext>> {
Ok(CliprdrClientContext::create( Ok(CliprdrClientContext::create(
enable_files, enable_files,
enable_others, enable_others,
Some(check_enabled),
Some(client_format_list), Some(client_format_list),
Some(client_format_list_response), Some(client_format_list_response),
Some(client_format_data_request), Some(client_format_data_request),
@ -323,23 +453,54 @@ pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> Result
)?) )?)
} }
extern "C" fn check_enabled(server_conn_id: UINT32, remote_conn_id: UINT32) -> BOOL {
let lock = CLIP_CONN_ENABLED.lock().unwrap();
if server_conn_id == 0 && remote_conn_id == 0 {
return FALSE;
}
let mut server_conn_enabled = false;
if server_conn_id != 0 {
if let Some(true) = lock.server_conn_enabled.get(&(server_conn_id as i32)) {
server_conn_enabled = true;
}
} else {
server_conn_enabled = true;
}
// let mut remote_conn_enabled = false;
// remote connection is always enabled
// if remote_conn_id != 0 {
// if let Some(true) = lock.remote_conn_enabled.get(&(remote_conn_id as i32)) {
// remote_conn_enabled = true;
// }
// } else {
// remote_conn_enabled = true;
// }
let remote_conn_enabled = true;
if server_conn_enabled && remote_conn_enabled {
return TRUE;
} else {
return FALSE;
}
}
extern "C" fn client_format_list( extern "C" fn client_format_list(
_context: *mut CliprdrClientContext, _context: *mut CliprdrClientContext,
format_list: *const CLIPRDR_FORMAT_LIST, clip_format_list: *const CLIPRDR_FORMAT_LIST,
) -> UINT { ) -> UINT {
log::debug!("client_format_list called"); 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 { unsafe {
let mut i = 0u32; let mut i = 0u32;
while i < (*format_list).numFormats { while i < (*clip_format_list).numFormats {
let format_data = &(*(*format_list).formats.offset(i as isize)); let format_data = &(*(*clip_format_list).formats.offset(i as isize));
if format_data.formatName.is_null() { if format_data.formatName.is_null() {
data.formats.push(CliprdrFormat { format_list.push((format_data.formatId as i32, "".to_owned()));
id: format_data.formatId as i32,
format: "".to_owned(),
..Default::default()
});
} else { } else {
let format_name = CStr::from_ptr(format_data.formatName).to_str(); let format_name = CStr::from_ptr(format_data.formatName).to_str();
let format_name = match format_name { let format_name = match format_name {
@ -349,30 +510,25 @@ extern "C" fn client_format_list(
"".to_owned() "".to_owned()
} }
}; };
data.formats.push(CliprdrFormat { format_list.push((format_data.formatId as i32, format_name));
id: format_data.formatId as i32,
format: format_name,
..Default::default()
});
} }
// log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name);
i += 1; i += 1;
} }
server_conn_id = (*clip_format_list).serverConnID as i32;
data.server_conn_id = (*format_list).serverConnID as i32; remote_conn_id = (*clip_format_list).remoteConnID as i32;
data.remote_conn_id = (*format_list).remoteConnID as i32;
} }
let conn_id = ConnID { let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32, server_conn_id: server_conn_id as u32,
remote_conn_id: data.remote_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 // 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 0
} }
@ -383,23 +539,25 @@ extern "C" fn client_format_list_response(
) -> UINT { ) -> UINT {
log::debug!("client_format_list_response called"); log::debug!("client_format_list_response called");
let mut data = CliprdrServerFormatListResponse::default(); let server_conn_id;
let remote_conn_id;
let msg_flags;
unsafe { unsafe {
data.server_conn_id = (*format_list_response).serverConnID as i32; server_conn_id = (*format_list_response).serverConnID as i32;
data.remote_conn_id = (*format_list_response).remoteConnID as i32; remote_conn_id = (*format_list_response).remoteConnID as i32;
data.msg_flags = (*format_list_response).msgFlags as i32; msg_flags = (*format_list_response).msgFlags as i32;
} }
let conn_id = ConnID { let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32, server_conn_id: server_conn_id as u32,
remote_conn_id: data.remote_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 // 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 0
} }
@ -410,23 +568,25 @@ extern "C" fn client_format_data_request(
) -> UINT { ) -> UINT {
log::debug!("client_format_data_request called"); 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 { unsafe {
data.server_conn_id = (*format_data_request).serverConnID as i32; server_conn_id = (*format_data_request).serverConnID as i32;
data.remote_conn_id = (*format_data_request).remoteConnID as i32; remote_conn_id = (*format_data_request).remoteConnID as i32;
data.requested_format_id = (*format_data_request).requestedFormatId as i32; requested_format_id = (*format_data_request).requestedFormatId as i32;
} }
let conn_id = ConnID { let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32, server_conn_id: server_conn_id as u32,
remote_conn_id: data.remote_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 // 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 0
} }
@ -437,28 +597,36 @@ extern "C" fn client_format_data_response(
) -> UINT { ) -> UINT {
log::debug!("client_format_data_response called"); 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 { unsafe {
data.server_conn_id = (*format_data_response).serverConnID as i32; server_conn_id = (*format_data_response).serverConnID as i32;
data.remote_conn_id = (*format_data_response).remoteConnID as i32; remote_conn_id = (*format_data_response).remoteConnID as i32;
data.msg_flags = (*format_data_response).msgFlags as i32; msg_flags = (*format_data_response).msgFlags as i32;
data.format_data = std::slice::from_raw_parts( if (*format_data_response).requestedFormatData.is_null() {
format_data = Vec::new();
} else {
format_data = std::slice::from_raw_parts(
(*format_data_response).requestedFormatData, (*format_data_response).requestedFormatData,
(*format_data_response).dataLen as usize, (*format_data_response).dataLen as usize,
) )
.to_vec(); .to_vec();
} }
}
let conn_id = ConnID { let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32, server_conn_id: server_conn_id as u32,
remote_conn_id: data.remote_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 // 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 0
} }
@ -479,30 +647,47 @@ extern "C" fn client_file_contents_request(
// return ERROR_INVALID_PARAMETER; // 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 { unsafe {
data.server_conn_id = (*file_contents_request).serverConnID as i32; server_conn_id = (*file_contents_request).serverConnID as i32;
data.remote_conn_id = (*file_contents_request).remoteConnID as i32; remote_conn_id = (*file_contents_request).remoteConnID as i32;
data.stream_id = (*file_contents_request).streamId as i32; stream_id = (*file_contents_request).streamId as i32;
data.list_index = (*file_contents_request).listIndex as i32; list_index = (*file_contents_request).listIndex as i32;
data.dw_flags = (*file_contents_request).dwFlags as i32; dw_flags = (*file_contents_request).dwFlags as i32;
data.n_position_low = (*file_contents_request).nPositionLow as i32; n_position_low = (*file_contents_request).nPositionLow as i32;
data.n_position_high = (*file_contents_request).nPositionHigh as i32; n_position_high = (*file_contents_request).nPositionHigh as i32;
data.cb_requested = (*file_contents_request).cbRequested as i32; cb_requested = (*file_contents_request).cbRequested as i32;
data.have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE; have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE;
data.clip_data_id = (*file_contents_request).clipDataId as i32; clip_data_id = (*file_contents_request).clipDataId as i32;
} }
let conn_id = ConnID { let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32, server_conn_id: server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32, remote_conn_id: remote_conn_id as u32,
}; };
let mut msg = Message::new(); let data = ClipbaordFile::FileContentsRequest {
let mut cliprdr = Cliprdr::new(); server_conn_id,
cliprdr.set_file_contents_request(data); remote_conn_id,
msg.set_cliprdr(cliprdr); 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 // 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 0
} }
@ -513,29 +698,40 @@ extern "C" fn client_file_contents_response(
) -> UINT { ) -> UINT {
log::debug!("client_file_contents_response called"); 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 { unsafe {
data.server_conn_id = (*file_contents_response).serverConnID as i32; server_conn_id = (*file_contents_response).serverConnID as i32;
data.remote_conn_id = (*file_contents_response).remoteConnID as i32; remote_conn_id = (*file_contents_response).remoteConnID as i32;
data.msg_flags = (*file_contents_response).msgFlags as i32; msg_flags = (*file_contents_response).msgFlags as i32;
data.stream_id = (*file_contents_response).streamId as i32; stream_id = (*file_contents_response).streamId as i32;
data.requested_data = std::slice::from_raw_parts( if (*file_contents_response).requestedData.is_null() {
requested_data = Vec::new();
} else {
requested_data = std::slice::from_raw_parts(
(*file_contents_response).requestedData, (*file_contents_response).requestedData,
(*file_contents_response).cbRequested as usize, (*file_contents_response).cbRequested as usize,
) )
.to_vec(); .to_vec();
} }
}
let conn_id = ConnID { let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32, server_conn_id: server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32, remote_conn_id: remote_conn_id as u32,
}; };
let mut msg = Message::new(); let data = ClipbaordFile::FileContentsResponse {
let mut cliprdr = Cliprdr::new(); server_conn_id,
cliprdr.set_file_contents_response(data); remote_conn_id,
msg.set_cliprdr(cliprdr); msg_flags,
stream_id,
requested_data,
};
// no need to handle result here // 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 0
} }

View File

@ -228,6 +228,8 @@ struct wf_clipboard
HANDLE response_data_event; HANDLE response_data_event;
LPDATAOBJECT data_obj; LPDATAOBJECT data_obj;
HANDLE data_obj_mutex;
ULONG req_fsize; ULONG req_fsize;
char *req_fdata; char *req_fdata;
HANDLE req_fevent; HANDLE req_fevent;
@ -252,6 +254,7 @@ typedef struct wf_clipboard wfClipboard;
BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
BOOL wf_do_empty_cliprdr(wfClipboard *clipboard);
static BOOL wf_create_file_obj(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject); static BOOL wf_create_file_obj(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject);
static void wf_destroy_file_obj(IDataObject *instance); static void wf_destroy_file_obj(IDataObject *instance);
@ -682,6 +685,10 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
return E_INVALIDARG; return E_INVALIDARG;
clipboard = (wfClipboard *)instance->m_pData; clipboard = (wfClipboard *)instance->m_pData;
if (!clipboard->context->CheckEnabled(instance->m_serverConnID, instance->m_remoteConnID))
{
return E_INVALIDARG;
}
if (!clipboard) if (!clipboard)
return E_INVALIDARG; return E_INVALIDARG;
@ -699,7 +706,13 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO
// DWORD remote_format_id = get_remote_format_id(clipboard, instance->m_pFormatEtc[idx].cfFormat); // DWORD remote_format_id = get_remote_format_id(clipboard, instance->m_pFormatEtc[idx].cfFormat);
// FIXME: origin code may be failed here??? // FIXME: origin code may be failed here???
if (cliprdr_send_data_request(instance->m_serverConnID, instance->m_remoteConnID, clipboard, instance->m_pFormatEtc[idx].cfFormat) != 0) if (cliprdr_send_data_request(instance->m_serverConnID, instance->m_remoteConnID, clipboard, instance->m_pFormatEtc[idx].cfFormat) != 0)
{
return E_UNEXPECTED; return E_UNEXPECTED;
}
if (!clipboard->hmem)
{
return E_UNEXPECTED;
}
pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */ pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */
/* GlobalLock returns a pointer to the first byte of the memory block, /* GlobalLock returns a pointer to the first byte of the memory block,
@ -1355,7 +1368,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard)
/* Ignore if other app is holding clipboard */ /* Ignore if other app is holding clipboard */
if (try_open_clipboard(clipboard->hwnd)) 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(); count = CountClipboardFormats();
if (count == 0)
{
CloseClipboard();
return CHANNEL_RC_NULL_DATA;
}
numFormats = (UINT32)count; numFormats = (UINT32)count;
formats = (CLIPRDR_FORMAT *)calloc(numFormats, sizeof(CLIPRDR_FORMAT)); formats = (CLIPRDR_FORMAT *)calloc(numFormats, sizeof(CLIPRDR_FORMAT));
@ -1377,7 +1399,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard)
} }
else else
{ {
while (formatId = EnumClipboardFormats(formatId)) while (formatId = EnumClipboardFormats(formatId) && index < numFormats)
formats[index++].formatId = formatId; formats[index++].formatId = formatId;
} }
@ -1395,6 +1417,10 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard)
{ {
formats[index].formatName = _strdup(formatName); formats[index].formatName = _strdup(formatName);
} }
else
{
formats[index].formatName = NULL;
}
} }
} }
@ -1408,11 +1434,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard)
rc = clipboard->context->ClientFormatList(clipboard->context, &formatList); rc = clipboard->context->ClientFormatList(clipboard->context, &formatList);
for (index = 0; index < numFormats; index++) for (index = 0; index < numFormats; index++)
{
if (formats[index].formatName != NULL)
{
free(formats[index].formatName); free(formats[index].formatName);
formats[index].formatName = NULL;
}
}
free(formats); free(formats);
return rc; return rc;
// return 0;
} }
static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *clipboard, UINT32 formatId) static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID, wfClipboard *clipboard, UINT32 formatId)
@ -1431,13 +1462,56 @@ static UINT cliprdr_send_data_request(UINT32 serverConnID, UINT32 remoteConnID,
formatDataRequest.requestedFormatId = remoteFormatId; formatDataRequest.requestedFormatId = remoteFormatId;
clipboard->requestedFormatId = formatId; clipboard->requestedFormatId = formatId;
rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest);
if (rc != ERROR_SUCCESS)
{
return rc;
}
if (WaitForSingleObject(clipboard->response_data_event, INFINITE) != WAIT_OBJECT_0) // with default 3min timeout
for (int i = 0; i < 20 * 60 * 3; i++)
{
DWORD waitRes = WaitForSingleObject(clipboard->response_data_event, 50);
if (waitRes == WAIT_TIMEOUT)
{
if (clipboard->context->CheckEnabled(serverConnID, remoteConnID))
{
continue;
}
else
{
break;
}
}
if (waitRes != WAIT_OBJECT_0)
{
return ERROR_INTERNAL_ERROR;
}
if (!ResetEvent(clipboard->response_data_event))
{
// NOTE: critical error here, crash may be better
rc = ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
else if (!ResetEvent(clipboard->response_data_event)) }
if (!clipboard->hmem)
{
rc = ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
}
return rc; return rc;
}
if (clipboard->hmem)
{
if (!ResetEvent(clipboard->response_data_event))
{
// NOTE: critical error here, crash may be better
}
return ERROR_SUCCESS;
}
return ERROR_INTERNAL_ERROR;
} }
UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, const void *streamid, ULONG index, UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, const void *streamid, ULONG index,
@ -1461,29 +1535,81 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 serverConn
fileContentsRequest.clipDataId = 0; fileContentsRequest.clipDataId = 0;
fileContentsRequest.msgFlags = 0; fileContentsRequest.msgFlags = 0;
rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest); rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest);
if (rc != ERROR_SUCCESS)
{
return rc;
}
if (WaitForSingleObject(clipboard->req_fevent, INFINITE) != WAIT_OBJECT_0) // with default 3min timeout
for (int i = 0; i < 20 * 60 * 3; i++)
{
DWORD waitRes = WaitForSingleObject(clipboard->req_fevent, 50);
if (waitRes == WAIT_TIMEOUT)
{
if (clipboard->context->CheckEnabled(serverConnID, remoteConnID))
{
continue;
}
else
{
break;
}
}
if (waitRes != WAIT_OBJECT_0)
{
return ERROR_INTERNAL_ERROR;
}
if (!ResetEvent(clipboard->req_fevent))
{
// NOTE: critical error here, crash may be better
rc = ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
else if (!ResetEvent(clipboard->req_fevent)) }
if (!clipboard->req_fdata)
{
rc = ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
}
return rc; return rc;
}
if (clipboard->req_fdata)
{
if (!ResetEvent(clipboard->req_fevent))
{
// NOTE: critical error here, crash may be better
}
return ERROR_SUCCESS;
}
return ERROR_INTERNAL_ERROR;
} }
static UINT cliprdr_send_response_filecontents(wfClipboard *clipboard, UINT32 serverConnID, UINT32 remoteConnID, UINT32 streamId, UINT32 size, static UINT cliprdr_send_response_filecontents(
wfClipboard *clipboard,
UINT32 serverConnID,
UINT32 remoteConnID,
UINT16 msgFlags,
UINT32 streamId,
UINT32 size,
BYTE *data) BYTE *data)
{ {
CLIPRDR_FILE_CONTENTS_RESPONSE fileContentsResponse; CLIPRDR_FILE_CONTENTS_RESPONSE fileContentsResponse;
if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsResponse) if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsResponse)
return ERROR_INTERNAL_ERROR; {
data = NULL;
size = 0;
msgFlags = CB_RESPONSE_FAIL;
}
fileContentsResponse.serverConnID = serverConnID; fileContentsResponse.serverConnID = serverConnID;
fileContentsResponse.remoteConnID = remoteConnID; fileContentsResponse.remoteConnID = remoteConnID;
fileContentsResponse.streamId = streamId; fileContentsResponse.streamId = streamId;
fileContentsResponse.cbRequested = size; fileContentsResponse.cbRequested = size;
fileContentsResponse.requestedData = data; fileContentsResponse.requestedData = data;
fileContentsResponse.msgFlags = CB_RESPONSE_OK; fileContentsResponse.msgFlags = msgFlags;
return clipboard->context->ClientFileContentsResponse(clipboard->context, return clipboard->context->ClientFileContentsResponse(clipboard->context,
&fileContentsResponse); &fileContentsResponse);
} }
@ -1522,7 +1648,6 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
case WM_CLIPBOARDUPDATE: case WM_CLIPBOARDUPDATE:
DEBUG_CLIPRDR("info: WM_CLIPBOARDUPDATE"); DEBUG_CLIPRDR("info: WM_CLIPBOARDUPDATE");
// if (clipboard->sync) // if (clipboard->sync)
{ {
if ((GetClipboardOwner() != clipboard->hwnd) && if ((GetClipboardOwner() != clipboard->hwnd) &&
@ -1614,6 +1739,11 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
case OLE_SETCLIPBOARD: case OLE_SETCLIPBOARD:
DEBUG_CLIPRDR("info: OLE_SETCLIPBOARD"); DEBUG_CLIPRDR("info: OLE_SETCLIPBOARD");
if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0)
{
break;
}
if (clipboard->data_obj != NULL) if (clipboard->data_obj != NULL)
{ {
wf_destroy_file_obj(clipboard->data_obj); wf_destroy_file_obj(clipboard->data_obj);
@ -1630,6 +1760,11 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
} }
free((void *)lParam); free((void *)lParam);
if (!ReleaseMutex(clipboard->data_obj_mutex))
{
// critical error!!!
}
break; break;
case DELAYED_RENDERING: case DELAYED_RENDERING:
@ -2270,7 +2405,7 @@ static UINT
wf_cliprdr_server_format_data_request(CliprdrClientContext *context, wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest) const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
{ {
UINT rc; UINT rc = ERROR_SUCCESS;
size_t size = 0; size_t size = 0;
void *buff = NULL; void *buff = NULL;
char *globlemem = NULL; char *globlemem = NULL;
@ -2280,12 +2415,18 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
wfClipboard *clipboard; wfClipboard *clipboard;
if (!context || !formatDataRequest) if (!context || !formatDataRequest)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
clipboard = (wfClipboard *)context->custom; clipboard = (wfClipboard *)context->custom;
if (!clipboard) if (!clipboard)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
requestedFormatId = formatDataRequest->requestedFormatId; requestedFormatId = formatDataRequest->requestedFormatId;
@ -2303,7 +2444,10 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
result = OleGetClipboard(&dataObj); result = OleGetClipboard(&dataObj);
if (FAILED(result)) if (FAILED(result))
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
ZeroMemory(&format_etc, sizeof(FORMATETC)); ZeroMemory(&format_etc, sizeof(FORMATETC));
ZeroMemory(&stg_medium, sizeof(STGMEDIUM)); ZeroMemory(&stg_medium, sizeof(STGMEDIUM));
@ -2316,7 +2460,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
if (FAILED(result)) if (FAILED(result))
{ {
DEBUG_CLIPRDR("dataObj->GetData failed."); rc = ERROR_INTERNAL_ERROR;
goto exit; goto exit;
} }
@ -2327,7 +2471,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
GlobalUnlock(stg_medium.hGlobal); GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium); ReleaseStgMedium(&stg_medium);
clipboard->nFiles = 0; clipboard->nFiles = 0;
goto exit; goto resp;
} }
clear_file_array(clipboard); clear_file_array(clipboard);
@ -2344,7 +2488,6 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
else else
{ {
char *p; char *p;
for (p = (char *)((char *)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0; for (p = (char *)((char *)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0;
p += len + 1, clipboard->nFiles++) p += len + 1, clipboard->nFiles++)
{ {
@ -2359,7 +2502,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
GlobalUnlock(stg_medium.hGlobal); GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium); ReleaseStgMedium(&stg_medium);
exit: resp:
size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW); size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW);
groupDsc = (FILEGROUPDESCRIPTORW *)malloc(size); groupDsc = (FILEGROUPDESCRIPTORW *)malloc(size);
@ -2377,6 +2520,7 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
} }
IDataObject_Release(dataObj); IDataObject_Release(dataObj);
rc = ERROR_SUCCESS;
} }
else else
{ {
@ -2388,26 +2532,50 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext *context,
if (!hClipdata) if (!hClipdata)
{ {
CloseClipboard(); CloseClipboard();
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
} }
}
else
{
globlemem = (char *)GlobalLock(hClipdata); globlemem = (char *)GlobalLock(hClipdata);
size = (int)GlobalSize(hClipdata); size = (int)GlobalSize(hClipdata);
buff = malloc(size); buff = malloc(size);
CopyMemory(buff, globlemem, size); CopyMemory(buff, globlemem, size);
GlobalUnlock(hClipdata); GlobalUnlock(hClipdata);
CloseClipboard(); CloseClipboard();
rc = ERROR_SUCCESS;
}
}
else
{
rc = ERROR_INTERNAL_ERROR;
} }
} }
exit:
if (rc == ERROR_SUCCESS)
{
response.msgFlags = CB_RESPONSE_OK;
}
else
{
response.msgFlags = CB_RESPONSE_FAIL;
}
response.serverConnID = formatDataRequest->serverConnID; response.serverConnID = formatDataRequest->serverConnID;
response.remoteConnID = formatDataRequest->remoteConnID; response.remoteConnID = formatDataRequest->remoteConnID;
response.msgFlags = CB_RESPONSE_OK;
response.dataLen = size; response.dataLen = size;
response.requestedFormatData = (BYTE *)buff; response.requestedFormatData = (BYTE *)buff;
rc = clipboard->context->ClientFormatDataResponse(clipboard->context, &response); if (ERROR_SUCCESS != clipboard->context->ClientFormatDataResponse(clipboard->context, &response))
{
// CAUTION: if failed to send, server will wait a long time
}
if (buff)
{
free(buff); free(buff);
}
return rc; return rc;
} }
@ -2420,32 +2588,48 @@ static UINT
wf_cliprdr_server_format_data_response(CliprdrClientContext *context, wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse) const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse)
{ {
UINT rc = ERROR_INTERNAL_ERROR;
BYTE *data; BYTE *data;
HANDLE hMem; HANDLE hMem;
wfClipboard *clipboard; wfClipboard *clipboard;
do
{
if (!context || !formatDataResponse) if (!context || !formatDataResponse)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
if (formatDataResponse->msgFlags != CB_RESPONSE_OK) break;
return E_FAIL; }
clipboard = (wfClipboard *)context->custom; clipboard = (wfClipboard *)context->custom;
if (!clipboard) if (!clipboard)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
break;
}
clipboard->hmem = NULL;
if (formatDataResponse->msgFlags != CB_RESPONSE_OK)
{
// BOOL emptyRes = wf_do_empty_cliprdr((wfClipboard *)context->custom);
// (void)emptyRes;
rc = E_FAIL;
break;
}
hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->dataLen); hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->dataLen);
if (!hMem) if (!hMem)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
break;
}
data = (BYTE *)GlobalLock(hMem); data = (BYTE *)GlobalLock(hMem);
if (!data) if (!data)
{ {
GlobalFree(hMem); GlobalFree(hMem);
return ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
break;
} }
CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen);
@ -2453,15 +2637,20 @@ wf_cliprdr_server_format_data_response(CliprdrClientContext *context,
if (!GlobalUnlock(hMem) && GetLastError()) if (!GlobalUnlock(hMem) && GetLastError())
{ {
GlobalFree(hMem); GlobalFree(hMem);
return ERROR_INTERNAL_ERROR; rc = ERROR_INTERNAL_ERROR;
break;
} }
clipboard->hmem = hMem; clipboard->hmem = hMem;
rc = CHANNEL_RC_OK;
} while (0);
if (!SetEvent(clipboard->response_data_event)) if (!SetEvent(clipboard->response_data_event))
return ERROR_INTERNAL_ERROR; {
// CAUTION: critical error here, process will hang up until wait timeout default 3min.
return CHANNEL_RC_OK; rc = ERROR_INTERNAL_ERROR;
}
return rc;
} }
/** /**
@ -2488,12 +2677,18 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
UINT32 cbRequested; UINT32 cbRequested;
if (!context || !fileContentsRequest) if (!context || !fileContentsRequest)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
clipboard = (wfClipboard *)context->custom; clipboard = (wfClipboard *)context->custom;
if (!clipboard) if (!clipboard)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
cbRequested = fileContentsRequest->cbRequested; cbRequested = fileContentsRequest->cbRequested;
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE) if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
@ -2502,14 +2697,18 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
pData = (BYTE *)calloc(1, cbRequested); pData = (BYTE *)calloc(1, cbRequested);
if (!pData) if (!pData)
goto error; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
hRet = OleGetClipboard(&pDataObj); hRet = OleGetClipboard(&pDataObj);
if (FAILED(hRet)) if (FAILED(hRet))
{ {
printf("filecontents: get ole clipboard failed.\n"); printf("filecontents: get ole clipboard failed.\n");
goto error; rc = ERROR_INTERNAL_ERROR;
goto exit;
} }
ZeroMemory(&vFormatEtc, sizeof(FORMATETC)); ZeroMemory(&vFormatEtc, sizeof(FORMATETC));
@ -2593,7 +2792,10 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE) if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
{ {
if (clipboard->nFiles <= fileContentsRequest->listIndex) if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
*((UINT32 *)&pData[0]) = *((UINT32 *)&pData[0]) =
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow; clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow;
*((UINT32 *)&pData[4]) = *((UINT32 *)&pData[4]) =
@ -2604,7 +2806,10 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
{ {
BOOL bRet; BOOL bRet;
if (clipboard->nFiles <= fileContentsRequest->listIndex) if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error; {
rc = ERROR_INTERNAL_ERROR;
goto exit;
}
bRet = wf_cliprdr_get_file_contents( bRet = wf_cliprdr_get_file_contents(
clipboard->file_names[fileContentsRequest->listIndex], pData, clipboard->file_names[fileContentsRequest->listIndex], pData,
fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested, fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested,
@ -2614,35 +2819,49 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
{ {
printf("get file contents failed.\n"); printf("get file contents failed.\n");
uSize = 0; uSize = 0;
goto error; rc = ERROR_INTERNAL_ERROR;
goto exit;
} }
} }
} }
rc = CHANNEL_RC_OK; rc = CHANNEL_RC_OK;
error: exit:
if (pDataObj) if (pDataObj)
IDataObject_Release(pDataObj); IDataObject_Release(pDataObj);
if (rc != CHANNEL_RC_OK)
{
uSize = 0;
}
if (uSize == 0) if (uSize == 0)
{
if (pData)
{ {
free(pData); free(pData);
pData = NULL; pData = NULL;
} }
}
sRc = sRc =
cliprdr_send_response_filecontents( cliprdr_send_response_filecontents(
clipboard, clipboard,
fileContentsRequest->serverConnID, fileContentsRequest->serverConnID,
fileContentsRequest->remoteConnID, fileContentsRequest->remoteConnID,
rc == CHANNEL_RC_OK ? CB_RESPONSE_OK : CB_RESPONSE_FAIL,
fileContentsRequest->streamId, fileContentsRequest->streamId,
uSize, uSize,
pData); pData);
free(pData);
if (sRc != CHANNEL_RC_OK) if (pData)
return sRc; {
free(pData);
}
// if (sRc != CHANNEL_RC_OK)
// return sRc;
return rc; return rc;
} }
@ -2657,34 +2876,50 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse) const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse)
{ {
wfClipboard *clipboard; wfClipboard *clipboard;
UINT rc = ERROR_INTERNAL_ERROR;
do
{
if (!context || !fileContentsResponse) if (!context || !fileContentsResponse)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
if (fileContentsResponse->msgFlags != CB_RESPONSE_OK) break;
return E_FAIL; }
clipboard = (wfClipboard *)context->custom; clipboard = (wfClipboard *)context->custom;
if (!clipboard) if (!clipboard)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
break;
}
clipboard->req_fsize = 0;
clipboard->req_fdata = NULL;
if (fileContentsResponse->msgFlags != CB_RESPONSE_OK)
{
rc = E_FAIL;
break;
}
clipboard->req_fsize = fileContentsResponse->cbRequested; clipboard->req_fsize = fileContentsResponse->cbRequested;
clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested); clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested);
if (!clipboard->req_fdata) if (!clipboard->req_fdata)
return ERROR_INTERNAL_ERROR; {
rc = ERROR_INTERNAL_ERROR;
break;
}
CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData, CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData,
fileContentsResponse->cbRequested); fileContentsResponse->cbRequested);
rc = CHANNEL_RC_OK;
} while (0);
if (!SetEvent(clipboard->req_fevent)) if (!SetEvent(clipboard->req_fevent))
{ {
free(clipboard->req_fdata); // CAUTION: critical error here, process will hang up until wait timeout default 3min.
return ERROR_INTERNAL_ERROR;
} }
return rc;
return CHANNEL_RC_OK;
} }
BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr) BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
@ -2720,6 +2955,9 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL))) if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
goto error; goto error;
if (!(clipboard->data_obj_mutex = CreateMutex(NULL, FALSE, "data_obj_mutex")))
goto error;
if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL))) if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
goto error; goto error;
@ -2750,6 +2988,23 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
cliprdr->custom = NULL; cliprdr->custom = NULL;
/* discard all contexts in clipboard */
if (try_open_clipboard(clipboard->hwnd))
{
if (!EmptyClipboard())
{
DEBUG_CLIPRDR("EmptyClipboard failed with 0x%x", GetLastError());
}
if (!CloseClipboard())
{
// critical error!!!
}
}
else
{
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
}
if (clipboard->hwnd) if (clipboard->hwnd)
PostMessage(clipboard->hwnd, WM_QUIT, 0, 0); PostMessage(clipboard->hwnd, WM_QUIT, 0, 0);
@ -2768,6 +3023,9 @@ BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr)
if (clipboard->response_data_event) if (clipboard->response_data_event)
CloseHandle(clipboard->response_data_event); CloseHandle(clipboard->response_data_event);
if (clipboard->data_obj_mutex)
CloseHandle(clipboard->data_obj_mutex);
if (clipboard->req_fevent) if (clipboard->req_fevent)
CloseHandle(clipboard->req_fevent); CloseHandle(clipboard->req_fevent);
@ -2788,3 +3046,86 @@ BOOL uninit_cliprdr(CliprdrClientContext *context)
{ {
return wf_cliprdr_uninit(&clipboard, context); return wf_cliprdr_uninit(&clipboard, context);
} }
BOOL empty_cliprdr(CliprdrClientContext *context, UINT32 server_conn_id, UINT32 remote_conn_id)
{
wfClipboard *clipboard = NULL;
CliprdrDataObject *instance = NULL;
BOOL rc = FALSE;
if (!context)
{
return FALSE;
}
if (server_conn_id == 0 && remote_conn_id == 0)
{
return TRUE;
}
clipboard = (wfClipboard *)context->custom;
if (!clipboard)
{
return FALSE;
}
instance = clipboard->data_obj;
if (instance)
{
if (server_conn_id != 0 && instance->m_serverConnID != server_conn_id)
{
return TRUE;
}
if (remote_conn_id != 0 && instance->m_remoteConnID != remote_conn_id)
{
return TRUE;
}
}
return wf_do_empty_cliprdr(clipboard);
}
BOOL wf_do_empty_cliprdr(wfClipboard *clipboard)
{
BOOL rc = FALSE;
if (!clipboard)
{
return FALSE;
}
if (WaitForSingleObject(clipboard->data_obj_mutex, INFINITE) != WAIT_OBJECT_0)
{
return FALSE;
}
do
{
if (clipboard->data_obj != NULL)
{
wf_destroy_file_obj(clipboard->data_obj);
clipboard->data_obj = NULL;
}
/* discard all contexts in clipboard */
if (!try_open_clipboard(clipboard->hwnd))
{
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
rc = FALSE;
break;
}
if (!EmptyClipboard())
{
rc = FALSE;
}
if (!CloseClipboard())
{
// critical error!!!
}
rc = TRUE;
} while (0);
if (!ReleaseMutex(clipboard->data_obj_mutex))
{
// critical error!!!
}
return rc;
}

207
src/clipboard_file.rs Normal file
View File

@ -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<CliprdrFormat> = 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<ClipbaordFile> {
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,
}
}

View File

@ -1,4 +1,5 @@
use crate::rendezvous_mediator::RendezvousMediator; use crate::rendezvous_mediator::RendezvousMediator;
pub use clipboard::ClipbaordFile;
use hbb_common::{ use hbb_common::{
allow_err, bail, bytes, allow_err, bail, bytes,
bytes_codec::BytesCodec, bytes_codec::BytesCodec,
@ -73,6 +74,7 @@ pub enum Data {
clipboard: bool, clipboard: bool,
audio: bool, audio: bool,
file: bool, file: bool,
file_transfer_enabled: bool,
}, },
ChatMessage { ChatMessage {
text: String, text: String,
@ -103,6 +105,8 @@ pub enum Data {
to: String, to: String,
}, },
SyncConfigToUserResp(bool), SyncConfigToUserResp(bool),
ClipbaordFile(ClipbaordFile),
ClipboardFileEnabled(bool),
} }
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]

View File

@ -28,3 +28,6 @@ pub mod cli;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
mod port_forward; mod port_forward;
mod lang; mod lang;
#[cfg(windows)]
pub mod clipboard_file;

View File

@ -29,8 +29,6 @@ use std::{
pub mod audio_service; pub mod audio_service;
mod clipboard_service; mod clipboard_service;
#[cfg(windows)]
pub mod clipboard_file_service;
mod connection; mod connection;
pub mod input_service; pub mod input_service;
mod service; mod service;
@ -63,8 +61,6 @@ pub fn new() -> ServerPtr {
server.add_service(Box::new(audio_service::new())); server.add_service(Box::new(audio_service::new()));
server.add_service(Box::new(video_service::new())); server.add_service(Box::new(video_service::new()));
server.add_service(Box::new(clipboard_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_cursor()));
server.add_service(Box::new(input_service::new_pos())); server.add_service(Box::new(input_service::new_pos()));
Arc::new(RwLock::new(server)) Arc::new(RwLock::new(server))

View File

@ -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<UnboundedReceiver<(ConnID, Cliprdr)>>) = {
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(())
}
}

View File

@ -1,4 +1,7 @@
use super::{input_service::*, *}; use super::{input_service::*, *};
#[cfg(windows)]
use crate::{clipboard_file::*, common::update_clipboard, ipc};
#[cfg(not(windows))]
use crate::{common::update_clipboard, ipc}; use crate::{common::update_clipboard, ipc};
use hbb_common::{ use hbb_common::{
config::Config, config::Config,
@ -243,17 +246,18 @@ impl Connection {
} else if &name == "file" { } else if &name == "file" {
conn.file = enabled; conn.file = enabled;
conn.send_permission(Permission::File, enabled).await; conn.send_permission(Permission::File, enabled).await;
#[cfg(windows)] conn.send_to_cm(ipc::Data::ClipboardFileEnabled(conn.file_transfer_enabled()));
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) => { ipc::Data::RawMessage(bytes) => {
allow_err!(conn.stream.send_raw(bytes).await); 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 +624,6 @@ impl Connection {
if !self.audio_enabled() { if !self.audio_enabled() {
noperms.push(super::audio_service::NAME); noperms.push(super::audio_service::NAME);
} }
if !self.file_transfer_enabled() {
#[cfg(windows)]
noperms.push(super::clipboard_file_service::NAME);
}
s.write() s.write()
.unwrap() .unwrap()
.add_connection(self.inner.clone(), &noperms); .add_connection(self.inner.clone(), &noperms);
@ -655,6 +655,7 @@ impl Connection {
clipboard: self.clipboard, clipboard: self.clipboard,
audio: self.audio, audio: self.audio,
file: self.file, file: self.file,
file_transfer_enabled: self.file_transfer_enabled(),
}); });
} }
@ -849,9 +850,13 @@ impl Connection {
update_clipboard(cb, None); update_clipboard(cb, None);
} }
} }
Some(message::Union::cliprdr(_clip)) => {
if self.file_transfer_enabled() {
#[cfg(windows)] #[cfg(windows)]
Some(message::Union::cliprdr(clip)) => { if let Some(clip) = msg_2_clip(_clip) {
clipboard_file_service::handle_serve_cliprdr_msg(self.inner.id, clip) self.send_to_cm(ipc::Data::ClipbaordFile(clip))
}
}
} }
Some(message::Union::file_action(fa)) => { Some(message::Union::file_action(fa)) => {
if self.file_transfer.is_some() { if self.file_transfer.is_some() {
@ -1017,13 +1022,7 @@ impl Connection {
if let Ok(q) = o.enable_file_transfer.enum_value() { if let Ok(q) = o.enable_file_transfer.enum_value() {
if q != BoolOption::NotSet { if q != BoolOption::NotSet {
self.enable_file_transfer = q == BoolOption::Yes; self.enable_file_transfer = q == BoolOption::Yes;
if let Some(s) = self.server.upgrade() { self.send_to_cm(ipc::Data::ClipboardFileEnabled(self.file_transfer_enabled()));
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() { if let Ok(q) = o.disable_clipboard.enum_value() {

View File

@ -1,4 +1,9 @@
use crate::ipc::{self, new_listener, Connection, Data}; use crate::ipc::{self, new_listener, Connection, Data};
#[cfg(windows)]
use clipboard::{
create_cliprdr_context, empty_clipboard, get_rx_clip_client, server_clip_file,
set_conn_enabled, ConnID,
};
use hbb_common::{ use hbb_common::{
allow_err, allow_err,
config::{Config, ICON}, config::{Config, ICON},
@ -106,6 +111,8 @@ impl ConnectionManager {
&self, &self,
id: i32, id: i32,
data: Data, data: Data,
_tx_clip_file: &mpsc::UnboundedSender<(i32, ipc::ClipbaordFile)>,
_tx_clip_empty: &mpsc::UnboundedSender<i32>,
write_jobs: &mut Vec<fs::TransferJob>, write_jobs: &mut Vec<fs::TransferJob>,
conn: &mut Connection, conn: &mut Connection,
) { ) {
@ -186,6 +193,17 @@ impl ConnectionManager {
} }
} }
}, },
Data::ClipbaordFile(_clip) => {
#[cfg(windows)]
allow_err!(_tx_clip_file.send((id, _clip)));
}
Data::ClipboardFileEnabled(enabled) => {
#[cfg(windows)]
set_conn_enabled(id, 0, enabled);
if !enabled {
allow_err!(_tx_clip_empty.send(id));
}
}
_ => {} _ => {}
} }
} }
@ -326,6 +344,13 @@ impl sciter::EventHandler for ConnectionManager {
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn start_ipc(cm: ConnectionManager) { async fn start_ipc(cm: ConnectionManager) {
let (tx_file, _rx_file) = mpsc::unbounded_channel::<(i32, ipc::ClipbaordFile)>();
let (tx_clip_empty, _rx_clip_empty) = mpsc::unbounded_channel::<i32>();
#[cfg(windows)]
let cm_clip = cm.clone();
#[cfg(windows)]
std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file, _rx_clip_empty));
match new_listener("_cm").await { match new_listener("_cm").await {
Ok(mut incoming) => { Ok(mut incoming) => {
while let Some(result) = incoming.next().await { while let Some(result) = incoming.next().await {
@ -333,6 +358,8 @@ async fn start_ipc(cm: ConnectionManager) {
Ok(stream) => { Ok(stream) => {
let mut stream = Connection::new(stream); let mut stream = Connection::new(stream);
let cm = cm.clone(); let cm = cm.clone();
let tx_file = tx_file.clone();
let tx_clip_empty = tx_clip_empty.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut conn_id: i32 = 0; let mut conn_id: i32 = 0;
let (tx, mut rx) = mpsc::unbounded_channel::<Data>(); let (tx, mut rx) = mpsc::unbounded_channel::<Data>();
@ -347,16 +374,22 @@ async fn start_ipc(cm: ConnectionManager) {
} }
Ok(Some(data)) => { Ok(Some(data)) => {
match data { match data {
Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file} => { Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled} => {
conn_id = id; conn_id = id;
#[cfg(windows)]
set_conn_enabled(id, 0, file_transfer_enabled);
let _ = file_transfer_enabled;
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, tx.clone());
} }
Data::Close => { Data::Close => {
allow_err!(tx_clip_empty.send(conn_id));
#[cfg(windows)]
set_conn_enabled(conn_id, 0, false);
log::info!("cm ipc connection closed from connection request"); log::info!("cm ipc connection closed from connection request");
break; break;
} }
_ => { _ => {
cm.handle_data(conn_id, data, &mut write_jobs, &mut stream).await; cm.handle_data(conn_id, data, &tx_file, &tx_clip_empty, &mut write_jobs, &mut stream).await;
} }
} }
} }
@ -465,3 +498,79 @@ 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)>,
mut rx_clip_empty: mpsc::UnboundedReceiver<i32>,
) {
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
}
},
server_conn_id = rx_clip_empty.recv() => match server_conn_id {
Some(server_conn_id) => {
if !empty_clipboard(&mut cliprdr_context, server_conn_id, 0) {
// log::error!("failed to empty clipboard");
}
}
None => {
break
}
}
}
}
}
#[cfg(windows)]
fn cmd_inner_send(cm: &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()));
}
}
}

View File

@ -1,12 +1,18 @@
use crate::client::*; #[cfg(windows)]
use crate::common::{ use crate::{
self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL, 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)] #[cfg(windows)]
use clipboard::{ use clipboard::{
cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context, 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, get_rx_clip_client, server_clip_file, ConnID as ClipboardFileConnID,
ConnID as ClipboardFileConnID,
}; };
use enigo::{self, Enigo, KeyboardControllable}; use enigo::{self, Enigo, KeyboardControllable};
use hbb_common::{ use hbb_common::{
@ -1313,9 +1319,9 @@ impl Remote {
// just build for now // just build for now
#[cfg(not(windows))] #[cfg(not(windows))]
let (_, mut clipboard_file_client_rx) = mpsc::unbounded_channel::<i32>(); let (_, mut rx_clip_client) = mpsc::unbounded_channel::<i32>();
#[cfg(windows)] #[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 { loop {
tokio::select! { tokio::select! {
@ -1347,12 +1353,12 @@ impl Remote {
} }
} }
} }
_msg = clipboard_file_client_rx.recv() => { _msg = rx_clip_client.recv() => {
#[cfg(windows)] #[cfg(windows)]
match _msg { match _msg {
Some((conn_id, msg)) => { Some((conn_id, clip)) => {
if conn_id.remote_conn_id == 0 || conn_id.remote_conn_id == self.pid { 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 => { None => {
@ -1740,7 +1746,8 @@ impl Remote {
Some(message::Union::cliprdr(clip)) => { Some(message::Union::cliprdr(clip)) => {
if !self.handler.lc.read().unwrap().disable_clipboard { if !self.handler.lc.read().unwrap().disable_clipboard {
if let Some(context) = &mut self.clipboard_file_context { if let Some(context) = &mut self.clipboard_file_context {
clipboard_file_msg( if let Some(clip) = msg_2_clip(clip) {
server_clip_file(
context, context,
ClipboardFileConnID { ClipboardFileConnID {
server_conn_id: 0, server_conn_id: 0,
@ -1751,6 +1758,7 @@ impl Remote {
} }
} }
} }
}
Some(message::Union::file_response(fr)) => match fr.union { Some(message::Union::file_response(fr)) => match fr.union {
Some(file_response::Union::dir(fd)) => { Some(file_response::Union::dir(fd)) => {
let entries = fd.entries.to_vec(); let entries = fd.entries.to_vec();