server: handle application/* as an attachment

This commit is contained in:
2025-08-18 12:11:31 -07:00
parent 834e873862
commit 574de65c35
3 changed files with 45 additions and 8 deletions

View File

@@ -87,6 +87,7 @@ pub fn extract_body(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body,
// APPLICATION_ZIP and APPLICATION_GZIP are handled in the thread function
APPLICATION_ZIP => 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<String>) -> Result<Body
.subparts
.iter()
.map(|sp| sp.ctype.mimetype.as_str())
.filter(|mt| !handled_types.contains(mt))
.filter(|mt| !handled_types.contains(mt) && !mt.starts_with("application/"))
.collect();
unhandled_types.sort();
if !unhandled_types.is_empty() {
@@ -434,7 +435,11 @@ pub fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body
)));
}
}
mt => 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<String>) -> Result<Bo
.subparts
.iter()
.map(|sp| sp.ctype.mimetype.as_str())
.filter(|mt| !handled_types.contains(mt))
.filter(|mt| !handled_types.contains(mt) && !mt.starts_with("application/"))
.collect();
unhandled_types.sort();
if !unhandled_types.is_empty() {
@@ -580,6 +585,13 @@ pub fn walk_attachments_inner<T, F: Fn(&ParsedMail, &[usize]) -> Option<T> + Cop
// get the bytes for serving attachments of HTTP
pub fn extract_attachments(m: &ParsedMail, id: &str) -> Result<Vec<Attachment>, 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<Att
pct.map(|pct| pct.params.get("name").map(|f| f.clone())),
) {
// Use filename from Content-Disposition
(Some(filename), _) => 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::<Vec<_>>()
.join(".")
)
} else {
return None;
}
};
info!("filename {}", filename);
// TODO: grab this from somewhere