use crate::{implementation::basic_parser::BasicParser, Mail, MailParser, RawBody};
#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub struct MessageBody {
raw: RawBody,
parsed: Option<Mail>,
}
impl From<either::Either<RawBody, Mail>> for MessageBody {
fn from(this: either::Either<RawBody, Mail>) -> Self {
match this {
either::Left(raw) => Self { raw, parsed: None },
either::Right(_parsed) => todo!(),
}
}
}
impl TryFrom<&str> for MessageBody {
type Error = anyhow::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut bytes = vec![];
let splitted = value.split("\r\n").collect::<Vec<_>>();
for (idx, mut line) in splitted.iter().map(|l| l.as_bytes().to_vec()).enumerate() {
bytes.push({
if idx != splitted.len() - 1 {
line.extend_from_slice(b"\r\n");
}
line
});
}
Ok(Self {
raw: BasicParser::default().parse_sync(bytes)?.unwrap_left(),
parsed: None,
})
}
}
impl MessageBody {
#[must_use]
pub fn new(headers: Vec<String>, body: String) -> Self {
Self {
raw: RawBody::new(headers, body),
parsed: None,
}
}
#[must_use]
pub const fn inner(&self) -> &RawBody {
&self.raw
}
#[must_use]
pub const fn get_parsed(&self) -> &Option<Mail> {
&self.parsed
}
#[must_use]
pub fn get_header(&self, name: &str) -> Option<String> {
let header = self.parsed.as_ref().map_or_else(
|| self.raw.get_header(name, false),
|p| p.get_header(name).map(str::to_string),
);
header
.as_ref()
.map(|header| header.strip_suffix("\r\n").unwrap_or(header))
.map(str::to_string)
}
#[must_use]
pub fn count_header(&self, name: &str) -> usize {
self.parsed
.as_ref()
.map_or_else(|| self.raw.count_header(name), |p| p.count_header(name))
}
pub fn set_header(&mut self, name: &str, value: &str) {
if let Some(parsed) = &mut self.parsed {
parsed.set_header(name, &format!("{value}\r\n"));
}
self.raw.set_header(name, &format!("{value}\r\n"));
}
pub fn rename_header(&mut self, old: &str, new: &str) {
if let Some(parsed) = &mut self.parsed {
parsed.rename_header(old, new);
}
self.raw.rename_header(old, new);
}
pub fn append_header(&mut self, name: &str, value: &str) {
if let Some(parsed) = &mut self.parsed {
parsed.push_headers([(name.to_string(), value.to_string())]);
}
self.raw.add_header(name, &format!("{value}\r\n"));
}
pub fn prepend_header(&mut self, name: &str, value: &str) {
if let Some(parsed) = &mut self.parsed {
parsed.prepend_headers([(name.to_string(), value.to_string())]);
}
self.raw.prepend_header([format!("{name}: {value}\r\n")]);
}
pub fn remove_header(&mut self, name: &str) -> bool {
if let Some(parsed) = &mut self.parsed {
parsed.remove_header(name);
}
self.raw.remove_header(name)
}
pub fn parse<P: MailParser>(&mut self) -> anyhow::Result<()> {
self.parsed = Some(
P::default()
.convert(&self.raw)?
.ok_or_else(|| anyhow::anyhow!("the parser did not produced a `Mail` part."))?,
);
Ok(())
}
pub fn parsed<P: MailParser>(&mut self) -> anyhow::Result<&mut Mail> {
if self.parsed.is_some() {
return Ok(self.parsed.as_mut().expect(""));
}
self.parse::<P>()?;
self.parsed::<P>()
}
}