Files
Stalwart/crates/smtp/src/scripts/mod.rs
2026-05-26 21:08:06 +02:00

137 lines
3.4 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use std::borrow::Cow;
use ahash::AHashMap;
use common::{
Server, auth::AccessToken, expr::functions::ResolveVariable, scripts::ScriptModification,
};
use mail_parser::Message;
use sieve::{Envelope, SpamStatus, runtime::Variable};
pub mod envelope;
pub mod event_loop;
pub mod exec;
#[derive(Debug, serde::Serialize)]
pub enum ScriptResult {
Accept {
modifications: Vec<ScriptModification>,
},
Replace {
message: Vec<u8>,
modifications: Vec<ScriptModification>,
},
Reject(String),
Discard,
}
pub struct ScriptParameters<'x> {
message: Option<Message<'x>>,
headers: Option<&'x [u8]>,
variables: AHashMap<Cow<'static, str>, Variable>,
envelope: Vec<(Envelope, Variable)>,
from_addr: String,
from_name: String,
return_path: String,
sign_domain: Option<String>,
access_token: Option<&'x AccessToken>,
spam_status: Option<SpamStatus>,
session_id: u64,
}
impl<'x> ScriptParameters<'x> {
pub fn new() -> Self {
ScriptParameters {
variables: AHashMap::with_capacity(10),
envelope: Vec::with_capacity(6),
message: None,
headers: None,
from_addr: Default::default(),
from_name: Default::default(),
return_path: Default::default(),
sign_domain: Default::default(),
access_token: None,
spam_status: None,
session_id: Default::default(),
}
}
pub async fn with_envelope(
mut self,
server: &Server,
vars: &impl ResolveVariable,
session_id: u64,
) -> Self {
for (variable, expr) in [
(&mut self.from_addr, &server.core.sieve.from_addr),
(&mut self.from_name, &server.core.sieve.from_name),
(&mut self.return_path, &server.core.sieve.return_path),
] {
if let Some(value) = server.eval_if(expr, vars, session_id).await {
*variable = value;
}
}
self.sign_domain = server
.eval_if(&server.core.sieve.sign, vars, session_id)
.await;
self
}
pub fn with_message(self, message: Message<'x>) -> Self {
Self {
message: message.into(),
..self
}
}
pub fn with_auth_headers(self, headers: &'x [u8]) -> Self {
Self {
headers: headers.into(),
..self
}
}
pub fn with_spam_status(self, status: SpamStatus) -> Self {
Self {
spam_status: status.into(),
..self
}
}
pub fn set_variable(
mut self,
name: impl Into<Cow<'static, str>>,
value: impl Into<Variable>,
) -> Self {
self.variables.insert(name.into(), value.into());
self
}
pub fn set_envelope(mut self, envelope: Envelope, value: impl Into<Variable>) -> Self {
self.envelope.push((envelope, value.into()));
self
}
pub fn with_access_token(mut self, access_token: &'x AccessToken) -> Self {
self.access_token = Some(access_token);
self
}
pub fn with_session_id(mut self, session_id: u64) -> Self {
self.session_id = session_id;
self
}
}
impl Default for ScriptParameters<'_> {
fn default() -> Self {
Self::new()
}
}