pub mod body;
pub mod headers;
pub mod quarantine;
pub mod recipients;
use enum_dispatch::enum_dispatch;
use super::{
actions::{Action, Continue},
ServerMessage,
};
use crate::encoding::Writable;
use crate::{actions::Abort, optneg::Capability};
use bytes::BytesMut;
use body::ReplaceBody;
use headers::{AddHeader, ChangeHeader, InsertHeader};
use quarantine::Quarantine;
use recipients::{AddRecipient, DeleteRecipient};
#[derive(Debug)]
pub struct ModificationResponse {
modifications: Vec<ModificationAction>,
final_action: Action,
}
impl ModificationResponse {
#[must_use]
pub fn builder() -> ModificationResponseBuilder {
ModificationResponseBuilder {
modifications: Vec::default(),
}
}
#[must_use]
pub fn empty_continue() -> Self {
Self {
modifications: Vec::new(),
final_action: Continue.into(),
}
}
pub fn filter_mods_by_caps(&mut self, capabilities: Capability) {
self.modifications
.retain(|m| Self::mod_matches_caps(m, capabilities));
}
fn mod_matches_caps(modification: &ModificationAction, capabilities: Capability) -> bool {
match modification {
ModificationAction::AddHeader(_) => capabilities.contains(Capability::SMFIF_ADDHDRS),
ModificationAction::ReplaceBody(_) => capabilities.contains(Capability::SMFIF_CHGBODY),
ModificationAction::AddRecipient(_) => capabilities.contains(Capability::SMFIF_ADDRCPT),
ModificationAction::DeleteRecipient(_) => {
capabilities.contains(Capability::SMFIF_DELRCPT)
}
ModificationAction::ChangeHeader(_) | ModificationAction::InsertHeader(_) => {
capabilities.contains(Capability::SMFIF_CHGHDRS)
}
ModificationAction::Quarantine(_) => {
capabilities.contains(Capability::SMFIF_QUARANTINE)
}
}
}
#[must_use]
pub fn modifications(&self) -> &[ModificationAction] {
self.modifications.as_ref()
}
#[must_use]
pub fn final_action(&self) -> &Action {
&self.final_action
}
}
impl From<ModificationResponse> for Vec<ServerMessage> {
fn from(value: ModificationResponse) -> Self {
let mut resp: Vec<ServerMessage> = Vec::with_capacity(value.modifications.len() + 1);
resp.extend(
value
.modifications
.into_iter()
.map(ServerMessage::ModificationAction),
);
resp.push(ServerMessage::Action(value.final_action));
resp
}
}
#[derive(Debug, Clone)]
pub struct ModificationResponseBuilder {
modifications: Vec<ModificationAction>,
}
impl ModificationResponseBuilder {
pub fn push<M: Into<ModificationAction>>(&mut self, mod_action: M) {
self.modifications.push(mod_action.into());
}
#[must_use]
pub fn abort(self) -> ModificationResponse {
self.build(Abort)
}
#[must_use]
pub fn contin(self) -> ModificationResponse {
self.build(Continue)
}
#[must_use]
pub fn build<A: Into<Action>>(self, final_action: A) -> ModificationResponse {
ModificationResponse {
modifications: self.modifications,
final_action: final_action.into(),
}
}
}
#[enum_dispatch]
#[cfg_attr(feature = "tracing", derive(strum::Display))]
#[derive(Debug, Clone)]
pub enum ModificationAction {
AddRecipient,
DeleteRecipient,
ReplaceBody,
AddHeader,
InsertHeader,
ChangeHeader,
Quarantine,
}