melib/email/compose: set attachment status
Set Content-Disposition: attachment to, well, attachments.memfd
parent
e8f3b6aa24
commit
83bee279e6
|
@ -972,7 +972,6 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
"uuid",
|
||||
"xdg",
|
||||
"xdg-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1006,6 +1005,7 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
"uuid",
|
||||
"xdg",
|
||||
"xdg-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -39,7 +39,6 @@ serde_json = "1.0"
|
|||
toml = { version = "0.5.6", features = ["preserve_order", ] }
|
||||
indexmap = { version = "^1.5", features = ["serde-1", ] }
|
||||
linkify = "0.4.0"
|
||||
xdg-utils = "0.3.0"
|
||||
notify = "4.0.1" # >:c
|
||||
notify-rust = { version = "^4", optional = true }
|
||||
termion = "1.5.1"
|
||||
|
|
|
@ -48,6 +48,7 @@ smol = "0.1.18"
|
|||
async-stream = "0.2.1"
|
||||
base64 = { version = "0.12.3", optional = true }
|
||||
flate2 = { version = "1.0.16", optional = true }
|
||||
xdg-utils = "0.3.0"
|
||||
|
||||
[features]
|
||||
default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard", "sqlite3", "smtp", "deflate_compression"]
|
||||
|
|
|
@ -30,6 +30,7 @@ use std::ffi::OsStr;
|
|||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
use xdg_utils::query_mime_info;
|
||||
|
||||
pub mod mime;
|
||||
pub mod random;
|
||||
|
@ -244,21 +245,25 @@ impl Draft {
|
|||
}
|
||||
for (k, v) in self.headers.deref() {
|
||||
if v.is_ascii() {
|
||||
ret.extend(format!("{}: {}\n", k, v).chars());
|
||||
ret.extend(format!("{}: {}\r\n", k, v).chars());
|
||||
} else {
|
||||
ret.extend(format!("{}: {}\n", k, mime::encode_header(v)).chars());
|
||||
ret.extend(format!("{}: {}\r\n", k, mime::encode_header(v)).chars());
|
||||
}
|
||||
}
|
||||
ret.push_str("MIME-Version: 1.0\n");
|
||||
ret.push_str("MIME-Version: 1.0\r\n");
|
||||
|
||||
if self.attachments.is_empty() {
|
||||
let content_type: ContentType = Default::default();
|
||||
let content_transfer_encoding: ContentTransferEncoding = ContentTransferEncoding::_8Bit;
|
||||
ret.extend(format!("Content-Type: {}; charset=\"utf-8\"\n", content_type).chars());
|
||||
ret.extend(format!("Content-Type: {}; charset=\"utf-8\"\r\n", content_type).chars());
|
||||
ret.extend(
|
||||
format!("Content-Transfer-Encoding: {}\n", content_transfer_encoding).chars(),
|
||||
format!(
|
||||
"Content-Transfer-Encoding: {}\r\n",
|
||||
content_transfer_encoding
|
||||
)
|
||||
.chars(),
|
||||
);
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
ret.push_str(&self.body);
|
||||
} else if self.body.is_empty() && self.attachments.len() == 1 {
|
||||
let attachment = std::mem::replace(&mut self.attachments, Vec::new()).remove(0);
|
||||
|
@ -283,18 +288,18 @@ fn build_multipart(ret: &mut String, kind: MultipartType, parts: Vec<AttachmentB
|
|||
let boundary = ContentType::make_boundary(&parts);
|
||||
ret.extend(
|
||||
format!(
|
||||
"Content-Type: {}; charset=\"utf-8\"; boundary=\"{}\"\n",
|
||||
"Content-Type: {}; charset=\"utf-8\"; boundary=\"{}\"\r\n",
|
||||
kind, boundary
|
||||
)
|
||||
.chars(),
|
||||
);
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
/* rfc1341 */
|
||||
ret.push_str("This is a MIME formatted message with attachments. Use a MIME-compliant client to view it properly.\n");
|
||||
ret.push_str("This is a MIME formatted message with attachments. Use a MIME-compliant client to view it properly.\r\n");
|
||||
for sub in parts {
|
||||
ret.push_str("--");
|
||||
ret.push_str(&boundary);
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
print_attachment(ret, &kind, sub);
|
||||
}
|
||||
ret.push_str("--");
|
||||
|
@ -310,13 +315,13 @@ fn print_attachment(ret: &mut String, kind: &MultipartType, a: AttachmentBuilder
|
|||
charset: Charset::UTF8,
|
||||
parameters: ref v,
|
||||
} if v.is_empty() => {
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
ret.push_str(&String::from_utf8_lossy(a.raw()));
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
}
|
||||
Text { .. } => {
|
||||
ret.push_str(&a.build().into_raw());
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
}
|
||||
Multipart {
|
||||
boundary: _boundary,
|
||||
|
@ -331,13 +336,14 @@ fn print_attachment(ret: &mut String, kind: &MultipartType, a: AttachmentBuilder
|
|||
.map(|s| s.into())
|
||||
.collect::<Vec<AttachmentBuilder>>(),
|
||||
);
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
}
|
||||
MessageRfc822 | PGPSignature => {
|
||||
ret.push_str(&format!("Content-Type: {}; charset=\"utf-8\"\n", kind));
|
||||
ret.push('\n');
|
||||
ret.push_str(&format!("Content-Type: {}; charset=\"utf-8\"\r\n", kind));
|
||||
ret.push_str("Content-Disposition: attachment\r\n");
|
||||
ret.push_str("\r\n");
|
||||
ret.push_str(&String::from_utf8_lossy(a.raw()));
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
}
|
||||
_ => {
|
||||
let content_transfer_encoding: ContentTransferEncoding =
|
||||
|
@ -345,7 +351,7 @@ fn print_attachment(ret: &mut String, kind: &MultipartType, a: AttachmentBuilder
|
|||
if let Some(name) = a.content_type().name() {
|
||||
ret.extend(
|
||||
format!(
|
||||
"Content-Type: {}; name=\"{}\"; charset=\"utf-8\"\n",
|
||||
"Content-Type: {}; name=\"{}\"; charset=\"utf-8\"\r\n",
|
||||
a.content_type(),
|
||||
name
|
||||
)
|
||||
|
@ -353,15 +359,20 @@ fn print_attachment(ret: &mut String, kind: &MultipartType, a: AttachmentBuilder
|
|||
);
|
||||
} else {
|
||||
ret.extend(
|
||||
format!("Content-Type: {}; charset=\"utf-8\"\n", a.content_type()).chars(),
|
||||
format!("Content-Type: {}; charset=\"utf-8\"\r\n", a.content_type()).chars(),
|
||||
);
|
||||
}
|
||||
ret.push_str("Content-Disposition: attachment\r\n");
|
||||
ret.extend(
|
||||
format!("Content-Transfer-Encoding: {}\n", content_transfer_encoding).chars(),
|
||||
format!(
|
||||
"Content-Transfer-Encoding: {}\r\n",
|
||||
content_transfer_encoding
|
||||
)
|
||||
.chars(),
|
||||
);
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
ret.push_str(&BASE64_MIME.encode(a.raw()).trim());
|
||||
ret.push('\n');
|
||||
ret.push_str("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,12 +439,17 @@ where
|
|||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents)?;
|
||||
let mut attachment = AttachmentBuilder::default();
|
||||
|
||||
attachment
|
||||
.set_raw(contents)
|
||||
.set_body_to_raw()
|
||||
.set_content_type(ContentType::Other {
|
||||
name: path.file_name().map(|s| s.to_string_lossy().into()),
|
||||
tag: b"application/octet-stream".to_vec(),
|
||||
tag: if let Ok(mime_type) = query_mime_info(&path) {
|
||||
mime_type
|
||||
} else {
|
||||
b"application/octet-stream".to_vec()
|
||||
},
|
||||
});
|
||||
|
||||
Ok(attachment)
|
||||
|
|
|
@ -138,6 +138,7 @@ pub extern crate indexmap;
|
|||
pub extern crate smallvec;
|
||||
pub extern crate smol;
|
||||
pub extern crate uuid;
|
||||
pub extern crate xdg_utils;
|
||||
|
||||
pub use shellexpand::ShellExpandTrait;
|
||||
pub mod shellexpand {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
use std::alloc::System;
|
||||
use std::collections::VecDeque;
|
||||
use std::path::PathBuf;
|
||||
extern crate xdg_utils;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate linkify;
|
||||
|
|
|
@ -32,7 +32,6 @@ use nix::sys::wait::WaitStatus;
|
|||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use xdg_utils::query_mime_info;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Cursor {
|
||||
|
@ -1243,7 +1242,7 @@ impl Component for Composer {
|
|||
.wait_with_output()
|
||||
.expect("failed to launch command")
|
||||
.stdout;
|
||||
let mut attachment =
|
||||
let attachment =
|
||||
match melib::email::compose::attachment_from_file(f.path()) {
|
||||
Ok(a) => a,
|
||||
Err(err) => {
|
||||
|
@ -1258,14 +1257,6 @@ impl Component for Composer {
|
|||
return true;
|
||||
}
|
||||
};
|
||||
if let Ok(mime_type) = query_mime_info(f.path()) {
|
||||
match attachment.content_type {
|
||||
ContentType::Other { ref mut tag, .. } => {
|
||||
*tag = mime_type;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.draft.attachments_mut().push(attachment);
|
||||
self.dirty = true;
|
||||
return true;
|
||||
|
@ -1281,7 +1272,7 @@ impl Component for Composer {
|
|||
}
|
||||
}
|
||||
Action::Compose(ComposeAction::AddAttachment(ref path)) => {
|
||||
let mut attachment = match melib::email::compose::attachment_from_file(path) {
|
||||
let attachment = match melib::email::compose::attachment_from_file(path) {
|
||||
Ok(a) => a,
|
||||
Err(err) => {
|
||||
context.replies.push_back(UIEvent::Notification(
|
||||
|
@ -1293,14 +1284,6 @@ impl Component for Composer {
|
|||
return true;
|
||||
}
|
||||
};
|
||||
if let Ok(mime_type) = query_mime_info(path) {
|
||||
match attachment.content_type {
|
||||
ContentType::Other { ref mut tag, .. } => {
|
||||
*tag = mime_type;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.draft.attachments_mut().push(attachment);
|
||||
self.dirty = true;
|
||||
return true;
|
||||
|
|
|
@ -12,6 +12,7 @@ This is a MIME formatted message with attachments. Use a MIME-compliant client t
|
|||
hello world.
|
||||
--bzz_bzz__bzz__
|
||||
Content-Type: image/gif; name="test_image.gif"; charset="utf-8"
|
||||
Content-Disposition: attachment
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
R0lGODdhKAAXAOfZAAABzAADzQAEzgQFtBEAxAAGxBcAxwALvRcFwAAPwBcLugATuQEUuxoNuxYQ
|
|
@ -1,20 +1,11 @@
|
|||
use melib;
|
||||
use melib::email::Draft;
|
||||
use xdg_utils::query_mime_info;
|
||||
|
||||
#[test]
|
||||
fn build_draft() {
|
||||
let mut new_draft = Draft::default();
|
||||
let mut attachment = melib::email::attachment_from_file(&"./tests/test_image.gif")
|
||||
let attachment = melib::email::attachment_from_file(&"./tests/test_image.gif")
|
||||
.expect("Could not open test_image.gif.");
|
||||
if let Ok(mime_type) = query_mime_info("./tests/test_image.gif") {
|
||||
match attachment.content_type {
|
||||
melib::email::attachment_types::ContentType::Other { ref mut tag, .. } => {
|
||||
*tag = mime_type;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
new_draft.headers_mut().remove("User-Agent");
|
||||
new_draft.headers_mut().remove("Date");
|
||||
|
||||
|
@ -27,5 +18,5 @@ fn build_draft() {
|
|||
let boundary_str = &boundary["bzz_bzz__bzz__".len()..];
|
||||
|
||||
let raw = raw.replace(boundary_str, "");
|
||||
assert_eq!(include_str!("generated.mail"), &raw);
|
||||
assert_eq!(include_str!("generated_email.eml"), &raw);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue