opensmtpd-filter-dkimout/src/message.rs

104 lines
2.5 KiB
Rust
Raw Normal View History

2023-03-19 21:42:36 +01:00
use crate::entry::Entry;
2023-03-25 15:42:46 +01:00
use mailparse::parse_mail;
2023-03-19 21:42:36 +01:00
use std::io::{BufWriter, Write};
pub const RETURN_SEP: &[u8] = b"|";
pub const RETURN_START: &[u8] = b"filter-dataline|";
2023-03-19 20:32:11 +01:00
#[derive(Debug)]
pub struct Message {
2023-03-19 21:42:36 +01:00
session_id: String,
token: String,
2023-03-23 20:54:20 +01:00
content: Vec<u8>,
nb_lines: usize,
2023-03-19 20:32:11 +01:00
}
impl Message {
2023-03-19 21:42:36 +01:00
pub fn from_entry(entry: &Entry) -> Self {
let mut ret = Self {
session_id: entry.get_session_id().to_string(),
token: entry.get_token().to_string(),
2023-03-23 20:54:20 +01:00
content: Vec::with_capacity(crate::DEFAULT_MSG_SIZE),
nb_lines: 0,
2023-03-19 21:42:36 +01:00
};
if !entry.is_end_of_message() {
ret.append_line(entry.get_data());
2023-03-19 20:32:11 +01:00
}
2023-03-19 21:42:36 +01:00
ret
2023-03-19 20:32:11 +01:00
}
pub fn append_line(&mut self, line: &[u8]) {
2023-03-23 20:54:20 +01:00
self.nb_lines += 1;
if self.content.len() + line.len() > self.content.capacity() {
self.content.reserve(crate::DEFAULT_MSG_SIZE);
}
self.content.extend_from_slice(line);
match line.last() {
Some(&c) => {
if c != b'\r' {
self.content.push(b'\r');
}
}
None => {
self.content.push(b'\r');
}
}
self.content.push(b'\n');
2023-03-19 20:32:11 +01:00
}
2023-03-21 13:00:44 +01:00
pub fn nb_lines(&self) -> usize {
2023-03-23 20:54:20 +01:00
self.nb_lines
2023-03-21 13:00:44 +01:00
}
2023-03-19 20:32:11 +01:00
pub fn sign_and_return(&self) {
2023-03-25 15:42:46 +01:00
log::trace!("content:\n{}", crate::display_bytes!(&self.content));
match parse_mail(&self.content) {
Ok(parsed_msg) => {
log::trace!("mail parsed");
for h in parsed_msg.get_headers() {
log::trace!("{:?}", h);
}
match self.get_body() {
Some(body) => {
log::trace!("MailBody:\n{}", crate::display_bytes!(body));
// TODO: sign the message using DKIM
}
None => {
log::error!("{}: unable to find the body", self.session_id);
}
}
}
Err(e) => {
log::error!("{}: unable to parse message: {e}", self.session_id);
}
};
self.print_msg();
}
fn get_body(&self) -> Option<&[u8]> {
match self.content.windows(4).position(|w| w == b"\r\n\r\n") {
Some(body_index) => Some(&self.content[body_index + 4..]),
None => None,
}
}
fn print_msg(&self) {
2023-03-23 20:54:20 +01:00
let i = self.content.len() - 1;
for line in self.content[0..i].split(|&b| b == b'\n') {
2023-03-19 21:42:36 +01:00
self.print_line(line);
}
self.print_line(b".");
}
fn print_line(&self, line: &[u8]) {
let mut stdout = BufWriter::new(std::io::stdout());
stdout.write_all(RETURN_START).unwrap();
stdout.write_all(self.session_id.as_bytes()).unwrap();
stdout.write_all(RETURN_SEP).unwrap();
stdout.write_all(self.token.as_bytes()).unwrap();
stdout.write_all(RETURN_SEP).unwrap();
stdout.write_all(line).unwrap();
stdout.write_all(b"\n").unwrap();
2023-03-19 20:32:11 +01:00
}
}