miltr_common/modifications/
mod.rs1pub mod body;
7pub mod headers;
8pub mod quarantine;
9pub mod recipients;
10
11use enum_dispatch::enum_dispatch;
12
13use super::{
14 actions::{Action, Continue},
15 ServerMessage,
16};
17
18use crate::encoding::Writable;
19use crate::{actions::Abort, optneg::Capability};
20use bytes::BytesMut;
21
22use body::ReplaceBody;
23use headers::{AddHeader, ChangeHeader, InsertHeader};
24use quarantine::Quarantine;
25use recipients::{AddRecipient, DeleteRecipient};
26
27#[derive(Debug)]
46pub struct ModificationResponse {
47 modifications: Vec<ModificationAction>,
48 final_action: Action,
49}
50
51impl ModificationResponse {
52 #[must_use]
54 pub fn builder() -> ModificationResponseBuilder {
55 ModificationResponseBuilder {
56 modifications: Vec::default(),
57 }
58 }
59
60 #[must_use]
62 pub fn empty_continue() -> Self {
63 Self {
64 modifications: Vec::new(),
65 final_action: Continue.into(),
66 }
67 }
68
69 pub fn filter_mods_by_caps(&mut self, capabilities: Capability) {
72 self.modifications
73 .retain(|m| Self::mod_matches_caps(m, capabilities));
74 }
75
76 fn mod_matches_caps(modification: &ModificationAction, capabilities: Capability) -> bool {
78 match modification {
79 ModificationAction::AddHeader(_) => capabilities.contains(Capability::SMFIF_ADDHDRS),
80 ModificationAction::ReplaceBody(_) => capabilities.contains(Capability::SMFIF_CHGBODY),
81 ModificationAction::AddRecipient(_) => capabilities.contains(Capability::SMFIF_ADDRCPT),
82 ModificationAction::DeleteRecipient(_) => {
83 capabilities.contains(Capability::SMFIF_DELRCPT)
84 }
85 ModificationAction::ChangeHeader(_) | ModificationAction::InsertHeader(_) => {
86 capabilities.contains(Capability::SMFIF_CHGHDRS)
87 }
88 ModificationAction::Quarantine(_) => {
89 capabilities.contains(Capability::SMFIF_QUARANTINE)
90 }
91 }
92 }
93
94 #[must_use]
96 pub fn modifications(&self) -> &[ModificationAction] {
97 self.modifications.as_ref()
98 }
99
100 #[must_use]
102 pub fn final_action(&self) -> &Action {
103 &self.final_action
104 }
105}
106
107impl From<ModificationResponse> for Vec<ServerMessage> {
108 fn from(value: ModificationResponse) -> Self {
109 let mut resp: Vec<ServerMessage> = Vec::with_capacity(value.modifications.len() + 1);
110 resp.extend(
111 value
112 .modifications
113 .into_iter()
114 .map(ServerMessage::ModificationAction),
115 );
116 resp.push(ServerMessage::Action(value.final_action));
117 resp
118 }
119}
120
121#[derive(Debug, Clone)]
123pub struct ModificationResponseBuilder {
124 modifications: Vec<ModificationAction>,
125}
126
127impl ModificationResponseBuilder {
128 pub fn push<M: Into<ModificationAction>>(&mut self, mod_action: M) {
130 self.modifications.push(mod_action.into());
131 }
132
133 #[must_use]
135 pub fn abort(self) -> ModificationResponse {
136 self.build(Abort)
137 }
138
139 #[must_use]
142 pub fn contin(self) -> ModificationResponse {
143 self.build(Continue)
144 }
145
146 #[must_use]
148 pub fn build<A: Into<Action>>(self, final_action: A) -> ModificationResponse {
149 ModificationResponse {
150 modifications: self.modifications,
151 final_action: final_action.into(),
152 }
153 }
154}
155
156#[enum_dispatch]
158#[cfg_attr(feature = "tracing", derive(strum::Display))]
159#[derive(Debug, Clone)]
160pub enum ModificationAction {
161 AddRecipient,
163 DeleteRecipient,
165 ReplaceBody,
173 AddHeader,
183 InsertHeader,
185 ChangeHeader,
189 Quarantine,
195}