use soft_ascii_string::{ SoftAsciiStr, SoftAsciiChar, SoftAsciiString }; use media_type::BOUNDARY; use internals::{ encoder::{ EncodingBuffer, EncodingWriter, }, error::{EncodingError, EncodingErrorKind, Place, UTF_8, US_ASCII} }; use headers::{ HeaderName, HeaderObj, HeaderObjTrait, HeaderKind, headers::{ContentTransferEncoding, ContentType} }; use ::{ error::MailError, mail::{ Mail, EncodableMail, assume_encoded } }; /// /// # Panics /// if the body is not yet resolved use `Body::poll_body` or `IntoFuture` /// on `Mail` to prevent this from happening /// #[inline(always)] pub(crate) fn encode_mail( mail: &EncodableMail, top: bool, encoder: &mut EncodingBuffer ) -> Result<(), MailError> { _encode_mail(&*mail, top, encoder) .map_err(|err| { let mail_type = encoder.mail_type(); use self::MailError::*; match err { Encoding(enc_err) => Encoding(enc_err.with_mail_type_or_else(||Some(mail_type))), other => other } }) } fn _encode_mail( mail: &Mail, top: bool, encoder: &mut EncodingBuffer ) -> Result<(), MailError> { encode_headers(&mail, top, encoder)?; //the empty line between the headers and the body encoder.write_blank_line(); encode_mail_part(&mail, encoder)?; Ok(()) } /// /// # Panics /// if the body is not yet resolved use `Body::poll_body` or `IntoFuture` /// on `Mail` to prevent this from happening /// fn encode_headers( mail: &Mail, top: bool, encoder: &mut EncodingBuffer ) -> Result<(), MailError> { use super::MailBody::*; let mut handle = encoder.writer(); if top { handle.write_str(SoftAsciiStr::from_unchecked( "MIME-Version: 1.0" ))?; handle.finish_header(); } for (name, hbody) in mail.headers().iter() { let name_as_str = name.as_str(); let ignored_header = !top && !(name_as_str.starts_with("Content-") || name_as_str.starts_with("X-") ); if ignored_header { warn!("non `Content-` header in MIME body: {:?}: {:?}", name, hbody); } encode_header(&mut handle, name, hbody)?; } match mail.body() { SingleBody { ref body } => { let data = assume_encoded(body); let header = ContentTransferEncoding::body(data.encoding()); encode_header(&mut handle, header.name(), &header)?; let header = ContentType::body(data.media_type().clone()); encode_header(&mut handle, header.name(), &header)?; }, MultipleBodies { hidden_text:_, bodies:_ } => {} } Ok(()) } fn encode_header( handle: &mut EncodingWriter, name: HeaderName, header: &HeaderObj ) -> Result<(), EncodingError> { //FIXME[rust/catch] use catch block let res = (|| -> Result<(), EncodingError> { handle.write_str(name.as_ascii_str())?; handle.write_char(SoftAsciiChar::from_unchecked(':'))?; handle.write_fws(); header.encode(handle)?; handle.finish_header(); Ok(()) })(); res.map_err(|err| { err.with_place_or_else(|| Some(Place::Header { name: name.as_str() })) }) } /// /// # Panics /// if the body is not yet resolved use `Body::poll_body` or `IntoFuture` /// on `Mail` to prevent this from happening /// fn encode_mail_part(mail: &Mail, encoder: &mut EncodingBuffer ) -> Result<(), MailError> { use super::MailBody::*; let minus = SoftAsciiChar::from_unchecked('-'); match mail.body() { SingleBody { ref body } => { let data = assume_encoded(body); let buffer = data.transfer_encoded_buffer(); encoder.write_body_unchecked(buffer); }, MultipleBodies { ref hidden_text, ref bodies } => { if hidden_text.len() > 0 { //TODO find out if there is any source using the hidden text // (e.g. for some form of validation, prove of senders validity etc.) // if not drop the "hidden_text" field warn!("\"hidden text\" in multipart bodies is dropped") } let mail_was_validated_err_msg = "[BUG] mail was already validated"; let boundary = mail.headers() .get_single(ContentType) .expect(mail_was_validated_err_msg) .expect(mail_was_validated_err_msg) .get_param(BOUNDARY) .expect(mail_was_validated_err_msg) .to_content(); let boundary = SoftAsciiString ::from_string(boundary) .map_err(|orig_string| EncodingError ::from(EncodingErrorKind::InvalidTextEncoding { got_encoding: UTF_8, expected_encoding: US_ASCII }) .with_place_or_else(|| Some(Place::Header { name: "Content-Type" })) .with_str_context(orig_string.into_source()) )?; for mail in bodies.iter() { encoder.write_header_line(|handle| { handle.write_char(minus)?; handle.write_char(minus)?; handle.write_str(&*boundary) })?; _encode_mail(mail, false, encoder)?; } if bodies.len() > 0 { encoder.write_header_line(|handle| { handle.write_char(minus)?; handle.write_char(minus)?; handle.write_str(&*boundary)?; handle.write_char(minus)?; handle.write_char(minus) })?; } } } Ok(()) }