1use crate::{
2 error::*,
3 serialization::{Decode, Encode},
4};
5use core::{convert::TryFrom, fmt};
6use num_derive::{FromPrimitive, ToPrimitive};
7use std::io::{Cursor, Write};
8
9#[derive(Debug, Clone)]
12pub struct NowStatusBuilder<CodeType> {
13 severity: SeverityLevel,
14 status_type: StatusType,
15 code: CodeType,
16}
17
18impl<CodeType> NowStatusBuilder<CodeType>
19where
20 CodeType: num::ToPrimitive,
21{
22 pub fn severity<V: Into<SeverityLevel>>(self, value: V) -> Self {
23 Self {
24 severity: value.into(),
25 ..self
26 }
27 }
28
29 pub fn status_type<V: Into<StatusType>>(self, value: V) -> Self {
30 Self {
31 status_type: value.into(),
32 ..self
33 }
34 }
35
36 pub fn build(self) -> NowStatus<CodeType> {
37 let repr = ((self.severity as u32) << 30)
38 + ((self.status_type as u32) << 16)
39 + num::ToPrimitive::to_u32(&self.code).unwrap(); NowStatus {
42 repr,
43 severity: self.severity,
44 status_type: self.status_type,
45 code: self.code,
46 }
47 }
48}
49
50#[derive(Debug, PartialEq, Clone)]
51pub struct NowStatus<CodeType> {
52 repr: u32,
53
54 severity: SeverityLevel,
56 status_type: StatusType,
57 code: CodeType,
58}
59
60impl<CodeType> Encode for NowStatus<CodeType> {
61 fn encoded_len(&self) -> usize {
62 std::mem::size_of::<u32>()
63 }
64
65 fn encode_into<W: Write>(&self, writer: &mut W) -> Result<()> {
66 self.repr.encode_into(writer)
67 }
68}
69
70impl<CodeType> Decode<'_> for NowStatus<CodeType>
71where
72 CodeType: num::FromPrimitive,
73{
74 fn decode_from(cursor: &mut Cursor<&[u8]>) -> Result<Self> {
75 let repr = u32::decode_from(cursor)?;
76 Self::from_u32(repr)
77 }
78}
79
80impl<CodeType> TryFrom<u32> for NowStatus<CodeType>
81where
82 CodeType: num::FromPrimitive,
83{
84 type Error = ProtoError;
85
86 fn try_from(repr: u32) -> Result<Self> {
87 Ok(NowStatus {
88 repr,
89 severity: num::FromPrimitive::from_u32(repr >> 30)
90 .chain(ProtoErrorKind::Decoding(stringify!(NowStatus)))
91 .or_desc("couldn't parse severity")?,
92 status_type: num::FromPrimitive::from_u32((repr & 0x00FF_0000) >> 16)
93 .chain(ProtoErrorKind::Decoding(stringify!(NowStatus)))
94 .or_desc("couldn't parse status type")?,
95 code: num::FromPrimitive::from_u32(repr & 0x0000_FFFF)
96 .chain(ProtoErrorKind::Decoding(stringify!(NowStatus)))
97 .or_desc("couldn't parse status code")?,
98 })
99 }
100}
101
102impl<CodeType> Into<u32> for NowStatus<CodeType> {
103 fn into(self) -> u32 {
104 self.repr
105 }
106}
107
108impl<CodeType> PartialEq<u32> for NowStatus<CodeType> {
109 fn eq(&self, other: &u32) -> bool {
110 self.repr == *other
111 }
112}
113
114impl<CodeType> Default for NowStatus<CodeType>
115where
116 CodeType: num::FromPrimitive + num::ToPrimitive,
117{
118 fn default() -> Self {
119 NowStatus::builder(<CodeType as num::FromPrimitive>::from_u8(0).unwrap()).build()
121 }
122}
123
124impl<CodeType> NowStatus<CodeType>
125where
126 CodeType: num::FromPrimitive,
127{
128 pub fn from_u32(repr: u32) -> Result<Self> {
129 Self::try_from(repr)
130 }
131}
132
133impl<CodeType> NowStatus<CodeType> {
134 pub fn builder<V: Into<CodeType>>(code: V) -> NowStatusBuilder<CodeType> {
135 NowStatusBuilder {
136 severity: SeverityLevel::Info,
137 status_type: StatusType::None,
138 code: code.into(),
139 }
140 }
141}
142
143impl<CodeType> NowStatus<CodeType>
144where
145 CodeType: Copy,
146{
147 pub fn severity(&self) -> SeverityLevel {
148 self.severity
149 }
150
151 pub fn status_type(&self) -> StatusType {
152 self.status_type
153 }
154
155 pub fn code(&self) -> CodeType {
156 self.code
157 }
158
159 pub fn as_u32(&self) -> u32 {
160 self.repr
161 }
162}
163
164impl<CodeType> fmt::Display for NowStatus<CodeType>
165where
166 CodeType: fmt::Display,
167{
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 write!(f, "{} {}: {}", self.status_type, self.severity, self.code)
170 }
171}
172
173#[derive(Encode, Decode, FromPrimitive, Debug, PartialEq, Clone, Copy)]
174#[repr(u8)]
175pub enum SeverityLevel {
176 Info = 0,
177 Warn = 1,
178 Error = 2,
179 Fatal = 3,
180}
181
182impl fmt::Display for SeverityLevel {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 write!(f, "{:?}", self)
185 }
186}
187
188#[derive(Encode, Decode, FromPrimitive, Debug, PartialEq, Clone, Copy)]
189#[repr(u8)]
190pub enum StatusType {
191 None = 0,
192 Disconnect = 1,
193 Connect = 2,
194 Security = 3,
195 Handshake = 21,
196 Negotiate = 22,
197 Auth = 23,
198 Associate = 24,
199 Capabilities = 25,
200 Channel = 26,
201 Clipboard = 0x81,
202 FileTransfer = 0x82,
203 Exec = 0x83,
204}
205
206impl fmt::Display for StatusType {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 write!(f, "{:?}", self)
209 }
210}
211
212#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
215#[repr(u16)]
216enum StatusCode {
217 Success = 0x0000,
218 Failure = 0xFFFF,
219}
220
221#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
224#[repr(u16)]
225pub enum DisconnectStatusCode {
226 Success = StatusCode::Success as u16,
227 Failure = StatusCode::Failure as u16,
228 ByLocalUser = 1,
229 ByRemoteUser = 2,
230 ByLocalSystem = 3,
231 ByRemoteSystem = 4,
232 SystemShutdown = 5,
233 SystemReboot = 6,
234 LocalLogoff = 7,
235 RemoteLogoff = 8,
236 ByOtherConnection = 9,
237 LogonTimeout = 10,
238 LogonCancelled = 11,
239 IdleTimeout = 12,
240 AlreadyActive = 13,
241 LicenseRequired = 14,
242}
243
244impl fmt::Display for DisconnectStatusCode {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 match self {
247 Self::Success => write!(f, "disconnected with success"),
248 Self::Failure => write!(f, "disconnection with unknown failure"),
249 Self::ByLocalUser => write!(f, "disconnected by local user."),
250 Self::ByRemoteUser => write!(f, "disconnected by remote user."),
251 Self::ByLocalSystem => write!(f, "disconnected by local system."),
252 Self::ByRemoteSystem => write!(f, "disconnected by remote system."),
253 Self::SystemShutdown => write!(f, "disconnected because of system shutdown."),
254 Self::SystemReboot => write!(f, "disconnected because of system reboot."),
255 Self::LocalLogoff => write!(f, "disconnected because of local logoff."),
256 Self::RemoteLogoff => write!(f, "disconnected because of remote logoff."),
257 Self::ByOtherConnection => write!(f, "disconnected by another connexion."),
258 Self::LogonTimeout => write!(f, "disconnected because of logon timeout."),
259 Self::LogonCancelled => write!(f, "disconnected because the logon was canceled."),
260 Self::IdleTimeout => write!(f, "disconnected because of idle timeout."),
261 Self::AlreadyActive => write!(f, "disconnected because another connection is already active."),
262 Self::LicenseRequired => write!(f, "disconnected because a license is required."),
263 }
264 }
265}
266
267#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
270#[repr(u16)]
271pub enum ConnectStatusCode {
272 Success = StatusCode::Success as u16,
273 Failure = StatusCode::Failure as u16,
274 Unresolved = 1,
275 Unreachable = 2,
276 Refused = 3,
277 Loopback = 4,
278 Concurrent = 5,
279 Unauthorized = 6,
280}
281
282impl fmt::Display for ConnectStatusCode {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 match self {
285 Self::Success => write!(f, "connection succeeded"),
286 Self::Failure => write!(f, "connection failed"),
287 Self::Unresolved => write!(f, "connection unresolved"),
288 Self::Unreachable => write!(f, "sharer unreachable"),
289 Self::Refused => write!(f, "sharer refused connection"),
290 Self::Loopback => write!(f, "connection loopback"),
291 Self::Concurrent => write!(f, "concurrent connection"),
292 Self::Unauthorized => write!(f, "unauthorized connection"),
293 }
294 }
295}
296
297#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
300#[repr(u16)]
301pub enum SecurityStatusCode {
302 Success = StatusCode::Success as u16,
303 Failure = StatusCode::Failure as u16,
304 TLSHandshake = 1,
305 TLSClientCert = 2,
306 TLSServerCert = 3,
307}
308
309impl fmt::Display for SecurityStatusCode {
310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311 match self {
312 Self::Success => write!(f, "success"),
313 Self::Failure => write!(f, "unknown failure"),
314 Self::TLSHandshake => write!(f, "TLS failed"),
315 Self::TLSClientCert => write!(f, "bad client TLS certificate"),
316 Self::TLSServerCert => write!(f, "bad server TLS certificate"),
317 }
318 }
319}
320
321#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
324#[repr(u16)]
325pub enum HandshakeStatusCode {
326 Success = StatusCode::Success as u16,
327 Failure = StatusCode::Failure as u16,
328 Incompatible = 1,
329}
330
331impl fmt::Display for HandshakeStatusCode {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 match self {
334 Self::Success => write!(f, "handshake succeeded"),
335 Self::Failure => write!(f, "handshaked failed"),
336 Self::Incompatible => write!(f, "version is incompatible"),
337 }
338 }
339}
340
341#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
344#[repr(u16)]
345pub enum NegotiateStatusCode {
346 Success = StatusCode::Success as u16,
347 Failure = StatusCode::Failure as u16,
348}
349
350impl fmt::Display for NegotiateStatusCode {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 match self {
353 Self::Success => write!(f, "negotiation succeeded"),
354 Self::Failure => write!(f, "negotiation failed"),
355 }
356 }
357}
358
359#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
362#[repr(u16)]
363pub enum AuthStatusCode {
364 Success = StatusCode::Success as u16,
365 Failure = StatusCode::Failure as u16,
366 Timeout = 1,
367 Cancelled = 2,
368 AccountDisabled = 3,
369 AccountExpired = 4,
370 AccountRestriction = 5,
371 InvalidLogonHours = 6,
372 InvalidWorkstation = 7,
373 PasswordExpired = 8,
374 PasswordMustChange = 9,
375}
376
377impl fmt::Display for AuthStatusCode {
378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379 match self {
380 Self::Success => write!(f, "authentication succeeded"),
381 Self::Failure => write!(f, "authentication failed"),
382 Self::Timeout => write!(f, "timed out"),
383 Self::Cancelled => write!(f, "cancelled"),
384 Self::AccountDisabled => write!(f, "account disabled"),
385 Self::AccountExpired => write!(f, "account expired"),
386 Self::AccountRestriction => write!(f, "account restricted"),
387 Self::InvalidLogonHours => write!(f, "invalid logon hours"),
388 Self::InvalidWorkstation => write!(f, "invalid workstation"),
389 Self::PasswordExpired => write!(f, "password expired"),
390 Self::PasswordMustChange => write!(f, "password must change"),
391 }
392 }
393}
394
395#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
398#[repr(u16)]
399pub enum AssociateStatusCode {
400 Success = StatusCode::Success as u16,
401 Failure = StatusCode::Failure as u16,
402}
403
404impl fmt::Display for AssociateStatusCode {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 match self {
407 Self::Success => write!(f, "association succeeded"),
408 Self::Failure => write!(f, "association failed"),
409 }
410 }
411}
412
413#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
416#[repr(u16)]
417pub enum CapabilitiesStatusCode {
418 Success = StatusCode::Success as u16,
419 Failure = StatusCode::Failure as u16,
420}
421
422impl fmt::Display for CapabilitiesStatusCode {
423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424 match self {
425 Self::Failure => write!(f, "capabilities negotiation failed"),
426 Self::Success => write!(f, "capabilities negotiation succeeded"),
427 }
428 }
429}
430
431#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
434#[repr(u16)]
435pub enum ChannelStatusCode {
436 Success = StatusCode::Success as u16,
437 Failure = StatusCode::Failure as u16,
438}
439
440impl fmt::Display for ChannelStatusCode {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 match self {
443 Self::Success => write!(f, "success"),
444 Self::Failure => write!(f, "failure"),
445 }
446 }
447}
448
449#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
452#[repr(u16)]
453pub enum ClipboardStatusCode {
454 Success = StatusCode::Success as u16,
455 Failure = StatusCode::Failure as u16,
456}
457
458impl fmt::Display for ClipboardStatusCode {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 match self {
461 Self::Success => write!(f, "success"),
462 Self::Failure => write!(f, "failure"),
463 }
464 }
465}
466
467#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
470#[repr(u16)]
471pub enum FileTransferStatusCode {
472 Success = StatusCode::Success as u16,
473 Failure = StatusCode::Failure as u16,
474}
475
476impl fmt::Display for FileTransferStatusCode {
477 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478 match self {
479 FileTransferStatusCode::Success => write!(f, "success"),
480 FileTransferStatusCode::Failure => write!(f, "failure"),
481 }
482 }
483}
484
485#[derive(Encode, Decode, FromPrimitive, ToPrimitive, Debug, PartialEq, Clone, Copy)]
488#[repr(u16)]
489pub enum ExecStatusCode {
490 Success = StatusCode::Success as u16,
491 Failure = StatusCode::Failure as u16,
492 FileNotFound = 1,
493 InvalidExecutable = 2,
494 AccessDenied = 3,
495}
496
497impl fmt::Display for ExecStatusCode {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 match self {
500 ExecStatusCode::Success => write!(f, "execution success"),
501 ExecStatusCode::Failure => write!(f, "execution failed"),
502 ExecStatusCode::FileNotFound => write!(f, "file not found"),
503 ExecStatusCode::InvalidExecutable => write!(f, "invalid executable"),
504 ExecStatusCode::AccessDenied => write!(f, "access denied"),
505 }
506 }
507}
508
509#[cfg(test)]
510mod tests {
511 use super::*;
512 use num;
513
514 #[test]
515 fn integer_conversion() {
516 let status = num::FromPrimitive::from_u8(3);
517 match status {
518 Some(SeverityLevel::Fatal) => { }
519 _ => panic!("wrong status value"),
520 }
521 }
522
523 #[test]
524 fn parse_from_u32() {
525 let nstatus = NowStatus::<AuthStatusCode>::try_from(0x8017_ffff).unwrap();
526 assert_eq!(nstatus.severity(), SeverityLevel::Error);
527 assert_eq!(nstatus.code(), AuthStatusCode::Failure);
528 assert_eq!(nstatus.status_type(), StatusType::Auth);
529 }
530
531 #[test]
532 fn repr_building() {
533 let nstatus = NowStatus::<AuthStatusCode>::builder(AuthStatusCode::Failure)
534 .severity(SeverityLevel::Error)
535 .status_type(StatusType::Auth)
536 .build();
537 assert_eq!(nstatus.as_u32(), 0x8017_ffff);
538 }
539}