diff options
author | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-09-28 10:46:49 +0300 |
---|---|---|
committer | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-09-28 12:19:22 +0300 |
commit | e35a93336a2c0ce081cd05f64986c6f6cdc59077 (patch) | |
tree | e36c7e99b24f7826980d5eec590551c68713d734 /melib | |
parent | 963fdd157503966d4ec16a9b175be6b2caa9fba6 (diff) |
Add GPG signing and sig verifying
Diffstat (limited to 'melib')
-rw-r--r-- | melib/src/email/attachment_types.rs | 23 | ||||
-rw-r--r-- | melib/src/email/attachments.rs | 84 | ||||
-rw-r--r-- | melib/src/email/compose.rs | 40 |
3 files changed, 123 insertions, 24 deletions
diff --git a/melib/src/email/attachment_types.rs b/melib/src/email/attachment_types.rs index f5287df6..8c3b8f49 100644 --- a/melib/src/email/attachment_types.rs +++ b/melib/src/email/attachment_types.rs @@ -74,6 +74,27 @@ impl<'a> From<&'a [u8]> for Charset { } } +impl Display for Charset { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + match self { + Charset::Ascii => write!(f, "us-ascii"), + Charset::UTF8 => write!(f, "utf-8"), + Charset::UTF16 => write!(f, "utf-16"), + Charset::ISO8859_1 => write!(f, "iso-8859-1"), + Charset::ISO8859_2 => write!(f, "iso-8859-2"), + Charset::ISO8859_7 => write!(f, "iso-8859-7"), + Charset::ISO8859_15 => write!(f, "iso-8859-15"), + Charset::Windows1251 => write!(f, "windows-1251"), + Charset::Windows1252 => write!(f, "windows-1252"), + Charset::Windows1253 => write!(f, "windows-1253"), + Charset::GBK => write!(f, "GBK"), + Charset::GB2312 => write!(f, "gb2312"), + Charset::BIG5 => write!(f, "BIG5"), + Charset::ISO2022JP => write!(f, "ISO-2022-JP"), + } + } +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum MultipartType { Mixed, @@ -264,7 +285,7 @@ pub enum ContentTransferEncoding { impl Default for ContentTransferEncoding { fn default() -> Self { - ContentTransferEncoding::_7Bit + ContentTransferEncoding::_8Bit } } diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs index bbe9cc38..953f6f57 100644 --- a/melib/src/email/attachments.rs +++ b/melib/src/email/attachments.rs @@ -273,6 +273,23 @@ impl From<Attachment> for AttachmentBuilder { } } +impl From<AttachmentBuilder> for Attachment { + fn from(val: AttachmentBuilder) -> Self { + let AttachmentBuilder { + content_type, + content_transfer_encoding, + raw, + body, + } = val; + Attachment { + content_type, + content_transfer_encoding, + raw, + body, + } + } +} + /// Immutable attachment type. #[derive(Clone, Serialize, Deserialize, PartialEq)] pub struct Attachment { @@ -546,6 +563,73 @@ impl Attachment { _ => false, } } + + pub fn into_raw(&self) -> String { + let mut ret = String::with_capacity(2 * self.raw.len()); + fn into_raw_helper(a: &Attachment, ret: &mut String) { + ret.extend( + format!( + "Content-Transfer-Encoding: {}\n", + a.content_transfer_encoding + ) + .chars(), + ); + match &a.content_type { + ContentType::Text { kind: _, charset } => { + ret.extend( + format!("Content-Type: {}; charset={}\n\n", a.content_type, charset) + .chars(), + ); + ret.extend(String::from_utf8_lossy(a.body()).chars()); + } + ContentType::Multipart { + boundary, + kind, + parts, + } => { + let boundary = String::from_utf8_lossy(boundary); + ret.extend(format!("Content-Type: {}; boundary={}", kind, boundary).chars()); + if *kind == MultipartType::Signed { + ret.extend( + "; micalg=pgp-sha512; protocol=\"application/pgp-signature\"".chars(), + ); + } + ret.push('\n'); + + let boundary_start = format!("\n--{}\n", boundary); + for p in parts { + ret.extend(boundary_start.chars()); + into_raw_helper(p, ret); + } + ret.extend(format!("--{}--\n\n", boundary).chars()); + } + ContentType::MessageRfc822 => { + ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars()); + ret.extend(String::from_utf8_lossy(a.body()).chars()); + } + ContentType::PGPSignature => { + ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars()); + ret.extend(String::from_utf8_lossy(a.body()).chars()); + } + ContentType::OctetStream { ref name } => { + if let Some(name) = name { + ret.extend( + format!("Content-Type: {}; name={}\n\n", a.content_type, name).chars(), + ); + } else { + ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars()); + } + ret.push_str(&BASE64_MIME.encode(a.body()).trim()); + } + _ => { + ret.extend(format!("Content-Type: {}\n\n", a.content_type).chars()); + ret.extend(String::from_utf8_lossy(a.body()).chars()); + } + } + } + into_raw_helper(self, &mut ret); + ret + } } pub fn interpret_format_flowed(_t: &str) -> String { diff --git a/melib/src/email/compose.rs b/melib/src/email/compose.rs index 17b6c16a..c78c6ce4 100644 --- a/melib/src/email/compose.rs +++ b/melib/src/email/compose.rs @@ -18,11 +18,11 @@ use fnv::FnvHashMap; #[derive(Debug, PartialEq, Clone)] pub struct Draft { - headers: FnvHashMap<String, String>, - header_order: Vec<String>, - body: String, + pub headers: FnvHashMap<String, String>, + pub header_order: Vec<String>, + pub body: String, - attachments: Vec<AttachmentBuilder>, + pub attachments: Vec<AttachmentBuilder>, } impl Default for Draft { @@ -259,7 +259,19 @@ impl Draft { } ret.push_str("MIME-Version: 1.0\n"); - if !self.attachments.is_empty() { + 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-Transfer-Encoding: {}\n", content_transfer_encoding).chars(), + ); + ret.push('\n'); + ret.push_str(&self.body); + } else if self.attachments.len() == 1 && self.body.is_empty() { + let attachment: Attachment = self.attachments.remove(0).into(); + ret.extend(attachment.into_raw().chars()); + } else { let mut parts = Vec::with_capacity(self.attachments.len() + 1); let attachments = std::mem::replace(&mut self.attachments, Vec::new()); let mut body_attachment = AttachmentBuilder::default(); @@ -267,24 +279,6 @@ impl Draft { parts.push(body_attachment); parts.extend(attachments.into_iter()); build_multipart(&mut ret, MultipartType::Mixed, parts); - } else { - if self.body.is_ascii() { - ret.push('\n'); - ret.push_str(&self.body); - } else { - let content_type: ContentType = Default::default(); - let content_transfer_encoding: ContentTransferEncoding = - ContentTransferEncoding::Base64; - - ret.extend(format!("Content-Type: {}; charset=\"utf-8\"\n", content_type).chars()); - ret.extend( - format!("Content-Transfer-Encoding: {}\n", content_transfer_encoding).chars(), - ); - ret.push('\n'); - - ret.push_str(&BASE64_MIME.encode(&self.body.as_bytes()).trim()); - ret.push('\n'); - } } Ok(ret) |