summaryrefslogtreecommitdiffstats
path: root/core/src/mail.rs
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/mail.rs')
-rw-r--r--core/src/mail.rs300
1 files changed, 130 insertions, 170 deletions
diff --git a/core/src/mail.rs b/core/src/mail.rs
index 0ceeba8..1b43475 100644
--- a/core/src/mail.rs
+++ b/core/src/mail.rs
@@ -1,55 +1,28 @@
//! Module containing all the parts for creating/encoding Mails.
//!
+use std::{fmt, mem, ops::Deref};
-use std::{
- ops::Deref,
- fmt,
- mem
-};
-
-use soft_ascii_string::SoftAsciiString;
-use futures::{
- future,
- Future,
- Async,
- Poll
-};
+use futures::{future, Async, Future, Poll};
use media_type::BOUNDARY;
+use soft_ascii_string::SoftAsciiString;
-use internals::{
- MailType,
- encoder::EncodingBuffer
-};
use headers::{
- Header, HeaderKind,
- HeaderMap,
+ error::HeaderValidationError,
+ header_components::{DateTime, MediaType},
headers::{
- ContentType, _From,
- ContentTransferEncoding,
- Date, MessageId,
- ContentDisposition,
- ContentId
- },
- header_components::{
- DateTime,
- MediaType
+ ContentDisposition, ContentId, ContentTransferEncoding, ContentType, Date, MessageId, _From,
},
- error::{
- HeaderValidationError,
- }
+ Header, HeaderKind, HeaderMap,
};
+use internals::{encoder::EncodingBuffer, MailType};
-use ::{
- utils::SendBoxFuture,
+use {
+ context::Context,
+ error::{MailError, OtherValidationError, ResourceLoadingError},
mime::create_structured_random_boundary,
- error::{
- MailError,
- OtherValidationError,
- ResourceLoadingError
- },
resource::*,
- context::Context
+ utils::SendBoxFuture,
};
/// A type representing a Mail.
@@ -186,7 +159,7 @@ pub struct Mail {
#[derive(Clone, Debug)]
pub enum MailBody {
SingleBody {
- body: Resource
+ body: Resource,
},
MultipleBodies {
//TODO[now]: use Vec1
@@ -196,12 +169,11 @@ pub enum MailBody {
/// there is a chance that we need to do so
/// in the future as some mechanisms might
/// misuse this, well unusual think.
- hidden_text: SoftAsciiString
- }
+ hidden_text: SoftAsciiString,
+ },
}
impl Mail {
-
/// Create a new plain text mail.
///
/// This will
@@ -235,8 +207,8 @@ impl Mail {
headers,
body: MailBody::MultipleBodies {
bodies,
- hidden_text: SoftAsciiString::new()
- }
+ hidden_text: SoftAsciiString::new(),
+ },
}
}
@@ -245,18 +217,18 @@ impl Mail {
let headers = HeaderMap::new();
Mail {
headers,
- body: MailBody::SingleBody { body }
+ body: MailBody::SingleBody { body },
}
}
-
/// Inserts a new header into the header map.
///
/// This will call `insert` on the inner `HeaderMap`,
/// which means all behavior of `HeaderMap::insert`
/// does apply, like e.g. the "max one" behavior.
pub fn insert_header<H>(&mut self, header: Header<H>)
- where H: HeaderKind
+ where
+ H: HeaderKind,
{
self.headers_mut().insert(header);
}
@@ -325,7 +297,7 @@ impl Mail {
validate_singlepart_headermap(self.headers())?;
}
match self.body() {
- &MailBody::SingleBody { .. } => {},
+ &MailBody::SingleBody { .. } => {}
&MailBody::MultipleBodies { ref bodies, .. } => {
for body in bodies {
body.generally_validate_mail()?;
@@ -374,16 +346,17 @@ impl Mail {
/// same Resource` (assuming the mail had not been modified in it's structure
/// in between).
fn visit_mail_bodies<FN>(&self, use_it_fn: &mut FN)
- where FN: FnMut(&Resource)
+ where
+ FN: FnMut(&Resource),
{
use self::MailBody::*;
match self.body {
- SingleBody { ref body } =>
- use_it_fn(body),
- MultipleBodies { ref bodies, .. } =>
+ SingleBody { ref body } => use_it_fn(body),
+ MultipleBodies { ref bodies, .. } => {
for body in bodies {
body.visit_mail_bodies(use_it_fn)
}
+ }
}
}
@@ -392,58 +365,64 @@ impl Mail {
/// See `visit_mail_bodies` for a listing of **visiting order guarantees** given
/// by this function.
fn visit_mail_bodies_mut<FN>(&mut self, use_it_fn: &mut FN)
- where FN: FnMut(&mut Resource)
+ where
+ FN: FnMut(&mut Resource),
{
use self::MailBody::*;
match self.body {
- SingleBody { ref mut body } =>
- use_it_fn(body),
- MultipleBodies { ref mut bodies, .. } =>
+ SingleBody { ref mut body } => use_it_fn(body),
+ MultipleBodies { ref mut bodies, .. } => {
for body in bodies {
body.visit_mail_bodies_mut(use_it_fn)
}
+ }
}
}
}
-
impl MailBody {
-
/// Returns `true` if it's an multipart body.
pub fn is_multipart(&self) -> bool {
use self::MailBody::*;
match *self {
SingleBody { .. } => false,
- MultipleBodies { .. } => true
+ MultipleBodies { .. } => true,
}
}
}
/// A future resolving to an encodable mail.
pub struct MailFuture<C: Context> {
- inner: InnerMailFuture<C>
+ inner: InnerMailFuture<C>,
}
enum InnerMailFuture<C: Context> {
- New { mail: Mail, ctx: C },
+ New {
+ mail: Mail,
+ ctx: C,
+ },
Loading {
mail: Mail,
pending: future::JoinAll<Vec<SendBoxFuture<EncData, ResourceLoadingError>>>,
- ctx: C
+ ctx: C,
},
- Poison
+ Poison,
}
impl<C> MailFuture<C>
- where C: Context
+where
+ C: Context,
{
fn new(mail: Mail, ctx: C) -> Self {
- MailFuture { inner: InnerMailFuture::New { mail, ctx } }
+ MailFuture {
+ inner: InnerMailFuture::New { mail, ctx },
+ }
}
}
impl<T> Future for MailFuture<T>
- where T: Context,
+where
+ T: Context,
{
type Item = EncodableMail;
type Error = MailError;
@@ -466,28 +445,31 @@ impl<T> Future for MailFuture<T>
mem::replace(
&mut self.inner,
InnerMailFuture::Loading {
- mail, ctx,
- pending: future::join_all(futures)
- }
- );
- },
- Loading { mut mail, mut pending, ctx } => {
- match pending.poll() {
- Err(err) => return Err(err.into()),
- Ok(Async::NotReady) => {
- mem::replace(
- &mut self.inner,
- InnerMailFuture::Loading { mail, pending, ctx }
- );
- return Ok(Async::NotReady);
+ mail,
+ ctx,
+ pending: future::join_all(futures),
},
- Ok(Async::Ready(encoded_bodies)) => {
- auto_gen_headers(&mut mail, encoded_bodies, &ctx);
- return Ok(Async::Ready(EncodableMail(mail)));
- }
+ );
+ }
+ Loading {
+ mut mail,
+ mut pending,
+ ctx,
+ } => match pending.poll() {
+ Err(err) => return Err(err.into()),
+ Ok(Async::NotReady) => {
+ mem::replace(
+ &mut self.inner,
+ InnerMailFuture::Loading { mail, pending, ctx },
+ );
+ return Ok(Async::NotReady);
+ }
+ Ok(Async::Ready(encoded_bodies)) => {
+ auto_gen_headers(&mut mail, encoded_bodies, &ctx);
+ return Ok(Async::Ready(EncodableMail(mail)));
}
},
- Poison => panic!("called again after completion (through value, error or panic)")
+ Poison => panic!("called again after completion (through value, error or panic)"),
}
}
}
@@ -498,7 +480,6 @@ impl<T> Future for MailFuture<T>
pub struct EncodableMail(Mail);
impl EncodableMail {
-
/// Encode the mail using the given encoding buffer.
///
/// After encoding succeeded the buffer should contain
@@ -531,11 +512,7 @@ fn top_level_validation(mail: &Mail) -> Result<(), HeaderValidationError> {
}
/// insert auto-generated headers like `Date`, `Message-Id` and `Content-Id`
-fn auto_gen_headers<C: Context>(
- mail: &mut Mail,
- encoded_resources: Vec<EncData>,
- ctx: &C
-) {
+fn auto_gen_headers<C: Context>(mail: &mut Mail, encoded_resources: Vec<EncData>, ctx: &C) {
{
let headers = mail.headers_mut();
if !headers.contains(Date) {
@@ -549,7 +526,8 @@ fn auto_gen_headers<C: Context>(
let mut iter = encoded_resources.into_iter();
mail.visit_mail_bodies_mut(&mut move |resource: &mut Resource| {
- let enc_data = iter.next()
+ let enc_data = iter
+ .next()
.expect("[BUG] mail structure modified while turing it into encoded mail");
mem::replace(resource, Resource::EncData(enc_data));
});
@@ -569,7 +547,7 @@ fn auto_gen_headers<C: Context>(
pub(crate) fn assume_encoded(resource: &Resource) -> &EncData {
match resource {
&Resource::EncData(ref ed) => ed,
- _ => panic!("[BUG] auto gen/encode should only be called on all resources are loaded")
+ _ => panic!("[BUG] auto gen/encode should only be called on all resources are loaded"),
}
}
@@ -584,7 +562,10 @@ pub(crate) fn assume_encoded(resource: &Resource) -> &EncData {
/// - create/overwrite the boundary for the `Content-Type` header
/// - call this method for all bodies in the multipart body
fn recursive_auto_gen_headers<C: Context>(mail: &mut Mail, boundary_count: &mut usize, ctx: &C) {
- let &mut Mail { ref mut headers, ref mut body } = mail;
+ let &mut Mail {
+ ref mut headers,
+ ref mut body,
+ } = mail;
match body {
&mut MailBody::SingleBody { ref mut body } => {
let data = assume_encoded(body);
@@ -595,7 +576,7 @@ fn recursive_auto_gen_headers<C: Context>(mail: &mut Mail, boundary_count: &mut
}
headers.insert(ContentId::body(data.content_id().clone()));
- },
+ }
&mut MailBody::MultipleBodies { ref mut bodies, .. } => {
let mut headers: &mut HeaderMap = headers;
let content_type: &mut Header<ContentType> = headers
@@ -614,10 +595,7 @@ fn recursive_auto_gen_headers<C: Context>(mail: &mut Mail, boundary_count: &mut
}
}
-pub(crate) fn validate_multipart_headermap(headers: &HeaderMap)
- -> Result<(), MailError>
-{
-
+pub(crate) fn validate_multipart_headermap(headers: &HeaderMap) -> Result<(), MailError> {
if headers.contains(ContentTransferEncoding) {
return Err(OtherValidationError::ContentTransferEncodingHeaderGiven.into());
}
@@ -633,10 +611,9 @@ pub(crate) fn validate_multipart_headermap(headers: &HeaderMap)
Ok(())
}
-
-pub(crate) fn validate_singlepart_headermap(headers: &HeaderMap)
- -> Result<(), HeaderValidationError>
-{
+pub(crate) fn validate_singlepart_headermap(
+ headers: &HeaderMap,
+) -> Result<(), HeaderValidationError> {
if headers.contains(ContentTransferEncoding) {
return Err(OtherValidationError::ContentTransferEncodingHeaderGiven.into());
}
@@ -648,9 +625,8 @@ pub(crate) fn validate_singlepart_headermap(headers: &HeaderMap)
}
impl Deref for EncodableMail {
-
type Target = Mail;
- fn deref( &self ) -> &Self::Target {
+ fn deref(&self) -> &Self::Target {
&self.0
}
}
@@ -662,14 +638,12 @@ impl Into<Mail> for EncodableMail {
}
}
-
impl fmt::Debug for EncodableMail {
fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
write!(fter, "EncodableMail {{ .. }}")
}
}
-
#[cfg(test)]
mod test {
use std::fmt::Debug;
@@ -680,65 +654,58 @@ mod test {
mod Mail {
#![allow(non_snake_case)]
- use headers::{
- headers::{
- Subject,
- Comments
- }
- };
- use default_impl::test_context;
use super::super::*;
use super::{AssertDebug, AssertSend, AssertSync};
+ use default_impl::test_context;
+ use headers::headers::{Comments, Subject};
impl AssertDebug for Mail {}
impl AssertSend for Mail {}
impl AssertSync for Mail {}
-
#[test]
fn visit_mail_bodies_does_not_skip() {
let ctx = test_context();
let mail = Mail {
headers: HeaderMap::new(),
body: MailBody::MultipleBodies {
- bodies: vec! [
+ bodies: vec![
Mail {
headers: HeaderMap::new(),
body: MailBody::MultipleBodies {
- bodies: vec! [
+ bodies: vec![
Mail {
headers: HeaderMap::new(),
body: MailBody::SingleBody {
- body: Resource::plain_text("r1", &ctx)
- }
+ body: Resource::plain_text("r1", &ctx),
+ },
},
Mail {
headers: HeaderMap::new(),
body: MailBody::SingleBody {
- body: Resource::plain_text("r2", &ctx)
- }
- }
+ body: Resource::plain_text("r2", &ctx),
+ },
+ },
],
- hidden_text: Default::default()
- }
+ hidden_text: Default::default(),
+ },
},
Mail {
headers: HeaderMap::new(),
body: MailBody::SingleBody {
- body: Resource::plain_text("r3", &ctx)
- }
- }
-
+ body: Resource::plain_text("r3", &ctx),
+ },
+ },
],
- hidden_text: Default::default()
- }
+ hidden_text: Default::default(),
+ },
};
let mut body_count = 0;
mail.visit_mail_bodies(&mut |body: &Resource| {
if let &Resource::Data(ref body) = body {
assert_eq!(
- [ "r1", "r2", "r3"][body_count].as_bytes(),
+ ["r1", "r2", "r3"][body_count].as_bytes(),
body.buffer().as_ref()
)
} else {
@@ -757,8 +724,6 @@ mod test {
assert!(mail.headers().contains(Subject));
});
-
-
test!(insert_headers_sets_all_headers, {
let ctx = test_context();
let mut mail = Mail::plain_text("r0", &ctx);
@@ -770,21 +735,15 @@ mod test {
assert!(mail.headers().contains(Subject));
assert!(mail.headers().contains(Comments));
});
-
}
mod EncodableMail {
#![allow(non_snake_case)]
- use chrono::{Utc, TimeZone};
- use headers::{
- headers::{
- _From, ContentType, ContentTransferEncoding,
- Date, Subject
- }
- };
- use default_impl::test_context;
use super::super::*;
use super::{AssertDebug, AssertSend, AssertSync};
+ use chrono::{TimeZone, Utc};
+ use default_impl::test_context;
+ use headers::headers::{ContentTransferEncoding, ContentType, Date, Subject, _From};
impl AssertDebug for EncodableMail {}
impl AssertSend for EncodableMail {}
@@ -795,11 +754,12 @@ mod test {
let ctx = test_context();
let resource = Resource::plain_text("r9", &ctx);
let mail = Mail {
- headers: headers!{
+ headers: headers! {
_From: ["random@this.is.no.mail"],
Subject: "hoho"
- }.unwrap(),
- body: MailBody::SingleBody { body: resource }
+ }
+ .unwrap(),
+ body: MailBody::SingleBody { body: resource },
};
let enc_mail = assert_ok!(mail.into_encodable_mail(ctx).wait());
@@ -821,20 +781,19 @@ mod test {
let ctx = test_context();
let resource = Resource::plain_text("r9", &ctx);
let mail = Mail {
- headers: headers!{
+ headers: headers! {
_From: ["random@this.is.no.mail"],
Subject: "hoho",
ContentType: "multipart/mixed"
- }.unwrap(),
- body: MailBody::MultipleBodies {
- bodies: vec![
- Mail {
- headers: HeaderMap::new(),
- body: MailBody::SingleBody { body: resource }
- }
- ],
- hidden_text: Default::default()
}
+ .unwrap(),
+ body: MailBody::MultipleBodies {
+ bodies: vec![Mail {
+ headers: HeaderMap::new(),
+ body: MailBody::SingleBody { body: resource },
+ }],
+ hidden_text: Default::default(),
+ },
};
let mail = mail.into_encodable_mail(ctx).wait().unwrap();
@@ -845,7 +804,7 @@ mod test {
assert!(mail.headers().contains(ContentType));
assert_not!(mail.headers().contains(ContentTransferEncoding));
- if let MailBody::MultipleBodies { ref bodies, ..} = mail.body {
+ if let MailBody::MultipleBodies { ref bodies, .. } = mail.body {
let headers = bodies[0].headers();
assert_not!(headers.contains(Date));
} else {
@@ -857,11 +816,14 @@ mod test {
fn runs_contextual_validators() {
let ctx = test_context();
let mail = Mail {
- headers: headers!{
+ headers: headers! {
_From: ["random@this.is.no.mail", "u.p.s@s.p.u"],
Subject: "hoho"
- }.unwrap(),
- body: MailBody::SingleBody { body: Resource::plain_text("r9", &ctx) }
+ }
+ .unwrap(),
+ body: MailBody::SingleBody {
+ body: Resource::plain_text("r9", &ctx),
+ },
};
assert_err!(mail.into_encodable_mail(ctx).wait());
@@ -871,10 +833,13 @@ mod test {
fn checks_there_is_from() {
let ctx = test_context();
let mail = Mail {
- headers: headers!{
+ headers: headers! {
Subject: "hoho"
- }.unwrap(),
- body: MailBody::SingleBody { body: Resource::plain_text("r9", &ctx) }
+ }
+ .unwrap(),
+ body: MailBody::SingleBody {
+ body: Resource::plain_text("r9", &ctx),
+ },
};
assert_err!(mail.into_encodable_mail(ctx).wait());
@@ -891,14 +856,9 @@ mod test {
}?);
let enc_mail = assert_ok!(mail.into_encodable_mail(ctx).wait());
- let used_date = enc_mail.headers()
- .get_single(Date)
- .unwrap()
- .unwrap();
+ let used_date = enc_mail.headers().get_single(Date).unwrap().unwrap();
assert_eq!(&**used_date.body(), &provided_date);
});
-
}
-
-} \ No newline at end of file
+}