diff --git a/server/src/bin/letterbox-server.rs b/server/src/bin/letterbox-server.rs index 3a8a996..410c26b 100644 --- a/server/src/bin/letterbox-server.rs +++ b/server/src/bin/letterbox-server.rs @@ -119,9 +119,10 @@ async fn download_attachment( } else { format!("id:{}", id) }; - info!("download attachment {mid} {idx}"); + info!("download attachment message id '{mid}' idx '{idx}'"); let idx: Vec<_> = idx .split('.') + .filter(|s| !s.is_empty()) .map(|s| s.parse().expect("not a usize")) .collect(); let attachment = attachment_bytes(&nm, &mid, &idx)?; diff --git a/server/src/email_extract.rs b/server/src/email_extract.rs index 680880c..8629c45 100644 --- a/server/src/email_extract.rs +++ b/server/src/email_extract.rs @@ -87,6 +87,7 @@ pub fn extract_body(m: &ParsedMail, part_addr: &mut Vec) -> Result extract_unhandled(m), APPLICATION_GZIP => extract_unhandled(m), + mt if mt.starts_with("application/") => Ok(Body::text("".to_string())), _ => extract_unhandled(m), }; if let Err(err) = ret { @@ -362,7 +363,7 @@ pub fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec) -> Result) -> Result parts.push(unhandled_html(MULTIPART_MIXED, mt)), + mt => { + if !mt.starts_with("application/") { + parts.push(unhandled_html(MULTIPART_MIXED, mt)) + } + } } part_addr.pop(); } @@ -500,7 +505,7 @@ pub fn extract_related(m: &ParsedMail, part_addr: &mut Vec) -> Result Option + Cop // get the bytes for serving attachments of HTTP pub fn extract_attachments(m: &ParsedMail, id: &str) -> Result, ServerError> { let mut attachments = Vec::new(); + + if m.ctype.mimetype.starts_with("application/") { + if let Some(attachment) = extract_attachment(m, id, &[]) { + attachments.push(attachment); + } + } + for (idx, sp) in m.subparts.iter().enumerate() { if let Some(attachment) = extract_attachment(sp, id, &[idx]) { // Filter out inline attachements, they're flattened into the body of the message. @@ -602,12 +614,30 @@ pub fn extract_attachment(m: &ParsedMail, id: &str, idx: &[usize]) -> Option filename, + (Some(filename), _) => Some(filename), // Use filename from Content-Type - (_, Some(Some(name))) => name, - // No known filename, assume it's not an attachment - _ => return None, + (_, Some(Some(name))) => Some(name), + // No known filename + _ => None, }; + + let filename = if let Some(fname) = filename { + fname + } else { + if m.ctype.mimetype.starts_with("application/") { + // Generate a default filename + format!( + "attachment-{}", + idx.iter() + .map(|i| i.to_string()) + .collect::>() + .join(".") + ) + } else { + return None; + } + }; + info!("filename {}", filename); // TODO: grab this from somewhere diff --git a/server/src/nm.rs b/server/src/nm.rs index ec57a4e..ef69c9a 100644 --- a/server/src/nm.rs +++ b/server/src/nm.rs @@ -479,6 +479,12 @@ pub fn attachment_bytes(nm: &Notmuch, id: &str, idx: &[usize]) -> Result