miltr_common/commands/
unknown.rs

1use bytes::{BufMut, BytesMut};
2
3use crate::decoding::Parsable;
4use crate::encoding::Writable;
5use crate::{InvalidData, ProtocolError};
6use miltr_utils::ByteParsing;
7
8/// An unknown SMTP command.
9///
10///
11/// This allows extending the SMTP protocol by special commands.
12#[derive(Clone, PartialEq, Debug)]
13pub struct Unknown {
14    data: BytesMut,
15}
16
17impl Unknown {
18    const CODE: u8 = b'U';
19}
20
21impl From<&[u8]> for Unknown {
22    fn from(value: &[u8]) -> Self {
23        Self {
24            data: BytesMut::from(value),
25        }
26    }
27}
28
29impl From<BytesMut> for Unknown {
30    fn from(data: BytesMut) -> Self {
31        Self { data }
32    }
33}
34
35impl Unknown {
36    /// Access the contained body bytes.
37    #[must_use]
38    pub fn as_bytes(&self) -> &[u8] {
39        &self.data
40    }
41
42    /// Access the contained body bytes mutably.
43    #[must_use]
44    pub fn as_mut_bytes(&mut self) -> &mut [u8] {
45        &mut self.data
46    }
47}
48
49impl Writable for Unknown {
50    fn write(&self, buffer: &mut BytesMut) {
51        buffer.extend_from_slice(&self.data);
52        buffer.put_u8(0);
53    }
54
55    fn len(&self) -> usize {
56        1 + self.data.len()
57    }
58
59    fn code(&self) -> u8 {
60        Self::CODE
61    }
62
63    fn is_empty(&self) -> bool {
64        false
65    }
66}
67
68impl Parsable for Unknown {
69    const CODE: u8 = Self::CODE;
70
71    fn parse(mut buffer: BytesMut) -> Result<Self, ProtocolError> {
72        let Some(data) = buffer.delimited(0) else {
73            return Err(
74                InvalidData::new("Received unknown package terminating null byte", buffer).into(),
75            );
76        };
77        Ok(data.into())
78    }
79}
80
81#[cfg(all(test, feature = "count-allocations"))]
82mod test {
83    use super::*;
84
85    #[test]
86    fn test_parse_unknown() {
87        let buffer = BytesMut::from_iter([255, 0, 0, 0]);
88        let info = allocation_counter::measure(|| {
89            let _ = Unknown::parse(buffer);
90        });
91        // Verify memory allocations
92        assert_eq!(info.count_total, 1);
93    }
94}