summaryrefslogtreecommitdiffstats
path: root/melib
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2019-09-28 10:46:49 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2019-09-28 12:19:22 +0300
commite35a93336a2c0ce081cd05f64986c6f6cdc59077 (patch)
treee36c7e99b24f7826980d5eec590551c68713d734 /melib
parent963fdd157503966d4ec16a9b175be6b2caa9fba6 (diff)
Add GPG signing and sig verifying
Diffstat (limited to 'melib')
-rw-r--r--melib/src/email/attachment_types.rs23
-rw-r--r--melib/src/email/attachments.rs84
-rw-r--r--melib/src/email/compose.rs40
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)