summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--melib/src/email.rs6
-rw-r--r--melib/src/email/attachment_types.rs77
-rw-r--r--melib/src/email/attachments.rs188
-rw-r--r--ui/src/components/mail/view.rs4
-rw-r--r--ui/src/components/mail/view/envelope.rs2
5 files changed, 121 insertions, 156 deletions
diff --git a/melib/src/email.rs b/melib/src/email.rs
index b7b8690d..29671724 100644
--- a/melib/src/email.rs
+++ b/melib/src/email.rs
@@ -472,7 +472,7 @@ impl Envelope {
&& cst.eq_ignore_ascii_case(b"mixed") =>
{
let mut builder = AttachmentBuilder::new(body);
- builder.set_content_type(value);
+ builder.set_content_type_from_bytes(value);
let b = builder.build();
let subs = b.attachments();
@@ -586,9 +586,9 @@ impl Envelope {
continue;
}
if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
- builder.set_content_transfer_encoding(value);
+ builder.set_content_transfer_encoding(ContentTransferEncoding::from(value));
} else if name.eq_ignore_ascii_case(b"content-type") {
- builder.set_content_type(value);
+ builder.set_content_type_from_bytes(value);
}
}
builder.build()
diff --git a/melib/src/email/attachment_types.rs b/melib/src/email/attachment_types.rs
index 6cba27ea..6e280253 100644
--- a/melib/src/email/attachment_types.rs
+++ b/melib/src/email/attachment_types.rs
@@ -1,30 +1,28 @@
+/*
+ * meli
+ *
+ * Copyright 2017-2019 Manos Pitsidianakis
+ *
+ * This file is part of meli.
+ *
+ * meli is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * meli is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with meli. If not, see <http://www.gnu.org/licenses/>.
+ */
use crate::email::attachments::Attachment;
use crate::email::parser::BytesExt;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::str;
-// TODO: rename.
-#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Default)]
-pub struct SliceBuild {
- offset: usize,
- end: usize,
-}
-
-impl SliceBuild {
- pub fn new(offset: usize, length: usize) -> Self {
- SliceBuild {
- offset,
- end: offset + length,
- }
- }
- //fn length(&self) -> usize {
- // self.end - self.offset + 1
- //}
- pub fn get<'a>(&self, slice: &'a [u8]) -> &'a [u8] {
- &slice[self.offset..self.end]
- }
-}
-
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum Charset {
Ascii,
@@ -100,6 +98,22 @@ impl Display for MultipartType {
}
}
+impl From<&[u8]> for MultipartType {
+ fn from(val: &[u8]) -> MultipartType {
+ if val.eq_ignore_ascii_case(b"mixed") {
+ MultipartType::Mixed
+ } else if val.eq_ignore_ascii_case(b"alternative") {
+ MultipartType::Alternative
+ } else if val.eq_ignore_ascii_case(b"digest") {
+ MultipartType::Digest
+ } else if val.eq_ignore_ascii_case(b"signed") {
+ MultipartType::Signed
+ } else {
+ Default::default()
+ }
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum ContentType {
Text {
@@ -107,7 +121,7 @@ pub enum ContentType {
charset: Charset,
},
Multipart {
- boundary: SliceBuild,
+ boundary: Vec<u8>,
kind: MultipartType,
subattachments: Vec<Attachment>,
},
@@ -216,3 +230,20 @@ impl Display for ContentTransferEncoding {
}
}
}
+impl From<&[u8]> for ContentTransferEncoding {
+ fn from(val: &[u8]) -> ContentTransferEncoding {
+ if val.eq_ignore_ascii_case(b"base64") {
+ ContentTransferEncoding::Base64
+ } else if val.eq_ignore_ascii_case(b"7bit") {
+ ContentTransferEncoding::_7Bit
+ } else if val.eq_ignore_ascii_case(b"8bit") {
+ ContentTransferEncoding::_8Bit
+ } else if val.eq_ignore_ascii_case(b"quoted-printable") {
+ ContentTransferEncoding::QuotedPrintable
+ } else {
+ ContentTransferEncoding::Other {
+ tag: val.to_ascii_lowercase(),
+ }
+ }
+ }
+}
diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs
index 3621f103..1a5352e0 100644
--- a/melib/src/email/attachments.rs
+++ b/melib/src/email/attachments.rs
@@ -21,20 +21,12 @@
use crate::email::parser;
use crate::email::parser::BytesExt;
use crate::email::EnvelopeWrapper;
+use core::fmt;
+use core::str;
use data_encoding::BASE64_MIME;
-use std::fmt;
-use std::str;
pub use crate::email::attachment_types::*;
-/*
- *
- * Data
- * Text { content: Vec<u8> }
- * Multipart
- */
-// TODO: Add example.
-//
#[derive(Default, PartialEq)]
pub struct AttachmentBuilder {
content_type: ContentType,
@@ -42,30 +34,6 @@ pub struct AttachmentBuilder {
raw: Vec<u8>,
}
-
-#[derive(Clone, Serialize, Deserialize, PartialEq)]
-pub struct Attachment {
- content_type: ContentType,
- content_transfer_encoding: ContentTransferEncoding,
-
- raw: Vec<u8>,
-}
-
-impl fmt::Debug for Attachment {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Attachment {{\n content_type: {:?},\n content_transfer_encoding: {:?},\n raw: Vec of {} bytes\n, body:\n{}\n}}",
- self.content_type,
- self.content_transfer_encoding,
- self.raw.len(),
- {
- let mut text = Vec::with_capacity(4096);
- self.get_text_recursive(&mut text);
- std::str::from_utf8(&text).map(std::string::ToString::to_string).unwrap_or_else(|e| format!("Unicode error {}", e))
- }
- )
- }
-}
-
impl AttachmentBuilder {
pub fn new(content: &[u8]) -> Self {
AttachmentBuilder {
@@ -74,11 +42,26 @@ impl AttachmentBuilder {
raw: content.to_vec(),
}
}
- pub fn content_type(&mut self) -> &ContentType {
+
+ pub fn set_content_type(&mut self, val: ContentType) -> &mut Self {
+ self.content_type = val;
+ self
+ }
+
+ pub fn content_type(&self) -> &ContentType {
&self.content_type
}
- pub fn set_content_type(&mut self, value: &[u8]) -> &Self {
+ pub fn set_content_transfer_encoding(&mut self, val: ContentTransferEncoding) -> &mut Self {
+ self.content_transfer_encoding = val;
+ self
+ }
+
+ pub fn content_transfer_encoding(&self) -> &ContentTransferEncoding {
+ &self.content_transfer_encoding
+ }
+
+ pub fn set_content_type_from_bytes(&mut self, value: &[u8]) -> &mut Self {
match parser::content_type(value).to_full_result() {
Ok((ct, cst, params)) => {
if ct.eq_ignore_ascii_case(b"multipart") {
@@ -90,26 +73,12 @@ impl AttachmentBuilder {
}
}
assert!(boundary.is_some());
- let _boundary = boundary.unwrap();
- let offset =
- (_boundary.as_ptr() as usize).wrapping_sub(value.as_ptr() as usize);
- let boundary = SliceBuild::new(offset, _boundary.len());
- let subattachments = Self::subattachments(&self.raw, boundary.get(&value));
- // Invalid mail or wrong assumption?
- // assert!(!subattachments.is_empty());
+ let boundary = boundary.unwrap().to_vec();
+ let subattachments = Self::subattachments(&self.raw, &boundary);
+
self.content_type = ContentType::Multipart {
boundary,
- kind: if cst.eq_ignore_ascii_case(b"mixed") {
- MultipartType::Mixed
- } else if cst.eq_ignore_ascii_case(b"alternative") {
- MultipartType::Alternative
- } else if cst.eq_ignore_ascii_case(b"digest") {
- MultipartType::Digest
- } else if cst.eq_ignore_ascii_case(b"signed") {
- MultipartType::Signed
- } else {
- Default::default()
- },
+ kind: MultipartType::from(cst),
subattachments,
};
} else if ct.eq_ignore_ascii_case(b"text") {
@@ -164,50 +133,7 @@ impl AttachmentBuilder {
}
self
}
- pub fn set_content_transfer_encoding(&mut self, value: &[u8]) -> &Self {
- self.content_transfer_encoding = if value.eq_ignore_ascii_case(b"base64") {
- ContentTransferEncoding::Base64
- } else if value.eq_ignore_ascii_case(b"7bit") {
- ContentTransferEncoding::_7Bit
- } else if value.eq_ignore_ascii_case(b"8bit") {
- ContentTransferEncoding::_8Bit
- } else if value.eq_ignore_ascii_case(b"quoted-printable") {
- ContentTransferEncoding::QuotedPrintable
- } else {
- ContentTransferEncoding::Other {
- tag: value.to_ascii_lowercase(),
- }
- };
- self
- }
- /*
- fn decode(&self) -> Vec<u8> {
- // TODO merge this and standalone decode() function
- let charset = match self.content_type {
- ContentType::Text { charset: c, .. } => c,
- _ => Default::default(),
- };
- let bytes = match self.content_transfer_encoding {
- ContentTransferEncoding::Base64 => match BASE64_MIME.decode(&self.raw) {
- Ok(v) => v,
- _ => self.raw.to_vec(),
- },
- ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(&self.raw)
- .to_full_result()
- .unwrap(),
- ContentTransferEncoding::_7Bit
- | ContentTransferEncoding::_8Bit
- | ContentTransferEncoding::Other { .. } => self.raw.to_vec(),
- };
-
- if let Ok(b) = parser::decode_charset(&bytes, charset) {
- b.into_bytes()
- } else {
- self.raw.to_vec()
- }
- }
- */
pub fn build(self) -> Attachment {
Attachment {
content_type: self.content_type,
@@ -234,16 +160,14 @@ impl AttachmentBuilder {
}
};
- let body_slice = {
- let offset = (body.as_ptr() as usize).wrapping_sub(a.as_ptr() as usize);
- SliceBuild::new(offset, body.len())
- };
- builder.raw = body_slice.get(a).ltrim().into();
+ builder.raw = body.ltrim().into();
for (name, value) in headers {
if name.eq_ignore_ascii_case(b"content-type") {
- builder.set_content_type(value);
+ builder.set_content_type_from_bytes(value);
} else if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
- builder.set_content_transfer_encoding(value);
+ builder.set_content_transfer_encoding(ContentTransferEncoding::from(
+ value,
+ ));
}
}
vec.push(builder.build());
@@ -263,10 +187,34 @@ impl AttachmentBuilder {
}
}
+/// Immutable attachment type.
+#[derive(Clone, Serialize, Deserialize, PartialEq)]
+pub struct Attachment {
+ content_type: ContentType,
+ content_transfer_encoding: ContentTransferEncoding,
+
+ raw: Vec<u8>,
+}
+
+impl fmt::Debug for Attachment {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Attachment {{\n content_type: {:?},\n content_transfer_encoding: {:?},\n raw: Vec of {} bytes\n, body:\n{}\n}}",
+ self.content_type,
+ self.content_transfer_encoding,
+ self.raw.len(),
+ {
+ let mut text = Vec::with_capacity(4096);
+ self.get_text_recursive(&mut text);
+ std::str::from_utf8(&text).map(std::string::ToString::to_string).unwrap_or_else(|e| format!("Unicode error {}", e))
+ }
+ )
+ }
+}
+
impl fmt::Display for Attachment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.content_type {
- ContentType::MessageRfc822 => match EnvelopeWrapper::new(self.bytes().to_vec()) {
+ ContentType::MessageRfc822 => match EnvelopeWrapper::new(self.raw().to_vec()) {
Ok(wrapper) => write!(
f,
"message/rfc822: {} - {} - {}",
@@ -307,7 +255,7 @@ impl Attachment {
}
}
- pub fn bytes(&self) -> &[u8] {
+ pub fn raw(&self) -> &[u8] {
&self.raw
}
fn get_text_recursive(&self, text: &mut Vec<u8>) {
@@ -442,27 +390,13 @@ impl Attachment {
}
pub fn interpret_format_flowed(_t: &str) -> String {
- //let mut n = String::with_capacity(t.len());
unimplemented!()
}
fn decode_rfc822(_raw: &[u8]) -> Attachment {
- let builder = AttachmentBuilder::new(b"");
+ // FIXME
+ let builder = AttachmentBuilder::new(b"message/rfc822 cannot be displayed");
builder.build()
-
- /*
- debug!("raw is\n{:?}", str::from_utf8(raw).unwrap());
- let e = match Envelope::from_bytes(raw) {
- Some(e) => e,
- None => {
- debug!("error in parsing mail");
- let error_msg = b"Mail cannot be shown because of errors.";
- let mut builder = AttachmentBuilder::new(error_msg);
- return builder.build();
- }
- };
- e.body(None)
- */
}
type Filter<'a> = Box<FnMut(&'a Attachment, &mut Vec<u8>) -> () + 'a>;
@@ -514,23 +448,23 @@ fn decode_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<
};
let bytes = match a.content_transfer_encoding {
- ContentTransferEncoding::Base64 => match BASE64_MIME.decode(a.bytes()) {
+ ContentTransferEncoding::Base64 => match BASE64_MIME.decode(a.raw()) {
Ok(v) => v,
- _ => a.bytes().to_vec(),
+ _ => a.raw().to_vec(),
},
- ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(a.bytes())
+ ContentTransferEncoding::QuotedPrintable => parser::quoted_printable_bytes(a.raw())
.to_full_result()
.unwrap(),
ContentTransferEncoding::_7Bit
| ContentTransferEncoding::_8Bit
- | ContentTransferEncoding::Other { .. } => a.bytes().to_vec(),
+ | ContentTransferEncoding::Other { .. } => a.raw().to_vec(),
};
let mut ret = if a.content_type.is_text() {
if let Ok(v) = parser::decode_charset(&bytes, charset) {
v.into_bytes()
} else {
- a.bytes().to_vec()
+ a.raw().to_vec()
}
} else {
bytes.to_vec()
diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs
index f27c53c9..621ca246 100644
--- a/ui/src/components/mail/view.rs
+++ b/ui/src/components/mail/view.rs
@@ -200,7 +200,7 @@ impl MailView {
}
t
}
- ViewMode::Raw => String::from_utf8_lossy(body.bytes()).into_owned(),
+ ViewMode::Raw => String::from_utf8_lossy(body.raw()).into_owned(),
ViewMode::Url => {
let mut t = body_text.to_string();
for (lidx, l) in finder.links(&body.text()).enumerate() {
@@ -720,7 +720,7 @@ impl Component for MailView {
match u.content_type() {
ContentType::MessageRfc822 => {
self.mode = ViewMode::Subview;
- match EnvelopeWrapper::new(u.bytes().to_vec()) {
+ match EnvelopeWrapper::new(u.raw().to_vec()) {
Ok(wrapper) => {
self.subview = Some(Box::new(EnvelopeView::new(
wrapper,
diff --git a/ui/src/components/mail/view/envelope.rs b/ui/src/components/mail/view/envelope.rs
index 040c2f10..532f2756 100644
--- a/ui/src/components/mail/view/envelope.rs
+++ b/ui/src/components/mail/view/envelope.rs
@@ -150,7 +150,7 @@ impl EnvelopeView {
}
t
}
- ViewMode::Raw => String::from_utf8_lossy(body.bytes()).into_owned(),
+ ViewMode::Raw => String::from_utf8_lossy(body.raw()).into_owned(),
ViewMode::Url => {
let mut t = body_text.to_string();
for (lidx, l) in finder.links(&body.text()).enumerate() {