rdp/core/
capability.rs

1use model::data::{Component, U16, U32, DynOption, MessageOption, Message, DataType, Check, Trame, to_vec};
2use model::error::{RdpResult, Error, RdpError, RdpErrorKind};
3use std::io::Cursor;
4use core::gcc::{KeyboardLayout, KeyboardType};
5use num_enum::TryFromPrimitive;
6use std::convert::TryFrom;
7
8/// All capabilities that can be negotiated
9/// between client and server
10/// This is done by the global channel
11#[repr(u16)]
12#[derive(Eq, PartialEq, Hash, Debug, TryFromPrimitive)]
13pub enum CapabilitySetType {
14    CapstypeGeneral = 0x0001,
15    CapstypeBitmap = 0x0002,
16    CapstypeOrder = 0x0003,
17    CapstypeBitmapcache = 0x0004,
18    CapstypeControl = 0x0005,
19    CapstypeActivation = 0x0007,
20    CapstypePointer = 0x0008,
21    CapstypeShare = 0x0009,
22    CapstypeColorcache = 0x000A,
23    CapstypeSound = 0x000C,
24    CapstypeInput = 0x000D,
25    CapstypeFont = 0x000E,
26    CapstypeBrush = 0x000F,
27    CapstypeGlyphcache = 0x0010,
28    CapstypeOffscreencache = 0x0011,
29    CapstypeBitmapcacheHostsupport = 0x0012,
30    CapstypeBitmapcacheRev2 = 0x0013,
31    CapstypeVirtualchannel = 0x0014,
32    CapstypeDrawninegridcache = 0x0015,
33    CapstypeDrawgdiplus = 0x0016,
34    CapstypeRail = 0x0017,
35    CapstypeWindow = 0x0018,
36    CapsettypeCompdesk = 0x0019,
37    CapsettypeMultifragmentupdate = 0x001A,
38    CapsettypeLargePointer = 0x001B,
39    CapsettypeSurfaceCommands = 0x001C,
40    CapsettypeBitmapCodecs = 0x001D,
41    CapssettypeFrameAcknowledge = 0x001E
42}
43
44/// A capability
45/// Composed by a type and structured
46/// component
47///
48/// # Example
49/// ```rust, ignore
50/// use rdp::core::capability::{Capability, CapabilitySetType};
51/// let capability = Capability {
52///     cap_type: CapabilitySetType::CapstypePointer,
53///     message: component![
54///         "colorPointerFlag" => U16::LE(0),
55///         "colorPointerCacheSize" => U16::LE(20)
56///     ]
57/// };
58/// ```
59pub struct Capability {
60    pub cap_type: CapabilitySetType,
61    pub message: Component
62}
63
64impl Capability {
65    /// Parse the capability from a parent capability_set
66    ///
67    /// # Example
68    /// ```
69    /// #[macro_use]
70    /// # extern crate rdp;
71    /// # use rdp::model::data::{DataType};
72    /// # use rdp::model::error::{Error, RdpError, RdpResult, RdpErrorKind};
73    /// # use rdp::core::capability::{capability_set, ts_general_capability_set, Capability};
74    /// # fn main() {
75    ///     let example = capability_set(Some(ts_general_capability_set(Some(4))));
76    ///     let general_capability = Capability::from_capability_set(&example).unwrap();
77    ///     assert_eq!(cast!(DataType::U16, general_capability.message["extraFlags"]).unwrap(), 4)
78    /// # }
79    /// ```
80    pub fn from_capability_set(capability_set: &Component) -> RdpResult<Capability> {
81        let cap_type = CapabilitySetType::try_from(cast!(DataType::U16, capability_set["capabilitySetType"])?)?;
82        let mut capability = match cap_type {
83            CapabilitySetType::CapstypeGeneral => ts_general_capability_set(None),
84            CapabilitySetType::CapstypeBitmap => ts_bitmap_capability_set(None, None, None),
85            CapabilitySetType::CapstypeOrder => ts_order_capability_set(None),
86            CapabilitySetType::CapstypeBitmapcache => ts_bitmap_cache_capability_set(),
87            CapabilitySetType::CapstypePointer => ts_pointer_capability_set(),
88            CapabilitySetType::CapstypeInput => ts_input_capability_set(None, None),
89            CapabilitySetType::CapstypeBrush => ts_brush_capability_set(),
90            CapabilitySetType::CapstypeGlyphcache => ts_glyph_capability_set(),
91            CapabilitySetType::CapstypeOffscreencache => ts_offscreen_capability_set(),
92            CapabilitySetType::CapstypeVirtualchannel => ts_virtualchannel_capability_set(),
93            CapabilitySetType::CapstypeSound => ts_sound_capability_set(),
94            CapabilitySetType::CapsettypeMultifragmentupdate => ts_multifragment_update_capability_ts(),
95            _ => {
96                return Err(Error::RdpError(RdpError::new(RdpErrorKind::Unknown, &format!("CAPABILITY: Unknown capability {:?}", cap_type))))
97            }
98        };
99        capability.message.read(&mut Cursor::new(cast!(DataType::Slice, capability_set["capabilitySet"])?))?;
100        Ok(capability)
101    }
102}
103
104/// General capability payload
105///
106/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/d705c3b6-a392-4b32-9610-391f6af62323
107///
108/// # Example
109/// ```
110/// #[macro_use]
111/// # extern crate rdp;
112/// # use rdp::model::data::DataType;
113/// # use rdp::model::error::{Error, RdpError, RdpResult, RdpErrorKind};
114/// fn main() {
115///     use rdp::core::capability::{capability_set, ts_general_capability_set, CapabilitySetType};
116///     let capability_set = capability_set(Some(ts_general_capability_set(Some(2))));
117///     assert_eq!(cast!(DataType::U16, capability_set["capabilitySetType"]).unwrap(), CapabilitySetType::CapstypeGeneral as u16)
118/// }
119/// ```
120pub fn capability_set(capability: Option<Capability>) -> Component {
121    let default_capability = capability.unwrap_or(Capability{ cap_type: CapabilitySetType::CapstypeGeneral, message: component![]});
122    component![
123        "capabilitySetType" => U16::LE(default_capability.cap_type as u16),
124        "lengthCapability" => DynOption::new(U16::LE(default_capability.message.length() as u16 + 4), |length| MessageOption::Size("capabilitySet".to_string(), length.inner() as usize - 4)),
125        "capabilitySet" => to_vec(&default_capability.message)
126    ]
127}
128
129#[repr(u16)]
130#[allow(dead_code)]
131enum MajorType {
132    OsmajortypeUnspecified = 0x0000,
133    OsmajortypeWindows = 0x0001,
134    OsmajortypeOs2 = 0x0002,
135    OsmajortypeMacintosh = 0x0003,
136    OsmajortypeUnix = 0x0004,
137    OsmajortypeIos = 0x0005,
138    OsmajortypeOsx = 0x0006,
139    OsmajortypeAndroid = 0x0007
140}
141
142#[allow(dead_code)]
143enum MinorType {
144    OsminortypeUnspecified = 0x0000,
145    OsminortypeWindows31x = 0x0001,
146    OsminortypeWindows95 = 0x0002,
147    OsminortypeWindowsNt = 0x0003,
148    OsminortypeOs2V21 = 0x0004,
149    OsminortypePowerPc = 0x0005,
150    OsminortypeMacintosh = 0x0006,
151    OsminortypeNativeXserver = 0x0007,
152    OsminortypePseudoXserver = 0x0008,
153    OsminortypeWindowsRt = 0x0009
154}
155
156#[repr(u16)]
157pub enum GeneralExtraFlag {
158    FastpathOutputSupported = 0x0001,
159    NoBitmapCompressionHdr = 0x0400,
160    LongCredentialsSupported = 0x0004,
161    AutoreconnectSupported = 0x0008,
162    EncSaltedChecksum = 0x0010
163}
164
165/// General capability
166/// This capability is send by both side
167///
168/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/41dc6845-07dc-4af6-bc14-d8281acd4877
169///
170/// # Example
171/// ```
172/// use rdp::core::capability::{capability_set, ts_general_capability_set};
173/// use rdp::model::data::to_vec;
174/// let capability_set = capability_set(Some(ts_general_capability_set(Some(8))));
175/// assert_eq!(to_vec(&capability_set), [1, 0, 24, 0, 1, 0, 3, 0, 0, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0])
176/// ```
177pub fn ts_general_capability_set(extra_flags: Option<u16>) -> Capability {
178    Capability {
179        cap_type: CapabilitySetType::CapstypeGeneral,
180        message: component![
181            "osMajorType" => U16::LE(MajorType::OsmajortypeWindows as u16),
182            "osMinorType" => U16::LE(MinorType::OsminortypeWindowsNt as u16),
183            "protocolVersion" => Check::new(U16::LE(0x0200)),
184            "pad2octetsA" => U16::LE(0),
185            "generalCompressionTypes" => Check::new(U16::LE(0)),
186            "extraFlags" => U16::LE(extra_flags.unwrap_or(0)),
187            "updateCapabilityFlag" => Check::new(U16::LE(0)),
188            "remoteUnshareFlag" => Check::new(U16::LE(0)),
189            "generalCompressionLevel" => Check::new(U16::LE(0)),
190            "refreshRectSupport" => 0 as u8,
191            "suppressOutputSupport" => 0 as u8
192        ]
193    }
194}
195
196/// Bitmap capability
197/// Here we can set Bit per pixel
198/// Screen Size
199///
200/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/76670547-e35c-4b95-a242-5729a21b83f6
201///
202/// # Example
203/// ```
204/// use rdp::core::capability::{capability_set, ts_bitmap_capability_set};
205/// use rdp::model::data::to_vec;
206/// let capability_set = capability_set(Some(ts_bitmap_capability_set(Some(24), Some(800), Some(600))));
207/// assert_eq!(to_vec(&capability_set), [2, 0, 28, 0, 24, 0, 1, 0, 1, 0, 1, 0, 32, 3, 88, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
208/// ```
209pub fn ts_bitmap_capability_set(preferred_bits_per_pixel: Option<u16>, desktop_width: Option<u16>, desktop_height: Option<u16>) -> Capability {
210    Capability {
211        cap_type: CapabilitySetType::CapstypeBitmap,
212        message: component![
213            "preferredBitsPerPixel" => U16::LE(preferred_bits_per_pixel.unwrap_or(0)),
214            "receive1BitPerPixel" => Check::new(U16::LE(0x0001)),
215            "receive4BitsPerPixel" => Check::new(U16::LE(0x0001)),
216            "receive8BitsPerPixel" => Check::new(U16::LE(0x0001)),
217            "desktopWidth" => U16::LE(desktop_width.unwrap_or(0)),
218            "desktopHeight" => U16::LE(desktop_height.unwrap_or(0)),
219            "pad2octets" => U16::LE(0),
220            "desktopResizeFlag" => U16::LE(0),
221            "bitmapCompressionFlag" => Check::new(U16::LE(0x0001)),
222            "highColorFlags" => Check::new(0 as u8),
223            "drawingFlags" => 0 as u8,
224            "multipleRectangleSupport" => Check::new(U16::LE(0x0001)),
225            "pad2octetsB" => U16::LE(0)
226        ]
227    }
228}
229
230#[repr(u16)]
231#[allow(dead_code)]
232pub enum OrderFlag {
233    NEGOTIATEORDERSUPPORT = 0x0002,
234    ZEROBOUNDSDELTASSUPPORT = 0x0008,
235    COLORINDEXSUPPORT = 0x0020,
236    SOLIDPATTERNBRUSHONLY = 0x0040,
237    OrderflagsExtraFlags = 0x0080
238}
239
240/// Order capability
241/// Some graphical orders options
242///
243/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9f409c29-480c-4751-9665-510b8ffff294
244///
245/// # Example
246/// ```
247/// use rdp::core::capability::{capability_set, ts_order_capability_set};
248/// use rdp::model::data::to_vec;
249/// let capability_set = capability_set(Some(ts_order_capability_set(Some(24))));
250/// assert_eq!(to_vec(&capability_set), vec![3, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 20, 0, 0, 0, 1, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0])
251/// ```
252pub fn ts_order_capability_set(order_flags: Option<u16>) -> Capability {
253    Capability {
254        cap_type: CapabilitySetType::CapstypeOrder,
255        message: component![
256            "terminalDescriptor" => vec![0 as u8; 16],
257            "pad4octetsA" => U32::LE(0),
258            "desktopSaveXGranularity" => U16::LE(1),
259            "desktopSaveYGranularity" => U16::LE(20),
260            "pad2octetsA" => U16::LE(0),
261            "maximumOrderLevel" => U16::LE(1),
262            "numberFonts" => U16::LE(0),
263            "orderFlags" => U16::LE(order_flags.unwrap_or(OrderFlag::NEGOTIATEORDERSUPPORT as u16)),
264            "orderSupport" => vec![0 as u8; 32],
265            "textFlags" => U16::LE(0),
266            "orderSupportExFlags" => U16::LE(0),
267            "pad4octetsB" => U32::LE(0),
268            "desktopSaveSize" => U32::LE(480*480),
269            "pad2octetsC" => U16::LE(0),
270            "pad2octetsD" => U16::LE(0),
271            "textANSICodePage" => U16::LE(0),
272            "pad2octetsE" => U16::LE(0)
273        ]
274    }
275}
276
277/// Bitmap cache is use as an optimization
278///
279/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/101d40a7-56c0-40e1-bcb9-1475ff63cb9d
280///
281/// # Example
282/// ```
283/// use rdp::core::capability::{capability_set, ts_bitmap_cache_capability_set};
284/// use rdp::model::data::to_vec;
285/// let capability_set = capability_set(Some(ts_bitmap_cache_capability_set()));
286/// assert_eq!(to_vec(&capability_set), vec![4, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
287/// ```
288pub fn ts_bitmap_cache_capability_set() -> Capability {
289    Capability {
290        cap_type: CapabilitySetType::CapstypeBitmapcache,
291        message: component![
292            "pad1" => U32::LE(0),
293            "pad2" => U32::LE(0),
294            "pad3" => U32::LE(0),
295            "pad4" => U32::LE(0),
296            "pad5" => U32::LE(0),
297            "pad6" => U32::LE(0),
298            "cache0Entries" => U16::LE(0),
299            "cache0MaximumCellSize" => U16::LE(0),
300            "cache1Entries" => U16::LE(0),
301            "cache1MaximumCellSize" => U16::LE(0),
302            "cache2Entries" => U16::LE(0),
303            "cache2MaximumCellSize" => U16::LE(0)
304        ]
305    }
306}
307
308/// Pointer capability
309/// send by both client and server
310///
311/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/925e2c05-c13f-44b1-aa20-23082051fef9
312///
313/// # Example
314/// ```
315/// use rdp::core::capability::{capability_set, ts_pointer_capability_set};
316/// use rdp::model::data::to_vec;
317/// let capability_set = capability_set(Some(ts_pointer_capability_set()));
318/// assert_eq!(to_vec(&capability_set), vec![8, 0, 8, 0, 0, 0, 20, 0])
319/// ```
320pub fn ts_pointer_capability_set() -> Capability {
321    Capability {
322        cap_type: CapabilitySetType::CapstypePointer,
323        message: component![
324            "colorPointerFlag" => U16::LE(0),
325            "colorPointerCacheSize" => U16::LE(20)
326        ]
327    }
328}
329
330#[repr(u16)]
331pub enum InputFlags {
332    /// Raw Keyboard scancode
333    /// This is the most convenient way to send keyboard event
334    /// This fearture is supported by rdp-rs
335    InputFlagScancodes = 0x0001,
336    /// This is the extended mouse event
337    /// with more button code
338    /// This feature is supported by rdp-rs
339    InputFlagMousex = 0x0004,
340    /// The capability to send fastpath input
341    /// This feature is NOT supported by rdp-rs
342    InputFlagFastpathInput = 0x0008,
343    /// In order to send keyboard scancode
344    /// We can send directly UNICODE code of char
345    /// Usefull if we want to send script
346    /// This feature is supported by rdp-rs
347    InputFlagUnicode = 0x0010,
348    InputFlagFastpathInput2 = 0x0020,
349    InputFlagUnused1 = 0x0040,
350    InputFlagUnused2 = 0x0080,
351    /// Support of the mouse wheel
352    /// This feature is supported by rdp-rs
353    TsInputFlagMouseHwheel = 0x0100
354}
355
356/// Send input capability
357///
358/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/b3bc76ae-9ee5-454f-b197-ede845ca69cc
359///
360/// # Example
361/// ```
362/// use rdp::core::capability::{capability_set, ts_input_capability_set, InputFlags};
363/// use rdp::model::data::to_vec;
364/// use rdp::core::gcc::KeyboardLayout;
365/// let capability_set = capability_set(Some(ts_input_capability_set(Some(InputFlags::InputFlagScancodes as u16), Some(KeyboardLayout::French))));
366/// assert_eq!(to_vec(&capability_set), vec![13, 0, 88, 0, 1, 0, 0, 0, 12, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
367/// ```
368pub fn ts_input_capability_set(input_flags: Option<u16>, keyboard_layout: Option<KeyboardLayout>) -> Capability {
369    Capability {
370        cap_type: CapabilitySetType::CapstypeInput,
371        message: component![
372            "inputFlags" => U16::LE(input_flags.unwrap_or(0)),
373            "pad2octetsA" => U16::LE(0),
374            "keyboardLayout" => U32::LE(keyboard_layout.unwrap_or(KeyboardLayout::French) as u32),
375            "keyboardType" => U32::LE(KeyboardType::Ibm101102Keys as u32),
376            "keyboardSubType" => U32::LE(0),
377            "keyboardFunctionKey" => U32::LE(12),
378            "imeFileName" => vec![0 as u8; 64]
379        ]
380    }
381}
382
383/// Brush capability
384/// send from client to server
385///
386/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/8b6a830f-3dde-4a84-9250-21ffa7d2e342
387/// # Example
388/// ```
389/// use rdp::core::capability::{capability_set, ts_brush_capability_set};
390/// use rdp::model::data::to_vec;
391/// use rdp::core::gcc::KeyboardLayout;
392/// let capability_set = capability_set(Some(ts_brush_capability_set()));
393/// assert_eq!(to_vec(&capability_set), vec![15, 0, 8, 0, 0, 0, 0, 0])
394/// ```
395pub fn ts_brush_capability_set() -> Capability {
396    Capability {
397        cap_type: CapabilitySetType::CapstypeBrush,
398        message: component![
399            "brushSupportLevel" => U32::LE(0)
400        ]
401    }
402}
403
404/// Glyph cache entry
405///
406/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/cae26830-263c-4c1e-97c2-b561faded3d9
407fn cache_entry() -> Component {
408    component![
409        "cacheEntries" => U16::LE(0),
410        "cacheMaximumCellSize" => U16::LE(0)
411    ]
412}
413
414
415/// Glyph capability set
416/// send from client to server
417///
418/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/8e292483-9b0f-43b9-be14-dc6cd07e1615
419///
420/// # Example
421/// ```
422/// use rdp::core::capability::{capability_set, ts_glyph_capability_set};
423/// use rdp::model::data::to_vec;
424/// use rdp::core::gcc::KeyboardLayout;
425/// let capability_set = capability_set(Some(ts_glyph_capability_set()));
426/// assert_eq!(to_vec(&capability_set), vec![16, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
427/// ```
428pub fn ts_glyph_capability_set() -> Capability {
429    Capability {
430        cap_type: CapabilitySetType::CapstypeGlyphcache,
431        message: component![
432            "glyphCache" => trame![
433                cache_entry(), cache_entry(), cache_entry(), cache_entry(), cache_entry(),
434                cache_entry(), cache_entry(), cache_entry(), cache_entry(), cache_entry()
435            ],
436            "fragCache" => U32::LE(0),
437            "glyphSupportLevel" => U16::LE(0),
438            "pad2octets" => U16::LE(0)
439        ]
440    }
441}
442
443/// Offscreen capability
444/// send from client to server
445///
446/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/412fa921-2faa-4f1b-ab5f-242cdabc04f9
447///
448/// # Example
449/// ```
450/// use rdp::core::capability::{capability_set, ts_offscreen_capability_set};
451/// use rdp::model::data::to_vec;
452/// use rdp::core::gcc::KeyboardLayout;
453/// let capability_set = capability_set(Some(ts_offscreen_capability_set()));
454/// assert_eq!(to_vec(&capability_set), vec![17, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0])
455/// ```
456pub fn ts_offscreen_capability_set() -> Capability {
457    Capability {
458        cap_type: CapabilitySetType::CapstypeOffscreencache,
459        message: component![
460            "offscreenSupportLevel" => U32::LE(0),
461            "offscreenCacheSize" => U16::LE(0),
462            "offscreenCacheEntries" => U16::LE(0)
463        ]
464    }
465}
466
467/// Virtual channel capability
468/// send by both side (client server)
469///
470/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a8593178-80c0-4b80-876c-cb77e62cecfc
471///
472/// # Example
473/// ```
474/// use rdp::core::capability::{capability_set, ts_virtualchannel_capability_set};
475/// use rdp::model::data::to_vec;
476/// use rdp::core::gcc::KeyboardLayout;
477/// let capability_set = capability_set(Some(ts_virtualchannel_capability_set()));
478/// assert_eq!(to_vec(&capability_set), vec![20, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0])
479/// ```
480pub fn ts_virtualchannel_capability_set() -> Capability {
481    Capability {
482        cap_type: CapabilitySetType::CapstypeVirtualchannel,
483        message: component![
484            "flags" => U32::LE(0),
485            "VCChunkSize" => Some(U32::LE(0))
486        ]
487    }
488}
489
490/// Sound capability
491/// send from client server
492///
493/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/fadb6a2c-18fa-4fa7-a155-e970d9b1ac59
494///
495/// # Example
496/// ```
497/// use rdp::core::capability::{capability_set, ts_sound_capability_set};
498/// use rdp::model::data::to_vec;
499/// use rdp::core::gcc::KeyboardLayout;
500/// let capability_set = capability_set(Some(ts_sound_capability_set()));
501/// assert_eq!(to_vec(&capability_set), vec![12, 0, 8, 0, 0, 0, 0, 0])
502/// ```
503pub fn ts_sound_capability_set() -> Capability {
504    Capability {
505        cap_type: CapabilitySetType::CapstypeSound,
506        message: component![
507            "soundFlags" => U16::LE(0),
508            "pad2octetsA" => U16::LE(0)
509        ]
510    }
511}
512
513/// Multi fragment capability
514/// send by both side (client, server)
515///
516/// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/01717954-716a-424d-af35-28fb2b86df89
517///
518/// /// # Example
519/// ```
520/// use rdp::core::capability::{capability_set, ts_multifragment_update_capability_ts};
521/// use rdp::model::data::to_vec;
522/// use rdp::core::gcc::KeyboardLayout;
523/// let capability_set = capability_set(Some(ts_multifragment_update_capability_ts()));
524/// assert_eq!(to_vec(&capability_set), vec![26, 0, 8, 0, 0, 0, 0, 0])
525/// ```
526pub fn ts_multifragment_update_capability_ts() -> Capability {
527    Capability {
528        cap_type: CapabilitySetType::CapsettypeMultifragmentupdate,
529        message: component![
530            "MaxRequestSize" => U32::LE(0)
531        ]
532    }
533}