server: handle application/* as an attachment
This commit is contained in:
parent
834e873862
commit
574de65c35
@ -119,9 +119,10 @@ async fn download_attachment(
|
|||||||
} else {
|
} else {
|
||||||
format!("id:{}", id)
|
format!("id:{}", id)
|
||||||
};
|
};
|
||||||
info!("download attachment {mid} {idx}");
|
info!("download attachment message id '{mid}' idx '{idx}'");
|
||||||
let idx: Vec<_> = idx
|
let idx: Vec<_> = idx
|
||||||
.split('.')
|
.split('.')
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
.map(|s| s.parse().expect("not a usize"))
|
.map(|s| s.parse().expect("not a usize"))
|
||||||
.collect();
|
.collect();
|
||||||
let attachment = attachment_bytes(&nm, &mid, &idx)?;
|
let attachment = attachment_bytes(&nm, &mid, &idx)?;
|
||||||
|
|||||||
@ -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 and APPLICATION_GZIP are handled in the thread function
|
||||||
APPLICATION_ZIP => extract_unhandled(m),
|
APPLICATION_ZIP => extract_unhandled(m),
|
||||||
APPLICATION_GZIP => extract_unhandled(m),
|
APPLICATION_GZIP => extract_unhandled(m),
|
||||||
|
mt if mt.starts_with("application/") => Ok(Body::text("".to_string())),
|
||||||
_ => extract_unhandled(m),
|
_ => extract_unhandled(m),
|
||||||
};
|
};
|
||||||
if let Err(err) = ret {
|
if let Err(err) = ret {
|
||||||
@ -362,7 +363,7 @@ pub fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body
|
|||||||
.subparts
|
.subparts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sp| sp.ctype.mimetype.as_str())
|
.map(|sp| sp.ctype.mimetype.as_str())
|
||||||
.filter(|mt| !handled_types.contains(mt))
|
.filter(|mt| !handled_types.contains(mt) && !mt.starts_with("application/"))
|
||||||
.collect();
|
.collect();
|
||||||
unhandled_types.sort();
|
unhandled_types.sort();
|
||||||
if !unhandled_types.is_empty() {
|
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();
|
part_addr.pop();
|
||||||
}
|
}
|
||||||
@ -500,7 +505,7 @@ pub fn extract_related(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Bo
|
|||||||
.subparts
|
.subparts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sp| sp.ctype.mimetype.as_str())
|
.map(|sp| sp.ctype.mimetype.as_str())
|
||||||
.filter(|mt| !handled_types.contains(mt))
|
.filter(|mt| !handled_types.contains(mt) && !mt.starts_with("application/"))
|
||||||
.collect();
|
.collect();
|
||||||
unhandled_types.sort();
|
unhandled_types.sort();
|
||||||
if !unhandled_types.is_empty() {
|
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
|
// get the bytes for serving attachments of HTTP
|
||||||
pub fn extract_attachments(m: &ParsedMail, id: &str) -> Result<Vec<Attachment>, ServerError> {
|
pub fn extract_attachments(m: &ParsedMail, id: &str) -> Result<Vec<Attachment>, ServerError> {
|
||||||
let mut attachments = Vec::new();
|
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() {
|
for (idx, sp) in m.subparts.iter().enumerate() {
|
||||||
if let Some(attachment) = extract_attachment(sp, id, &[idx]) {
|
if let Some(attachment) = extract_attachment(sp, id, &[idx]) {
|
||||||
// Filter out inline attachements, they're flattened into the body of the message.
|
// 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())),
|
pct.map(|pct| pct.params.get("name").map(|f| f.clone())),
|
||||||
) {
|
) {
|
||||||
// Use filename from Content-Disposition
|
// Use filename from Content-Disposition
|
||||||
(Some(filename), _) => filename,
|
(Some(filename), _) => Some(filename),
|
||||||
// Use filename from Content-Type
|
// Use filename from Content-Type
|
||||||
(_, Some(Some(name))) => name,
|
(_, Some(Some(name))) => Some(name),
|
||||||
// No known filename, assume it's not an attachment
|
// No known filename
|
||||||
_ => return None,
|
_ => 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);
|
info!("filename {}", filename);
|
||||||
|
|
||||||
// TODO: grab this from somewhere
|
// TODO: grab this from somewhere
|
||||||
|
|||||||
@ -479,6 +479,12 @@ pub fn attachment_bytes(nm: &Notmuch, id: &str, idx: &[usize]) -> Result<Attachm
|
|||||||
let file = File::open(&path)?;
|
let file = File::open(&path)?;
|
||||||
let mmap = unsafe { MmapOptions::new().map(&file)? };
|
let mmap = unsafe { MmapOptions::new().map(&file)? };
|
||||||
let m = parse_mail(&mmap)?;
|
let m = parse_mail(&mmap)?;
|
||||||
|
if idx.is_empty() {
|
||||||
|
let Some(attachment) = extract_attachment(&m, id, &[]) else {
|
||||||
|
return Err(ServerError::PartNotFound);
|
||||||
|
};
|
||||||
|
return Ok(attachment);
|
||||||
|
}
|
||||||
if let Some(attachment) = walk_attachments(&m, |sp, cur_idx| {
|
if let Some(attachment) = walk_attachments(&m, |sp, cur_idx| {
|
||||||
if cur_idx == idx {
|
if cur_idx == idx {
|
||||||
let attachment = extract_attachment(&sp, id, idx).unwrap_or(Attachment {
|
let attachment = extract_attachment(&sp, id, idx).unwrap_or(Attachment {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user