2023-03-26 16:07:49 +02:00
|
|
|
use crate::config::Config;
|
2023-03-19 21:42:36 +01:00
|
|
|
use crate::entry::Entry;
|
2023-03-27 22:46:17 +02:00
|
|
|
use crate::parsed_message::ParsedMessage;
|
2023-04-10 13:09:56 +02:00
|
|
|
use anyhow::Result;
|
2023-04-09 11:07:16 +02:00
|
|
|
use tokio::io::{AsyncWriteExt, BufWriter};
|
2023-03-19 21:42:36 +01:00
|
|
|
|
|
|
|
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-04-09 17:54:07 +02:00
|
|
|
pub async fn sign_and_return(&self, cnf: &Config) -> String {
|
2023-03-27 22:46:17 +02:00
|
|
|
log::trace!("content: {}", crate::display_bytes!(&self.content));
|
|
|
|
match ParsedMessage::from_bytes(&self.content) {
|
2023-03-25 15:42:46 +01:00
|
|
|
Ok(parsed_msg) => {
|
|
|
|
log::trace!("mail parsed");
|
2023-03-27 22:46:17 +02:00
|
|
|
for h in &parsed_msg.headers {
|
|
|
|
log::trace!(
|
|
|
|
"ParsedMessage: header: raw: {}",
|
|
|
|
crate::display_bytes!(h.raw)
|
|
|
|
);
|
|
|
|
log::trace!(
|
|
|
|
"ParsedMessage: header: name: {}",
|
|
|
|
crate::display_bytes!(h.name)
|
|
|
|
);
|
|
|
|
log::trace!(
|
|
|
|
"ParsedMessage: header: value: {}",
|
|
|
|
crate::display_bytes!(h.value)
|
|
|
|
);
|
2023-03-25 15:42:46 +01:00
|
|
|
}
|
2023-03-27 22:46:17 +02:00
|
|
|
log::trace!(
|
|
|
|
"ParsedMessage: body: {}",
|
|
|
|
crate::display_bytes!(parsed_msg.body)
|
|
|
|
);
|
|
|
|
// TODO: sign the message using DKIM
|
2023-03-25 15:42:46 +01:00
|
|
|
}
|
2023-04-10 16:29:36 +02:00
|
|
|
Err(err) => {
|
|
|
|
log::error!("{msg_id}: unable to parse message: {err}");
|
2023-03-25 15:42:46 +01:00
|
|
|
}
|
|
|
|
}
|
2023-04-10 13:09:56 +02:00
|
|
|
if let Err(err) = self.print_msg().await {
|
|
|
|
log::error!("unable to write message: {err}");
|
|
|
|
}
|
2023-04-09 17:54:07 +02:00
|
|
|
get_msg_id(&self.session_id, &self.token)
|
2023-03-25 15:42:46 +01:00
|
|
|
}
|
|
|
|
|
2023-04-10 13:09:56 +02:00
|
|
|
async fn print_msg(&self) -> Result<()> {
|
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-04-10 13:09:56 +02:00
|
|
|
self.print_line(line).await?;
|
2023-03-19 21:42:36 +01:00
|
|
|
}
|
2023-04-10 13:09:56 +02:00
|
|
|
self.print_line(b".").await?;
|
|
|
|
Ok(())
|
2023-03-19 21:42:36 +01:00
|
|
|
}
|
|
|
|
|
2023-04-10 13:09:56 +02:00
|
|
|
async fn print_line(&self, line: &[u8]) -> Result<()> {
|
2023-04-09 11:07:16 +02:00
|
|
|
let mut stdout = BufWriter::new(tokio::io::stdout());
|
2023-04-10 13:09:56 +02:00
|
|
|
stdout.write_all(RETURN_START).await?;
|
|
|
|
stdout.write_all(self.session_id.as_bytes()).await?;
|
|
|
|
stdout.write_all(RETURN_SEP).await?;
|
|
|
|
stdout.write_all(self.token.as_bytes()).await?;
|
|
|
|
stdout.write_all(RETURN_SEP).await?;
|
|
|
|
stdout.write_all(line).await?;
|
|
|
|
stdout.write_all(b"\n").await?;
|
|
|
|
stdout.flush().await?;
|
|
|
|
Ok(())
|
2023-03-19 20:32:11 +01:00
|
|
|
}
|
|
|
|
}
|
2023-04-09 15:13:18 +02:00
|
|
|
|
|
|
|
pub fn get_msg_id(session_id: &str, token: &str) -> String {
|
|
|
|
format!("{session_id}.{token}")
|
|
|
|
}
|