Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/ironrdp-client/src/rdp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,14 @@ async fn active_session(
Some(cliprdr.initiate_paste(format)
.map_err(|e| session::custom_err!("CLIPRDR", e))?)
}
ClipboardMessage::SendLockClipboard { clip_data_id } => {
Some(cliprdr.lock_clipboard(clip_data_id)
.map_err(|e| session::custom_err!("CLIPRDR", e))?)
}
ClipboardMessage::SendUnlockClipboard { clip_data_id } => {
Some(cliprdr.unlock_clipboard(clip_data_id)
.map_err(|e| session::custom_err!("CLIPRDR", e))?)
}
ClipboardMessage::Error(e) => {
error!("Clipboard backend error: {}", e);
None
Expand Down
10 changes: 10 additions & 0 deletions crates/ironrdp-cliprdr/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ pub enum ClipboardMessage {
/// received.
SendInitiatePaste(ClipboardFormatId),

/// Sent by clipboard backend when clipboard data should be locked on the remote.
///
/// Implementation should send lock clipboard data PDU on `CLIPRDR` SVC when received.
SendLockClipboard { clip_data_id: u32 },

/// Sent by clipboard backend when clipboard data should be unlocked on the remote.
///
/// Implementation should send unlock clipboard data PDU on `CLIPRDR` SVC when received.
SendUnlockClipboard { clip_data_id: u32 },

/// Failure received from the OS clipboard event loop.
///
/// Client implementation should log/display this error.
Expand Down
28 changes: 27 additions & 1 deletion crates/ironrdp-cliprdr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ironrdp_svc::{
};
use pdu::{
Capabilities, ClientTemporaryDirectory, ClipboardFormat, ClipboardFormatId, ClipboardGeneralCapabilityFlags,
ClipboardPdu, ClipboardProtocolVersion, FileContentsResponse, FormatDataRequest, FormatListResponse,
ClipboardPdu, ClipboardProtocolVersion, FileContentsResponse, FormatDataRequest, FormatListResponse, LockDataId,
OwnedFormatDataResponse,
};
use tracing::{error, info};
Expand Down Expand Up @@ -276,6 +276,32 @@ impl<R: Role> Cliprdr<R> {

Ok(vec![into_cliprdr_message(pdu)].into())
}

/// [2.2.4.6] Lock Clipboard Data PDU (CLIPRDR_LOCK_CLIPDATA)
///
/// Locks clipboard data on the remote before file transfer. Should be called before
/// requesting file contents to ensure data stability during transfer.
///
/// [2.2.4.6]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeclip/150bac72-bc7f-42e5-9e8e-cb5a0ddc7dbc
pub fn lock_clipboard(&self, clip_data_id: u32) -> PduResult<CliprdrSvcMessages<R>> {
ready_guard!(self, lock_clipboard);

let pdu = ClipboardPdu::LockData(LockDataId(clip_data_id));
Ok(vec![into_cliprdr_message(pdu)].into())
}

/// [2.2.4.7] Unlock Clipboard Data PDU (CLIPRDR_UNLOCK_CLIPDATA)
///
/// Unlocks previously locked clipboard data. Should be called after file transfer
/// operations complete.
///
/// [2.2.4.7]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeclip/e587a20c-fb7c-47d1-8698-4bcb92c48a38
pub fn unlock_clipboard(&self, clip_data_id: u32) -> PduResult<CliprdrSvcMessages<R>> {
ready_guard!(self, unlock_clipboard);

let pdu = ClipboardPdu::UnlockData(LockDataId(clip_data_id));
Ok(vec![into_cliprdr_message(pdu)].into())
}
}

impl<R: Role> SvcProcessor for Cliprdr<R> {
Expand Down
2 changes: 1 addition & 1 deletion crates/ironrdp-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ ironrdp-svc = { path = "../ironrdp-svc", version = "0.5" } # public
ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.5" } # public
ironrdp-displaycontrol = { path = "../ironrdp-displaycontrol", version = "0.4" } # public
ironrdp-dvc = { path = "../ironrdp-dvc", version = "0.4" } # public
ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.8" }
ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.8", features = ["reqwest"] }
ironrdp-acceptor = { path = "../ironrdp-acceptor", version = "0.8" } # public
ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.7" } # public
ironrdp-rdpsnd = { path = "../ironrdp-rdpsnd", version = "0.6" } # public
Expand Down
4 changes: 4 additions & 0 deletions crates/ironrdp-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ impl RdpServer {
ClipboardMessage::SendInitiateCopy(formats) => cliprdr.initiate_copy(&formats),
ClipboardMessage::SendFormatData(data) => cliprdr.submit_format_data(data),
ClipboardMessage::SendInitiatePaste(format) => cliprdr.initiate_paste(format),
ClipboardMessage::SendLockClipboard { clip_data_id } => cliprdr.lock_clipboard(clip_data_id),
ClipboardMessage::SendUnlockClipboard { clip_data_id } => {
cliprdr.unlock_clipboard(clip_data_id)
}
ClipboardMessage::Error(error) => {
error!(?error, "Handling clipboard event");
continue;
Expand Down
8 changes: 8 additions & 0 deletions crates/ironrdp-web/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,14 @@ impl iron_remote_desktop::Session for Session {
cliprdr.initiate_paste(format)
.context("CLIPRDR initiate paste")?
),
ClipboardMessage::SendLockClipboard { clip_data_id } => Some(
cliprdr.lock_clipboard(clip_data_id)
.context("CLIPRDR lock clipboard")?
),
ClipboardMessage::SendUnlockClipboard { clip_data_id } => Some(
cliprdr.unlock_clipboard(clip_data_id)
.context("CLIPRDR unlock clipboard")?
),
ClipboardMessage::Error(e) => {
error!("Clipboard backend error: {}", e);
None
Expand Down
8 changes: 8 additions & 0 deletions ffi/src/clipboard/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ pub mod ffi {
ironrdp::cliprdr::backend::ClipboardMessage::SendInitiatePaste(_) => {
ClipboardMessageType::SendInitiatePaste
}
ironrdp::cliprdr::backend::ClipboardMessage::SendLockClipboard { .. } => {
ClipboardMessageType::SendLockClipboard
}
ironrdp::cliprdr::backend::ClipboardMessage::SendUnlockClipboard { .. } => {
ClipboardMessageType::SendUnlockClipboard
}
ironrdp::cliprdr::backend::ClipboardMessage::Error(_) => ClipboardMessageType::Error,
}
}
Expand Down Expand Up @@ -51,6 +57,8 @@ pub mod ffi {
SendInitiateCopy,
SendFormatData,
SendInitiatePaste,
SendLockClipboard,
SendUnlockClipboard,
Error,
}

Expand Down
Loading