now_proto_pdu/session/
msg_box_rsp.rs

1use ironrdp_core::{
2    cast_length, ensure_fixed_part_size, Decode, DecodeResult, Encode, EncodeResult, IntoOwned, ReadCursor, WriteCursor,
3};
4
5use crate::{
6    NowHeader, NowMessage, NowMessageClass, NowSessionMessage, NowSessionMessageKind, NowStatus, NowStatusError,
7};
8
9/// Message box response; Directly maps to the WinAPI MessageBox function response.
10///
11/// NOW_PROTO: `response` field from NOW_SESSION_MESSAGE_BOX_RSP_MSG
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct NowMsgBoxResponse(u32);
14
15impl NowMsgBoxResponse {
16    /// OK
17    ///
18    /// NOW_PROTO: IDOK
19    pub const OK: Self = Self(1);
20    /// Cancel
21    ///
22    /// NOW_PROTO: IDCANCEL
23    pub const CANCEL: Self = Self(2);
24    /// Abort
25    ///
26    /// NOW_PROTO: IDABORT
27    pub const ABORT: Self = Self(3);
28    /// Retry
29    ///
30    /// NOW_PROTO: IDRETRY
31    pub const RETRY: Self = Self(4);
32    /// Ignore
33    ///
34    /// NOW_PROTO: IDIGNORE
35    pub const IGNORE: Self = Self(5);
36    /// Yes
37    ///
38    /// NOW_PROTO: IDYES
39    pub const YES: Self = Self(6);
40    /// No
41    ///
42    /// NOW_PROTO: IDNO
43    pub const NO: Self = Self(7);
44    /// Try Again
45    ///
46    /// NOW_PROTO: IDTRYAGAIN
47    pub const TRY_AGAIN: Self = Self(10);
48    /// Continue
49    ///
50    /// NOW_PROTO: IDCONTINUE
51    pub const CONTINUE: Self = Self(11);
52    /// Timeout
53    ///
54    /// NOW_PROTO: IDTIMEOUT
55    pub const TIMEOUT: Self = Self(32000);
56
57    pub fn new(response: u32) -> Self {
58        Self(response)
59    }
60
61    pub fn value(&self) -> u32 {
62        self.0
63    }
64}
65
66/// The NOW_SESSION_MSGBOX_RSP_MSG is a message sent in response to NOW_SESSION_MSGBOX_REQ_MSG if
67/// the NOW_MSGBOX_FLAG_RESPONSE has been set, and contains the result from the message box dialog.
68///
69/// NOW_PROTO: NOW_SESSION_MSGBOX_RSP_MSG
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct NowSessionMsgBoxRspMsg<'a> {
72    request_id: u32,
73    response: NowMsgBoxResponse,
74    status: NowStatus<'a>,
75}
76
77impl_pdu_borrowing!(NowSessionMsgBoxRspMsg<'_>, OwnedNowSessionMsgBoxRspMsg);
78
79impl IntoOwned for NowSessionMsgBoxRspMsg<'_> {
80    type Owned = OwnedNowSessionMsgBoxRspMsg;
81
82    fn into_owned(self) -> Self::Owned {
83        OwnedNowSessionMsgBoxRspMsg {
84            request_id: self.request_id,
85            response: self.response,
86            status: self.status.into_owned(),
87        }
88    }
89}
90
91impl<'a> NowSessionMsgBoxRspMsg<'a> {
92    const NAME: &'static str = "NOW_SESSION_MSGBOX_RSP_MSG";
93    const FIXED_PART_SIZE: usize = 8;
94
95    pub fn new_success(request_id: u32, response: NowMsgBoxResponse) -> Self {
96        Self {
97            request_id,
98            response,
99            status: NowStatus::new_success(),
100        }
101    }
102
103    pub fn new_error(request_id: u32, error: impl Into<NowStatusError>) -> EncodeResult<Self> {
104        let msg = Self {
105            request_id,
106            response: NowMsgBoxResponse(0),
107            status: NowStatus::new_error(error),
108        };
109
110        ensure_now_message_size!(Self::FIXED_PART_SIZE, msg.status.size());
111
112        Ok(msg)
113    }
114
115    pub fn request_id(&self) -> u32 {
116        self.request_id
117    }
118
119    /// Get the response from the message box dialog. Returns (Err(_) if the request has failed).
120    pub fn to_result(&self) -> Result<NowMsgBoxResponse, NowStatusError> {
121        self.status.to_result().map(|_| self.response)
122    }
123
124    // LINTS: Overall message size is validated in the constructor/decode method
125    #[allow(clippy::arithmetic_side_effects)]
126    fn body_size(&self) -> usize {
127        Self::FIXED_PART_SIZE + self.status.size()
128    }
129
130    pub(super) fn decode_from_body(_header: NowHeader, src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
131        ensure_fixed_part_size!(in: src);
132
133        let request_id = src.read_u32();
134        let response = NowMsgBoxResponse(src.read_u32());
135
136        let status = NowStatus::decode(src)?;
137
138        Ok(Self {
139            request_id,
140            response,
141            status,
142        })
143    }
144}
145
146impl Encode for NowSessionMsgBoxRspMsg<'_> {
147    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
148        let header = NowHeader {
149            size: cast_length!("size", self.body_size())?,
150            class: NowMessageClass::SESSION,
151            kind: NowSessionMessageKind::MSGBOX_RSP.0,
152            flags: 0,
153        };
154
155        header.encode(dst)?;
156
157        ensure_fixed_part_size!(in: dst);
158        dst.write_u32(self.request_id);
159        dst.write_u32(self.response.value());
160
161        self.status.encode(dst)?;
162
163        Ok(())
164    }
165
166    fn name(&self) -> &'static str {
167        Self::NAME
168    }
169
170    fn size(&self) -> usize {
171        NowHeader::FIXED_PART_SIZE + self.body_size()
172    }
173}
174
175impl<'de> Decode<'de> for NowSessionMsgBoxRspMsg<'de> {
176    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
177        let header = NowHeader::decode(src)?;
178
179        match (header.class, NowSessionMessageKind(header.kind)) {
180            (NowMessageClass::SESSION, NowSessionMessageKind::MSGBOX_RSP) => Self::decode_from_body(header, src),
181            _ => Err(unsupported_message_err!(class: header.class.0, kind: header.kind)),
182        }
183    }
184}
185
186impl<'a> From<NowSessionMsgBoxRspMsg<'a>> for NowMessage<'a> {
187    fn from(val: NowSessionMsgBoxRspMsg<'a>) -> Self {
188        NowMessage::Session(NowSessionMessage::MsgBoxRsp(val))
189    }
190}