Skip to content

Commit d587b0c

Browse files
fix(cliprdr): allow servers to announce clipboard ownership (#1053)
Servers can now send Format List PDU via initiate_copy() regardless of internal state. The existing state machine was designed for clients where clipboard initialization must complete before announcing ownership. MS-RDPECLIP Section 2.2.3.1 specifies that Format List PDU is sent by either client or server when the local clipboard is updated. Servers should be able to announce clipboard changes immediately after channel negotiation. This change enables RDP servers to properly announce clipboard ownership by bypassing the Initialization/Ready state check when R::is_server() is true. Client behavior remains unchanged. Co-authored-by: lamco-office <office@lamco.io>
1 parent 0903c9a commit d587b0c

File tree

1 file changed

+26
-20
lines changed
  • crates/ironrdp-cliprdr/src

1 file changed

+26
-20
lines changed

crates/ironrdp-cliprdr/src/lib.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -230,26 +230,32 @@ impl<R: Role> Cliprdr<R> {
230230
pub fn initiate_copy(&self, available_formats: &[ClipboardFormat]) -> PduResult<CliprdrSvcMessages<R>> {
231231
let mut pdus = Vec::new();
232232

233-
match (self.state, R::is_server()) {
234-
// When user initiates copy, we should send format list to server.
235-
(CliprdrState::Ready, _) => {
236-
pdus.push(ClipboardPdu::FormatList(
237-
self.build_format_list(available_formats).map_err(|e| encode_err!(e))?,
238-
));
239-
}
240-
(CliprdrState::Initialization, false) => {
241-
// During initialization state, first copy action is synthetic and should be sent along with
242-
// capabilities and temporary directory PDUs.
243-
pdus.push(ClipboardPdu::Capabilities(self.capabilities.clone()));
244-
pdus.push(ClipboardPdu::TemporaryDirectory(
245-
ClientTemporaryDirectory::new(self.backend.temporary_directory()).map_err(|e| encode_err!(e))?,
246-
));
247-
pdus.push(ClipboardPdu::FormatList(
248-
self.build_format_list(available_formats).map_err(|e| encode_err!(e))?,
249-
));
250-
}
251-
_ => {
252-
error!(?self.state, "Attempted to initiate copy in incorrect state");
233+
if R::is_server() {
234+
pdus.push(ClipboardPdu::FormatList(
235+
self.build_format_list(available_formats).map_err(|e| encode_err!(e))?,
236+
));
237+
} else {
238+
match self.state {
239+
CliprdrState::Ready => {
240+
pdus.push(ClipboardPdu::FormatList(
241+
self.build_format_list(available_formats).map_err(|e| encode_err!(e))?,
242+
));
243+
}
244+
CliprdrState::Initialization => {
245+
// During initialization state, first copy action is synthetic and should be sent along with
246+
// capabilities and temporary directory PDUs.
247+
pdus.push(ClipboardPdu::Capabilities(self.capabilities.clone()));
248+
pdus.push(ClipboardPdu::TemporaryDirectory(
249+
ClientTemporaryDirectory::new(self.backend.temporary_directory())
250+
.map_err(|e| encode_err!(e))?,
251+
));
252+
pdus.push(ClipboardPdu::FormatList(
253+
self.build_format_list(available_formats).map_err(|e| encode_err!(e))?,
254+
));
255+
}
256+
_ => {
257+
error!(?self.state, "Attempted to initiate copy in incorrect state");
258+
}
253259
}
254260
}
255261

0 commit comments

Comments
 (0)