miltr_common/actions/
to_mta_only.rs1use std::borrow::Cow;
2
3use bytes::{BufMut, BytesMut};
4use itertools::Itertools;
5
6use crate::decoding::Parsable;
7use crate::encoding::Writable;
8use crate::{error::STAGE_DECODING, NotEnoughData};
9use crate::{InvalidData, ProtocolError};
10use miltr_utils::ByteParsing;
11
12#[derive(Debug, Clone)]
14pub struct Discard;
15
16impl Discard {
17 const CODE: u8 = b'd';
18}
19
20impl Parsable for Discard {
21 const CODE: u8 = Self::CODE;
22
23 fn parse(_buffer: BytesMut) -> Result<Self, ProtocolError> {
24 Ok(Self)
25 }
26}
27
28impl Writable for Discard {
29 fn write(&self, _buffer: &mut BytesMut) {}
30
31 fn len(&self) -> usize {
32 0
33 }
34
35 fn code(&self) -> u8 {
36 Self::CODE
37 }
38
39 fn is_empty(&self) -> bool {
40 self.len() == 0
41 }
42}
43
44#[derive(Debug, Clone)]
46pub struct Reject;
47
48impl Reject {
49 const CODE: u8 = b'r';
50}
51
52impl Parsable for Reject {
53 const CODE: u8 = Self::CODE;
54
55 fn parse(_buffer: BytesMut) -> Result<Self, ProtocolError> {
56 Ok(Self)
57 }
58}
59
60impl Writable for Reject {
61 fn write(&self, _buffer: &mut BytesMut) {}
62
63 fn len(&self) -> usize {
64 0
65 }
66
67 fn code(&self) -> u8 {
68 Self::CODE
69 }
70
71 fn is_empty(&self) -> bool {
72 self.len() == 0
73 }
74}
75
76#[derive(Debug, Clone)]
78pub struct Tempfail;
79
80impl Tempfail {
81 const CODE: u8 = b't';
82}
83
84impl Parsable for Tempfail {
85 const CODE: u8 = Self::CODE;
86
87 fn parse(_buffer: BytesMut) -> Result<Self, ProtocolError> {
88 Ok(Self)
89 }
90}
91
92impl Writable for Tempfail {
93 fn write(&self, _buffer: &mut BytesMut) {}
94
95 fn len(&self) -> usize {
96 0
97 }
98
99 fn code(&self) -> u8 {
100 Self::CODE
101 }
102 fn is_empty(&self) -> bool {
103 self.len() == 0
104 }
105}
106
107#[derive(Debug, Clone)]
109pub struct Skip;
110
111impl Skip {
112 const CODE: u8 = b's';
113}
114
115impl Parsable for Skip {
116 const CODE: u8 = Self::CODE;
117
118 fn parse(_buffer: BytesMut) -> Result<Self, ProtocolError> {
119 Ok(Self)
120 }
121}
122
123impl Writable for Skip {
124 fn write(&self, _buffer: &mut BytesMut) {}
125
126 fn len(&self) -> usize {
127 0
128 }
129
130 fn code(&self) -> u8 {
131 Self::CODE
132 }
133
134 fn is_empty(&self) -> bool {
135 self.len() == 0
136 }
137}
138
139const REPLY_CODE_LENGTH: usize = 3;
140#[derive(Debug, Clone)]
142pub struct Replycode {
143 rcode: Code,
144 xcode: Code,
145 message: BytesMut,
146}
147
148impl Replycode {
149 const CODE: u8 = b'y';
150
151 #[must_use]
153 #[allow(clippy::similar_names)]
154 pub fn new<R: Into<Code>, X: Into<Code>>(rcode: R, xcode: X, message: &str) -> Self {
155 let rcode = rcode.into();
156 let xcode = xcode.into();
157
158 Self {
159 rcode,
160 xcode,
161 message: BytesMut::from(message.as_bytes()),
162 }
163 }
164
165 #[must_use]
167 pub fn message(&self) -> Cow<str> {
168 String::from_utf8_lossy(&self.message)
169 }
170
171 #[must_use]
173 pub fn rcode(&self) -> &Code {
174 &self.rcode
175 }
176
177 #[must_use]
179 pub fn xcode(&self) -> &Code {
180 &self.xcode
181 }
182}
183
184impl Parsable for Replycode {
185 const CODE: u8 = Self::CODE;
186
187 #[allow(clippy::similar_names)]
189 fn parse(mut buffer: BytesMut) -> Result<Self, ProtocolError> {
190 #[allow(clippy::similar_names)]
191 let Some(rcode) = buffer.delimited(0) else {
192 return Err(NotEnoughData::new(
193 STAGE_DECODING,
194 "Replycode",
195 "Missing nullbyte delimiter after rcode",
196 1,
197 0,
198 buffer,
199 )
200 .into());
201 };
202 let rcode = Code::parse(rcode)?;
203
204 let Some(xcode) = buffer.delimited(0) else {
205 return Err(NotEnoughData::new(
206 STAGE_DECODING,
207 "Replycode",
208 "Missing nullbyte delimiter after xcode",
209 1,
210 0,
211 buffer,
212 )
213 .into());
214 };
215 let xcode = Code::parse(xcode)?;
216
217 let Some(message) = buffer.delimited(0) else {
218 return Err(NotEnoughData::new(
219 STAGE_DECODING,
220 "Replycode",
221 "Missing nullbyte delimiter after message",
222 1,
223 0,
224 buffer,
225 )
226 .into());
227 };
228
229 Ok(Self {
230 rcode,
231 xcode,
232 message,
233 })
234 }
235}
236
237impl Writable for Replycode {
238 fn write(&self, buffer: &mut BytesMut) {
239 buffer.put_slice(self.rcode.as_bytes());
240 buffer.put_u8(0);
241 buffer.put_slice(self.xcode.as_bytes());
242 buffer.put_u8(0);
243 buffer.put_slice(&self.message);
244 buffer.put_u8(0);
245 }
246
247 fn len(&self) -> usize {
248 self.rcode.len() + 1 + self.xcode.len() + 1 + self.message.len() + 1
249 }
250
251 fn code(&self) -> u8 {
252 Self::CODE
253 }
254 fn is_empty(&self) -> bool {
255 self.len() == 0
256 }
257}
258
259#[derive(Debug, Clone)]
260pub struct Code {
261 code: [u16; REPLY_CODE_LENGTH],
262 bytes: BytesMut,
263}
264
265impl From<[u16; REPLY_CODE_LENGTH]> for Code {
266 fn from(code: [u16; REPLY_CODE_LENGTH]) -> Self {
267 Self::new(code)
268 }
269}
270
271impl Code {
272 pub fn new(code: [u16; REPLY_CODE_LENGTH]) -> Self {
273 Self {
274 code,
275 bytes: BytesMut::from_iter(code.iter().map(ToString::to_string).join(".").as_bytes()),
276 }
277 }
278
279 fn parse(buffer: BytesMut) -> Result<Self, InvalidData> {
280 let mut positions = buffer.iter().positions(|&c| c == b'.');
281 let mut code: [u16; 3] = [0_u16; REPLY_CODE_LENGTH];
282
283 let mut start = 0;
284 for c_code in code.iter_mut().take(REPLY_CODE_LENGTH - 1) {
285 let Some(end) = positions.next() else {
286 return Err(InvalidData {
287 msg: "missing '.' delimiter in code",
288 offending_bytes: buffer,
289 });
290 };
291 let raw = &buffer[start..end];
292 let Ok(number) = String::from_utf8_lossy(raw).parse() else {
293 return Err(InvalidData {
294 msg: "invalid u16 in code",
295 offending_bytes: buffer,
296 });
297 };
298
299 *c_code = number;
300 start = end + 1;
301 }
302 let raw = &buffer[start..buffer.len()];
303 let Ok(number) = String::from_utf8_lossy(raw).parse() else {
304 return Err(InvalidData {
305 msg: "invalid u16 in code",
306 offending_bytes: buffer,
307 });
308 };
309
310 code[REPLY_CODE_LENGTH - 1] = number;
311
312 Ok(Self {
313 code,
314 bytes: buffer,
315 })
316 }
317
318 #[must_use]
320 pub fn code(&self) -> [u16; REPLY_CODE_LENGTH] {
321 self.code
322 }
323
324 fn as_bytes(&self) -> &[u8] {
325 &self.bytes
326 }
327
328 fn len(&self) -> usize {
329 self.bytes.len()
330 }
331}
332
333#[cfg(test)]
334mod test {
335 use super::*;
336
337 #[test]
338 fn test_rcode_valid() {
339 let input = BytesMut::from_iter(b"1.20.3");
340 let code = Code::parse(input).expect("Failed parsing input");
341
342 assert_eq!(code.code, [1, 20, 3]);
343
344 println!("{:?}", code.bytes);
345 assert_eq!(6, code.bytes.len());
346 }
347
348 #[test]
349 fn test_rcode_invalid() {
350 let input = BytesMut::from_iter(b"1.23");
351 let _code = Code::parse(input).expect_err("Parsing did not error on invalid");
352 }
353}