move clipboard file service to cm module

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-02-22 14:17:50 +08:00
parent 69769cc123
commit 8834251eec
12 changed files with 720 additions and 391 deletions

2
Cargo.lock generated
View File

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

View File

@ -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" }

View File

@ -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<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>,
},
}
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();
(tx, TokioMutex::new(rx))
};
}
#[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
}
pub fn server_msg(context: &mut Box<CliprdrClientContext>, 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<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;
}
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<CliprdrClientContext>,
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::<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 {
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<CliprdrClientContext>,
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<CliprdrClientContext>,
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<CliprdrClientContext>,
conn_id: ConnID,
mut data: CliprdrServerFormatDataResponse,
server_conn_id: i32,
remote_conn_id: i32,
msg_flags: i32,
mut format_data: Vec<u8>,
) -> 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<CliprdrClientContext>,
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<CliprdrClientContext>,
conn_id: ConnID,
mut data: CliprdrFileContentsResponse,
server_conn_id: i32,
remote_conn_id: i32,
msg_flags: i32,
stream_id: i32,
mut requested_data: Vec<u8>,
) -> 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<Box<CliprdrClientContext>> {
pub fn create_cliprdr_context(
enable_files: bool,
enable_others: bool,
) -> ResultType<Box<CliprdrClientContext>> {
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
}

View File

@ -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)

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;
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")]

View File

@ -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;

View File

@ -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))

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::*, *};
#[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() {

View File

@ -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<fs::TransferJob>,
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::<Data>();
@ -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()));
}
}
}

View File

@ -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::<i32>();
let (_, mut rx_clip_client) = mpsc::unbounded_channel::<i32>();
#[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,
);
}
}
}
}