diff --git a/server/src/bin/server.rs b/server/src/bin/server.rs index cb2360b..6e5e096 100644 --- a/server/src/bin/server.rs +++ b/server/src/bin/server.rs @@ -75,7 +75,6 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for InlineAttachmentResponder { fn respond_to(self, _: &'r Request<'_>) -> rocket::response::Result<'o> { let mut resp = Response::build(); if let Some(filename) = self.0.filename { - info!("filename {:?}", filename); resp.header(Header::new( "Content-Disposition", format!(r#"inline; filename="{}""#, filename), @@ -97,7 +96,6 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for DownloadAttachmentResponder { fn respond_to(self, _: &'r Request<'_>) -> rocket::response::Result<'o> { let mut resp = Response::build(); if let Some(filename) = self.0.filename { - info!("filename {:?}", filename); resp.header(Header::new( "Content-Disposition", format!(r#"attachment; filename="{}""#, filename), diff --git a/server/src/graphql.rs b/server/src/graphql.rs index 2c3e945..3549298 100644 --- a/server/src/graphql.rs +++ b/server/src/graphql.rs @@ -348,7 +348,10 @@ impl QueryRoot { Body::Html(Html { html: format!( r#"

{}

"#, - sanitize_html(&linkify_html(&text))? + // Trim newlines to prevent excessive white space at the beginning/end of + // presenation. Leave tabs and spaces incase plain text attempts to center a + // header on the first line. + sanitize_html(&linkify_html(&text.trim_matches('\n')))? ), content_tree: if debug_content_tree { render_content_type_tree(&m) @@ -584,23 +587,25 @@ fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec) -> Result parts.push(Body::text(sp.get_body()?)), TEXT_HTML => parts.push(Body::html(sp.get_body()?)), IMAGE_JPEG | IMAGE_PNG => { - let filename = { - let pcd = sp.get_content_disposition(); - pcd.params - .get("filename") - .map(|s| s.clone()) - .unwrap_or("".to_string()) - }; - parts.push(Body::html(format!( - r#""#, - part_addr[0], - part_addr - .iter() - .skip(1) - .map(|i| i.to_string()) - .collect::>() - .join(".") - ))) + let pcd = sp.get_content_disposition(); + let filename = pcd + .params + .get("filename") + .map(|s| s.clone()) + .unwrap_or("".to_string()); + // Only add inline images, attachments are handled as an attribute of the top level Message and rendered separate client-side. + if pcd.disposition == mailparse::DispositionType::Inline { + parts.push(Body::html(format!( + r#""#, + part_addr[0], + part_addr + .iter() + .skip(1) + .map(|i| i.to_string()) + .collect::>() + .join(".") + ))); + } } _ => (), } @@ -613,10 +618,15 @@ fn flatten_body_parts(parts: &[Body]) -> Body { let html = parts .iter() .map(|p| match p { - Body::PlainText(PlainText { text, .. }) => format!( - r#"

{}

"#, - linkify_html(&text) - ), + Body::PlainText(PlainText { text, .. }) => { + format!( + r#"

{}

"#, + // Trim newlines to prevent excessive white space at the beginning/end of + // presenation. Leave tabs and spaces incase plain text attempts to center a + // header on the first line. + linkify_html(&text.trim_matches('\n')) + ) + } Body::Html(Html { html, .. }) => html.clone(), Body::UnhandledContentType(UnhandledContentType { text }) => { format!(r#"

{text}

"#) @@ -683,7 +693,10 @@ fn extract_attachments(m: &ParsedMail, id: &str) -> Result, Erro let mut attachments = Vec::new(); for (idx, sp) in m.subparts.iter().enumerate() { if let Some(attachment) = extract_attachment(sp, id, &[idx]) { - attachments.push(attachment); + // Filter out inline attachements, they're flattened into the body of the message. + if attachment.disposition == DispositionType::Attachment { + attachments.push(attachment); + } } } Ok(attachments) @@ -865,7 +878,6 @@ pub fn attachment_bytes(nm: &Notmuch, id: &str, idx: &[usize]) -> Result