1- // QUESTION: consider auto-generating this file based on a reference file?
2- // https://gist.github.com/awakecoding/838c7fe2ed3a6208e3ca5d8af25363f6
1+ mod target_addr ;
2+ pub use target_addr :: { ParseTargetAddrError , TargetAddr , TargetHost } ;
33
44use ironrdp_propertyset:: PropertySet ;
55
6+ /// Error returned when the `server port` property value is outside the valid port range (1–65535).
7+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
8+ pub struct InvalidServerPort ;
9+
10+ impl core:: fmt:: Display for InvalidServerPort {
11+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
12+ f. write_str ( "server port value is out of the valid port range (1-65535)" )
13+ }
14+ }
15+
16+ impl core:: error:: Error for InvalidServerPort { }
17+
18+ /// Error returned when a desktop dimension or scale factor property value is out of range.
19+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
20+ pub struct InvalidDesktopSize ;
21+
22+ impl core:: fmt:: Display for InvalidDesktopSize {
23+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
24+ f. write_str ( "desktop size property value is out of range" )
25+ }
26+ }
27+
28+ impl core:: error:: Error for InvalidDesktopSize { }
29+
30+ /// Controls whether and how an RD Gateway server is used.
31+ ///
32+ /// Corresponds to the `gatewayusagemethod` `.rdp` property.
33+ /// See also: <https://learn.microsoft.com/en-us/windows/win32/termserv/rdp-file-settings>
34+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
35+ pub enum GatewayUsageMethod {
36+ /// 0: Do not use an RD Gateway server.
37+ Direct ,
38+ /// 1: Always use an RD Gateway server.
39+ UseAlways ,
40+ /// 2: Use an RD Gateway server, bypass for local addresses.
41+ UseBypassLocal ,
42+ /// 3: Use an RD Gateway server, never bypass.
43+ UseNeverBypass ,
44+ /// 4: Automatically detect RD Gateway settings (client-side heuristic; no explicit gateway configured).
45+ Automatic ,
46+ }
47+
48+ impl GatewayUsageMethod {
49+ /// Returns `true` when the file explicitly requires routing through a gateway server.
50+ pub fn is_gateway_required ( self ) -> bool {
51+ matches ! ( self , Self :: UseAlways | Self :: UseBypassLocal | Self :: UseNeverBypass )
52+ }
53+
54+ /// Returns the raw integer value for writing to a `.rdp` property set.
55+ pub fn as_i64 ( self ) -> i64 {
56+ match self {
57+ Self :: Direct => 0 ,
58+ Self :: UseAlways => 1 ,
59+ Self :: UseBypassLocal => 2 ,
60+ Self :: UseNeverBypass => 3 ,
61+ Self :: Automatic => 4 ,
62+ }
63+ }
64+ }
65+
66+ impl TryFrom < i64 > for GatewayUsageMethod {
67+ type Error = UnknownGatewayUsageMethod ;
68+
69+ fn try_from ( value : i64 ) -> Result < Self , Self :: Error > {
70+ match value {
71+ 0 => Ok ( Self :: Direct ) ,
72+ 1 => Ok ( Self :: UseAlways ) ,
73+ 2 => Ok ( Self :: UseBypassLocal ) ,
74+ 3 => Ok ( Self :: UseNeverBypass ) ,
75+ 4 => Ok ( Self :: Automatic ) ,
76+ _ => Err ( UnknownGatewayUsageMethod ( value) ) ,
77+ }
78+ }
79+ }
80+
81+ /// Error returned when a `gatewayusagemethod` value is not a recognized variant.
82+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
83+ pub struct UnknownGatewayUsageMethod ( pub i64 ) ;
84+
85+ impl core:: fmt:: Display for UnknownGatewayUsageMethod {
86+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
87+ write ! ( f, "unknown gatewayusagemethod value: {}" , self . 0 )
88+ }
89+ }
90+
91+ impl core:: error:: Error for UnknownGatewayUsageMethod { }
92+
93+ /// Controls which credentials are used to authenticate to the RD Gateway.
94+ ///
95+ /// Corresponds to the `gatewaycredentialssource` `.rdp` property.
96+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
97+ pub enum GatewayCredentialsSource {
98+ /// 0: Use the same credentials as the RDP server (pass-through / NTLM).
99+ UseServerCredentials ,
100+ /// 1: Use the gateway-specific user credentials.
101+ UseUserCredentials ,
102+ /// 2: Use credentials stored in a profile.
103+ UseProfile ,
104+ /// 3: Prompt the user for gateway credentials.
105+ Prompt ,
106+ /// 4: Use a smart card.
107+ SmartCard ,
108+ /// 5: Use the logged-on user's credentials.
109+ UseLogonCredentials ,
110+ }
111+
112+ impl TryFrom < i64 > for GatewayCredentialsSource {
113+ type Error = UnknownGatewayCredentialsSource ;
114+
115+ fn try_from ( value : i64 ) -> Result < Self , Self :: Error > {
116+ match value {
117+ 0 => Ok ( Self :: UseServerCredentials ) ,
118+ 1 => Ok ( Self :: UseUserCredentials ) ,
119+ 2 => Ok ( Self :: UseProfile ) ,
120+ 3 => Ok ( Self :: Prompt ) ,
121+ 4 => Ok ( Self :: SmartCard ) ,
122+ 5 => Ok ( Self :: UseLogonCredentials ) ,
123+ _ => Err ( UnknownGatewayCredentialsSource ( value) ) ,
124+ }
125+ }
126+ }
127+
128+ /// Error returned when a `gatewaycredentialssource` value is not a recognized variant.
129+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
130+ pub struct UnknownGatewayCredentialsSource ( pub i64 ) ;
131+
132+ impl core:: fmt:: Display for UnknownGatewayCredentialsSource {
133+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
134+ write ! ( f, "unknown gatewaycredentialssource value: {}" , self . 0 )
135+ }
136+ }
137+
138+ impl core:: error:: Error for UnknownGatewayCredentialsSource { }
139+
140+ /// Controls where audio is played during a remote session.
141+ ///
142+ /// Corresponds to the `audiomode` `.rdp` property.
143+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
144+ pub enum AudioMode {
145+ /// 0: Redirect audio to the local (client) machine.
146+ RedirectToClient ,
147+ /// 1: Play audio on the remote computer.
148+ PlayOnServer ,
149+ /// 2: Do not play audio.
150+ Disabled ,
151+ }
152+
153+ impl TryFrom < i64 > for AudioMode {
154+ type Error = UnknownAudioMode ;
155+
156+ fn try_from ( value : i64 ) -> Result < Self , Self :: Error > {
157+ match value {
158+ 0 => Ok ( Self :: RedirectToClient ) ,
159+ 1 => Ok ( Self :: PlayOnServer ) ,
160+ 2 => Ok ( Self :: Disabled ) ,
161+ _ => Err ( UnknownAudioMode ( value) ) ,
162+ }
163+ }
164+ }
165+
166+ /// Error returned when an `audiomode` value is not a recognized variant.
167+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
168+ pub struct UnknownAudioMode ( pub i64 ) ;
169+
170+ impl core:: fmt:: Display for UnknownAudioMode {
171+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
172+ write ! ( f, "unknown audiomode value: {}" , self . 0 )
173+ }
174+ }
175+
176+ impl core:: error:: Error for UnknownAudioMode { }
177+
6178pub trait PropertySetExt {
7- fn full_address ( & self ) -> Option < & str > ;
179+ fn full_address ( & self ) -> Result < Option < TargetAddr > , ParseTargetAddrError > ;
180+
181+ fn server_port ( & self ) -> Result < Option < u16 > , InvalidServerPort > ;
182+
183+ fn alternate_full_address ( & self ) -> Result < Option < TargetAddr > , ParseTargetAddrError > ;
8184
9- fn server_port ( & self ) -> Option < i64 > ;
185+ fn domain ( & self ) -> Option < & str > ;
10186
11- fn alternate_full_address ( & self ) -> Option < & str > ;
187+ fn enable_credssp_support ( & self ) -> Option < bool > ;
188+
189+ fn compression ( & self ) -> Option < bool > ;
12190
13191 fn gateway_hostname ( & self ) -> Option < & str > ;
14192
193+ fn gateway_usage_method ( & self ) -> Result < Option < GatewayUsageMethod > , UnknownGatewayUsageMethod > ;
194+
195+ fn gateway_credentials_source ( & self ) -> Result < Option < GatewayCredentialsSource > , UnknownGatewayCredentialsSource > ;
196+
197+ fn gateway_username ( & self ) -> Option < & str > ;
198+
199+ fn gateway_password ( & self ) -> Option < & str > ;
200+
201+ fn desktop_width ( & self ) -> Result < Option < u16 > , InvalidDesktopSize > ;
202+
203+ fn desktop_height ( & self ) -> Result < Option < u16 > , InvalidDesktopSize > ;
204+
205+ fn desktop_scale_factor ( & self ) -> Result < Option < u32 > , InvalidDesktopSize > ;
206+
207+ fn alternate_shell ( & self ) -> Option < & str > ;
208+
209+ fn shell_working_directory ( & self ) -> Option < & str > ;
210+
211+ fn redirect_clipboard ( & self ) -> Option < bool > ;
212+
213+ fn audio_mode ( & self ) -> Result < Option < AudioMode > , UnknownAudioMode > ;
214+
15215 fn remote_application_name ( & self ) -> Option < & str > ;
16216
17217 fn remote_application_program ( & self ) -> Option < & str > ;
18218
19219 fn kdc_proxy_url ( & self ) -> Option < & str > ;
20220
221+ fn kdc_proxy_name ( & self ) -> Option < & str > ;
222+
21223 fn username ( & self ) -> Option < & str > ;
22224
23225 /// Target RDP server password - use for testing only
24226 fn clear_text_password ( & self ) -> Option < & str > ;
25227}
26228
27229impl PropertySetExt for PropertySet {
28- fn full_address ( & self ) -> Option < & str > {
29- self . get :: < & str > ( "full address" )
230+ fn full_address ( & self ) -> Result < Option < TargetAddr > , ParseTargetAddrError > {
231+ self . get :: < & str > ( "full address" ) . map ( |s| s . parse ( ) ) . transpose ( )
30232 }
31233
32- fn server_port ( & self ) -> Option < i64 > {
234+ fn server_port ( & self ) -> Result < Option < u16 > , InvalidServerPort > {
33235 self . get :: < i64 > ( "server port" )
236+ . map ( |p| u16:: try_from ( p) . ok ( ) . filter ( |& p| p != 0 ) . ok_or ( InvalidServerPort ) )
237+ . transpose ( )
34238 }
35239
36- fn alternate_full_address ( & self ) -> Option < & str > {
240+ fn alternate_full_address ( & self ) -> Result < Option < TargetAddr > , ParseTargetAddrError > {
37241 self . get :: < & str > ( "alternate full address" )
242+ . map ( |s| s. parse ( ) )
243+ . transpose ( )
244+ }
245+
246+ fn domain ( & self ) -> Option < & str > {
247+ self . get :: < & str > ( "domain" )
248+ }
249+
250+ fn enable_credssp_support ( & self ) -> Option < bool > {
251+ self . get :: < bool > ( "enablecredsspsupport" )
252+ }
253+
254+ fn compression ( & self ) -> Option < bool > {
255+ self . get :: < bool > ( "compression" )
38256 }
39257
40258 fn gateway_hostname ( & self ) -> Option < & str > {
41259 self . get :: < & str > ( "gatewayhostname" )
42260 }
43261
262+ fn gateway_usage_method ( & self ) -> Result < Option < GatewayUsageMethod > , UnknownGatewayUsageMethod > {
263+ self . get :: < i64 > ( "gatewayusagemethod" )
264+ . map ( GatewayUsageMethod :: try_from)
265+ . transpose ( )
266+ }
267+
268+ fn gateway_credentials_source ( & self ) -> Result < Option < GatewayCredentialsSource > , UnknownGatewayCredentialsSource > {
269+ self . get :: < i64 > ( "gatewaycredentialssource" )
270+ . map ( GatewayCredentialsSource :: try_from)
271+ . transpose ( )
272+ }
273+
274+ fn gateway_username ( & self ) -> Option < & str > {
275+ self . get :: < & str > ( "gatewayusername" )
276+ }
277+
278+ fn gateway_password ( & self ) -> Option < & str > {
279+ self . get :: < & str > ( "GatewayPassword" )
280+ . or_else ( || self . get :: < & str > ( "gatewaypassword" ) )
281+ }
282+
283+ fn desktop_width ( & self ) -> Result < Option < u16 > , InvalidDesktopSize > {
284+ self . get :: < i64 > ( "desktopwidth" )
285+ . map ( |v| u16:: try_from ( v) . map_err ( |_| InvalidDesktopSize ) )
286+ . transpose ( )
287+ }
288+
289+ fn desktop_height ( & self ) -> Result < Option < u16 > , InvalidDesktopSize > {
290+ self . get :: < i64 > ( "desktopheight" )
291+ . map ( |v| u16:: try_from ( v) . map_err ( |_| InvalidDesktopSize ) )
292+ . transpose ( )
293+ }
294+
295+ fn desktop_scale_factor ( & self ) -> Result < Option < u32 > , InvalidDesktopSize > {
296+ self . get :: < i64 > ( "desktopscalefactor" )
297+ . map ( |v| u32:: try_from ( v) . map_err ( |_| InvalidDesktopSize ) )
298+ . transpose ( )
299+ }
300+
301+ fn alternate_shell ( & self ) -> Option < & str > {
302+ self . get :: < & str > ( "alternate shell" )
303+ }
304+
305+ fn shell_working_directory ( & self ) -> Option < & str > {
306+ self . get :: < & str > ( "shell working directory" )
307+ }
308+
309+ fn redirect_clipboard ( & self ) -> Option < bool > {
310+ self . get :: < bool > ( "redirectclipboard" )
311+ }
312+
313+ fn audio_mode ( & self ) -> Result < Option < AudioMode > , UnknownAudioMode > {
314+ self . get :: < i64 > ( "audiomode" ) . map ( AudioMode :: try_from) . transpose ( )
315+ }
316+
44317 fn remote_application_name ( & self ) -> Option < & str > {
45318 self . get :: < & str > ( "remoteapplicationname" )
46319 }
@@ -51,6 +324,11 @@ impl PropertySetExt for PropertySet {
51324
52325 fn kdc_proxy_url ( & self ) -> Option < & str > {
53326 self . get :: < & str > ( "kdcproxyurl" )
327+ . or_else ( || self . get :: < & str > ( "KDCProxyURL" ) )
328+ }
329+
330+ fn kdc_proxy_name ( & self ) -> Option < & str > {
331+ self . get :: < & str > ( "kdcproxyname" )
54332 }
55333
56334 fn username ( & self ) -> Option < & str > {
0 commit comments