use crate::mailet::{Mailet, MailetConfig};
use crate::mailets::{
AddHeaderMailet, DkimVerifyMailet, DmarcVerifyMailet, LocalDeliveryMailet,
RemoteDeliveryMailet, RemoveMimeHeaderMailet, SieveMailet, SpamAssassinMailet, SpfCheckMailet,
VirusScanMailet,
};
use crate::matcher::Matcher;
use crate::matcher::{AllMatcher, NoneMatcher};
use crate::matchers::{
AndMatcher, HeaderContainsMatcher, IsInBlacklistMatcher, IsInWhitelistMatcher, NotMatcher,
OrMatcher, RecipientIsLocalMatcher, RemoteAddressMatcher, SizeGreaterThanMatcher,
};
use rusmes_storage::StorageBackend;
use std::net::IpAddr;
use std::sync::Arc;
pub async fn create_mailet(name: &str, config: MailetConfig) -> anyhow::Result<Arc<dyn Mailet>> {
create_mailet_with_storage(name, config, None).await
}
pub async fn create_mailet_with_storage(
name: &str,
config: MailetConfig,
storage: Option<Arc<dyn StorageBackend>>,
) -> anyhow::Result<Arc<dyn Mailet>> {
match name {
"LocalDelivery" => {
let mut mailet = if let Some(storage) = storage {
LocalDeliveryMailet::with_storage(storage)
} else {
LocalDeliveryMailet::new()
};
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"RemoteDelivery" => {
let mut mailet = RemoteDeliveryMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"AddHeader" => {
let mut mailet = AddHeaderMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"RemoveMimeHeader" => {
let mut mailet = RemoveMimeHeaderMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"SpamAssassin" => {
let mut mailet = SpamAssassinMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"VirusScan" => {
let mut mailet = VirusScanMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"DkimVerify" => {
let mut mailet = DkimVerifyMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"SpfCheck" => {
let mut mailet = SpfCheckMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"DmarcVerify" => {
let mut mailet = DmarcVerifyMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
"Sieve" | "SieveMailet" => {
let mut mailet = SieveMailet::new();
mailet.init(config).await?;
Ok(Arc::new(mailet))
}
_ => Err(anyhow::anyhow!("Unknown mailet: {}", name)),
}
}
pub fn create_matcher(name: &str, local_domains: Vec<String>) -> anyhow::Result<Arc<dyn Matcher>> {
match name {
"All" => Ok(Arc::new(AllMatcher)),
"None" => Ok(Arc::new(NoneMatcher)),
"RecipientIsLocal" => Ok(Arc::new(RecipientIsLocalMatcher::new(local_domains))),
_ => Err(anyhow::anyhow!("Unknown matcher: {}", name)),
}
}
pub fn create_size_greater_than_matcher(threshold_bytes: usize) -> Arc<dyn Matcher> {
Arc::new(SizeGreaterThanMatcher::new(threshold_bytes))
}
pub fn create_header_contains_matcher(header_name: String, value: String) -> Arc<dyn Matcher> {
Arc::new(HeaderContainsMatcher::new(header_name, value))
}
pub fn create_remote_address_matcher(
allowed_ips: Vec<IpAddr>,
allowed_cidrs: Vec<(IpAddr, u8)>,
) -> Arc<dyn Matcher> {
Arc::new(RemoteAddressMatcher::new(allowed_ips, allowed_cidrs))
}
pub fn create_whitelist_matcher(whitelist: Vec<String>) -> Arc<dyn Matcher> {
Arc::new(IsInWhitelistMatcher::new(whitelist))
}
pub fn create_blacklist_matcher(blacklist: Vec<String>) -> Arc<dyn Matcher> {
Arc::new(IsInBlacklistMatcher::new(blacklist))
}
pub fn create_and_matcher(matchers: Vec<Arc<dyn Matcher>>) -> Arc<dyn Matcher> {
Arc::new(AndMatcher::new(matchers))
}
pub fn create_or_matcher(matchers: Vec<Arc<dyn Matcher>>) -> Arc<dyn Matcher> {
Arc::new(OrMatcher::new(matchers))
}
pub fn create_not_matcher(matcher: Arc<dyn Matcher>) -> Arc<dyn Matcher> {
Arc::new(NotMatcher::new(matcher))
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_create_mailet() {
let config = MailetConfig::new("LocalDelivery");
let mailet = create_mailet("LocalDelivery", config).await;
assert!(mailet.is_ok());
}
#[test]
fn test_create_matcher() {
let matcher = create_matcher("All", vec![]);
assert!(matcher.is_ok());
assert_eq!(matcher.unwrap().name(), "All");
}
#[tokio::test]
async fn test_issue_1_sieve_mailet_recognized() {
let config = MailetConfig::new("Sieve")
.with_param("name", "sieve")
.with_param("global_script", "keep;")
.with_param("script_dir", "/root/rusmes");
let mailet = create_mailet("Sieve", config.clone()).await;
assert!(
mailet.is_ok(),
"expected `Sieve` mailet to resolve, got: {:?}",
mailet.err()
);
assert_eq!(mailet.expect("Sieve mailet should resolve").name(), "Sieve");
let alias = create_mailet("SieveMailet", config).await;
assert!(
alias.is_ok(),
"expected `SieveMailet` alias to resolve, got: {:?}",
alias.err()
);
assert_eq!(
alias.expect("SieveMailet alias should resolve").name(),
"Sieve"
);
}
}