diff --git a/src/main.rs b/src/main.rs index 5379a9f..91b1b71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,14 @@ fn main() -> Result<(), anyhow::Error> { println!("Date: {}", date); } println!("---"); - print!("{}", message.body()?.text.unwrap_or_default()); + let parts = message.parts()?; + println!("{}", parts.text.unwrap_or_default()); + for (i, attachment) in parts.attachments.iter().enumerate() { + println!( + "[{}] {}", + i, + &attachment.filename.as_deref().unwrap_or("") + ); + } Ok(()) } diff --git a/src/parsing.rs b/src/parsing.rs index 7fbeb05..95c24ed 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -1,33 +1,53 @@ use mailparse::{DispositionType, MailHeaderMap, ParsedMail}; #[derive(PartialEq, Eq, Debug, Default)] -pub struct Body { +pub struct Parts { pub text: Option, pub html: Option, + pub attachments: Vec, +} + +#[derive(PartialEq, Eq, Debug)] +pub struct Attachment { + pub filename: Option, + pub ctype: mime::Mime, + pub body: Vec, +} + +impl Attachment { + fn from_part(part: &ParsedMail) -> anyhow::Result { + let content_disposition = dbg!(part.get_content_disposition()); + Ok(Self { + filename: content_disposition.params.get("filename").cloned(), + ctype: part.ctype.mimetype.parse()?, + body: part.get_body_raw()?, + }) + } } pub trait ParsedMailExt { fn is_attachment(&self) -> bool; fn subject(&self) -> Option; fn date(&self) -> Result>, anyhow::Error>; - fn body(&self) -> Result; + fn parts(&self) -> Result; } -fn find_body(message: &ParsedMail, body: &mut Body) -> Result<(), anyhow::Error> { - if message.is_attachment() { - return Ok(()); - } - let mimetype: mime::Mime = message.ctype.mimetype.parse()?; - if mimetype == mime::TEXT_PLAIN { - body.text.get_or_insert(message.get_body()?); - } else if mimetype == mime::TEXT_HTML { - body.html.get_or_insert(message.get_body()?); - } - for subpart in &message.subparts { - find_body(subpart, body)?; - if body.text.is_some() && body.html.is_some() { +fn find_body(message: &ParsedMail, parts: &mut Parts) -> Result<(), anyhow::Error> { + if !message.subparts.is_empty() { + for subpart in &message.subparts { + find_body(subpart, parts)?; + } + } else { + if message.is_attachment() { + parts.attachments.push(Attachment::from_part(message)?); return Ok(()); } + let mimetype: mime::Mime = message.ctype.mimetype.parse()?; + if mimetype == mime::TEXT_PLAIN { + parts.text.get_or_insert(message.get_body()?); + } else if mimetype == mime::TEXT_HTML { + parts.html.get_or_insert(message.get_body()?); + } } Ok(()) } @@ -49,8 +69,8 @@ impl<'a> ParsedMailExt for ParsedMail<'a> { Ok(date) } - fn body(&self) -> Result { - let mut body = Body::default(); + fn parts(&self) -> Result { + let mut body = Parts::default(); find_body(self, &mut body)?; Ok(body) } @@ -152,10 +172,11 @@ TsSbamFrw6EgcMWZw61sb2hhLgo= ) ); assert_eq!( - message.body()?, - Body { + message.parts()?, + Parts { text: Some("Prostý text.".to_string()), html: None, + ..Default::default() }, ); Ok(()) @@ -174,10 +195,11 @@ TsSbamFrw6EgcMWZw61sb2hhLgo= ) ); assert_eq!( - message.body()?, - Body { + message.parts()?, + Parts { text: Some("Prostý text.".to_string()), html: Some("Tučný HTML text".to_string()), + ..Default::default() }, ); Ok(()) @@ -199,10 +221,15 @@ TsSbamFrw6EgcMWZw61sb2hhLgo= ) ); assert_eq!( - message.body()?, - Body { + message.parts()?, + Parts { text: Some("Prostý text.".to_string()), html: Some("Tučný HTML text".to_string()), + attachments: vec![Attachment { + filename: Some("test.txt".to_string()), + ctype: mime::TEXT_PLAIN, + body: "Nějaká příloha.\n".into(), + }] }, ); Ok(())