Files
stalwart/crates/common/src/scripts/functions/header.rs
2025-06-15 15:09:32 +02:00

97 lines
3.1 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use mail_parser::{HeaderName, HeaderValue, MimeHeaders, parsers::fields::thread::thread_name};
use sieve::{Context, compiler::ReceivedPart, runtime::Variable};
use super::ApplyString;
pub fn fn_received_part<'x>(ctx: &'x Context<'x>, v: Vec<Variable>) -> Variable {
if let (Ok(part), Some(HeaderValue::Received(rcvd))) = (
ReceivedPart::try_from(v[1].to_string().as_ref()),
ctx.message()
.part(ctx.part())
.and_then(|p| {
p.headers
.iter()
.filter(|h| h.name == HeaderName::Received)
.nth((v[0].to_integer() as usize).saturating_sub(1))
})
.map(|h| &h.value),
) {
part.eval(rcvd).unwrap_or_default()
} else {
Variable::default()
}
}
pub fn fn_is_encoding_problem<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> Variable {
ctx.message()
.part(ctx.part())
.map(|p| p.is_encoding_problem)
.unwrap_or_default()
.into()
}
pub fn fn_is_attachment<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> Variable {
ctx.message().attachments.contains(&ctx.part()).into()
}
pub fn fn_is_body<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> Variable {
(ctx.message().text_body.contains(&ctx.part()) || ctx.message().html_body.contains(&ctx.part()))
.into()
}
pub fn fn_attachment_name<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> Variable {
ctx.message()
.part(ctx.part())
.and_then(|p| p.attachment_name())
.unwrap_or_default()
.into()
}
pub fn fn_mime_part_len<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> Variable {
ctx.message()
.part(ctx.part())
.map(|p| p.len())
.unwrap_or_default()
.into()
}
pub fn fn_thread_name<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
v[0].transform(|s| thread_name(s).into())
}
pub fn fn_is_header_utf8_valid<'x>(ctx: &'x Context<'x>, v: Vec<Variable>) -> Variable {
ctx.message()
.part(ctx.part())
.map(|p| {
let raw = ctx.message().raw_message();
let mut is_valid = true;
if let Some(header_name) = HeaderName::parse(v[0].to_string().as_ref()) {
for header in &p.headers {
if header.name == header_name
&& raw
.get(header.offset_start() as usize..header.offset_end() as usize)
.and_then(|raw| std::str::from_utf8(raw).ok())
.is_none()
{
is_valid = false;
break;
}
}
} else {
is_valid = raw
.get(p.raw_header_offset() as usize..p.raw_body_offset() as usize)
.and_then(|raw| std::str::from_utf8(raw).ok())
.is_some();
}
Variable::from(is_valid)
})
.unwrap_or(Variable::Integer(1))
}