miltr_common/optneg/
protocol.rs

1use crate::commands::Command;
2
3bitflags::bitflags! {
4    /// Protocol flags configuring communications behavior
5    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
6    pub struct Protocol: u32 {
7        /// MTA should not send connect info
8        #[doc(alias="SMFIP_NOCONNECT")]
9        const NO_CONNECT = 0x0000_0001;
10            /// MTA should not send HELO info
11        #[doc(alias="SMFIP_NOHELO")]
12        const NO_HELO = 0x0000_0002;
13        /// MTA should not send MAIL info
14        #[doc(alias="SMFIP_NOMAIL")]
15        const NO_MAIL = 0x0000_0004;
16        /// MTA should not send RCPT info
17        #[doc(alias="SMFIP_NORCPT")]
18        const NO_RECIPIENT = 0x0000_0008;
19        /// MTA should not send body
20        #[doc(alias="SMFIP_NOBODY")]
21        const NO_BODY = 0x0000_0010;
22        /// MTA should not send headers
23        #[doc(alias="SMFIP_NOHDRS")]
24        const NO_HEADER = 0x0000_0020;
25        /// MTA should not send EOH
26        #[doc(alias="SMFIP_NOEOH")]
27        const NO_END_OF_HEADER = 0x0000_0040;
28        /// No reply for headers
29        #[doc(alias="SMFIP_NR_HDR")]
30        const NR_HEADER = 0x0000_0080;
31        /// MTA should not send unknown commands
32        #[doc(alias="SMFIP_NOUNKNOWN")]
33        const NO_UNKNOWN = 0x0000_0100;
34        /// MTA should not send DATA
35        #[doc(alias="SMFIP_NODATA")]
36        const NO_DATA =    0x0000_0200;
37        /// MTA understands SMFIS_SKIP
38        const SMFIP_SKIP = 0x0000_0400;
39        /// MTA should also send rejected RCPTs
40        const SMFIP_RCPT_REJ = 0x0000_0800;
41        /// No reply for connect
42        #[doc(alias="SMFIP_NR_CONN")]
43        const NR_CONNECT = 0x0000_1000;
44        /// No reply for HELO
45        #[doc(alias="SMFIP_NR_HELO")]
46        const NR_HELO = 0x0000_2000;
47        /// No reply for MAIL
48        #[doc(alias="SMFIP_NR_MAIL")]
49        const NR_MAIL = 0x0000_4000;
50        /// No reply for RCPT
51        #[doc(alias="SMFIP_NR_RCPT")]
52        const NR_RECIPIENT = 0x0000_8000;
53        /// No reply for DATA
54        #[doc(alias="SMFIP_NR_DATA")]
55        const NR_DATA = 0x0001_0000;
56        /// No reply for UNKN
57        #[doc(alias="SMFIP_NR_UNKN")]
58        const NR_UNKNOWN = 0x0002_0000;
59        /// No reply for eoh
60        #[doc(alias="SMFIP_NR_EOH")]
61        const NR_END_OF_HEADER = 0x0004_0000;
62        /// No reply for body chunk
63        #[doc(alias="SMFIP_NR_BODY")]
64        const NR_BODY = 0x0008_0000;
65        /// header value leading space
66        const SMFIP_HDR_LEADSPC = 0x0010_0000;
67    }
68}
69
70impl Default for Protocol {
71    fn default() -> Self {
72        Self::empty()
73    }
74}
75
76impl Protocol {
77    /// Whether `self` indicates that this command should be sent or not
78    #[must_use]
79    pub fn should_skip_send(&self, command: &Command) -> bool {
80        match command {
81            Command::Connect(_) => self.contains(Protocol::NO_CONNECT),
82            Command::Helo(_) => self.contains(Protocol::NO_HELO),
83            Command::Mail(_) => self.contains(Protocol::NO_MAIL),
84            Command::Recipient(_) => self.contains(Protocol::NO_RECIPIENT),
85            Command::Header(_) => self.contains(Protocol::NO_HEADER),
86            Command::EndOfHeader(_) => self.contains(Protocol::NO_END_OF_HEADER),
87            Command::Data(_) => self.contains(Protocol::NO_DATA),
88            Command::Body(_) => self.contains(Protocol::NO_BODY),
89            Command::EndOfBody(_) => false,
90            Command::Unknown(_) => self.contains(Protocol::NO_UNKNOWN),
91        }
92    }
93
94    /// Whether `self` indicates a response should be awaited to this command
95    #[must_use]
96    pub fn should_skip_response(&self, command: &Command) -> bool {
97        match command {
98            Command::Connect(_) => self.contains(Protocol::NR_CONNECT),
99            Command::Helo(_) => self.contains(Protocol::NR_HELO),
100            Command::Mail(_) => self.contains(Protocol::NR_MAIL),
101            Command::Recipient(_) => self.contains(Protocol::NR_RECIPIENT),
102            Command::Header(_) => self.contains(Protocol::NR_HEADER),
103            Command::EndOfHeader(_) => self.contains(Protocol::NR_END_OF_HEADER),
104            Command::Data(_) => self.contains(Protocol::NR_DATA),
105            Command::Body(_) => self.contains(Protocol::NR_BODY),
106            Command::EndOfBody(_) => false,
107            Command::Unknown(_) => self.contains(Protocol::NR_UNKNOWN),
108        }
109    }
110
111    /// Merge `other` protocol with `self`
112    ///
113    /// Currently no version dependent merging implemented
114    #[must_use]
115    pub fn merge_regarding_version(self, _version: u32, other: Self) -> Self {
116        // No version dependent merging implemented yet
117        self.intersection(other)
118    }
119}