use quoted_string;
use internals::grammar::is_atext;
use internals::grammar::encoded_word::EncodedWordContext;
use internals::error::{EncodingError, EncodingErrorKind};
use internals::encoder::{EncodingWriter, EncodableInHeader};
use internals::bind::encoded_word::{EncodedWordEncoding, WriterWrapper};
use internals::bind::quoted_string::{MailQsSpec, InternationalizedMailQsSpec};
use ::{HeaderTryFrom, HeaderTryInto};
use ::error::ComponentCreationError;
use ::data::Input;
use super::CFWS;
#[derive( Debug, Clone, Eq, PartialEq, Hash )]
pub struct Word {
pub left_padding: Option<CFWS>,
pub input: Input,
pub right_padding: Option<CFWS>
}
impl<T> HeaderTryFrom<T> for Word
where T: HeaderTryInto<Input>
{
fn try_from( input: T ) -> Result<Self, ComponentCreationError> {
let input = input.try_into()?;
Ok( Word { left_padding: None, input, right_padding: None } )
}
}
impl Word {
pub fn pad_left( &mut self, padding: CFWS) {
self.left_padding = Some( padding )
}
pub fn pad_right( &mut self, padding: CFWS) {
self.right_padding = Some( padding )
}
}
pub fn do_encode_word<'a,'b: 'a>(
word: &'a Word,
handle: &'a mut EncodingWriter<'b>,
ecw_ctx: Option<EncodedWordContext>,
) -> Result<(), EncodingError> {
if let Some( pad ) = word.left_padding.as_ref() {
pad.encode( handle )?;
}
let input: &str = &*word.input;
let mail_type = handle.mail_type();
handle.write_if(input, |input| {
(!input.starts_with("=?"))
&& input.chars().all( |ch| is_atext( ch, mail_type ) )
}).handle_condition_failure(|handle| {
if let Some( _ecw_ctx ) = ecw_ctx {
let encoding = EncodedWordEncoding::QuotedPrintable;
let mut writer = WriterWrapper::new(
encoding,
handle
);
encoding.encode(input, &mut writer);
Ok(())
} else {
let mail_type = handle.mail_type();
let res =
if mail_type.is_internationalized() {
quoted_string::quote::<InternationalizedMailQsSpec>(input)
} else {
quoted_string::quote::<MailQsSpec>(input)
};
let quoted = res.map_err(|_err| {
EncodingError
::from(EncodingErrorKind::Malformed)
.with_str_context(input)
})?;
handle.write_str_unchecked(&*quoted)
}
})?;
if let Some( pad ) = word.right_padding.as_ref() {
pad.encode( handle )?;
}
Ok( () )
}
#[cfg(test)]
mod test {
use std::mem;
use internals::MailType;
use internals::encoder::EncodingBuffer;
use internals::encoder::TraceToken::*;
use internals::encoder::simplify_trace_tokens;
use super::*;
use super::super::FWS;
ec_test!{encode_pseudo_encoded_words, {
let word = Word::try_from( "=?" )?;
enc_closure!(move |handle: &mut EncodingWriter| {
do_encode_word( &word, handle, Some( EncodedWordContext::Text ) )
})
} => ascii => [
Text "=?utf8?Q?=3D=3F?="
]}
ec_test!{encode_word, {
let word = Word::try_from( "a↑b" )?;
enc_closure!(move |handle: &mut EncodingWriter| {
do_encode_word( &word, handle, Some( EncodedWordContext::Text ) )
})
} => ascii => [
Text "=?utf8?Q?a=E2=86=91b?="
]}
#[test]
fn encode_fails() {
let mut encoder = EncodingBuffer::new(MailType::Ascii);
let mut handle = encoder.writer();
let word = Word::try_from( "a↑b" ).unwrap();
assert_err!(do_encode_word( &word, &mut handle, None ));
handle.undo_header();
}
ec_test!{quoted_fallback, {
let word = Word::try_from( "a\"b" )?;
enc_closure!(move |handle: &mut EncodingWriter| {
do_encode_word( &word, handle, None )
})
} => ascii => [
Text r#""a\"b""#
]}
#[test]
fn encode_word_padding() {
let words = &[
( Word {
left_padding: None,
input: "abc".into(),
right_padding: None,
}, vec![
Text("abc".into())
] ),
( Word {
left_padding: Some( CFWS::SingleFws( FWS) ),
input: "abc".into(),
right_padding: None,
}, vec![
MarkFWS,
Text(" abc".into())
] ),
( Word {
left_padding: Some( CFWS::SingleFws( FWS ) ),
input: "abc".into(),
right_padding: Some( CFWS::SingleFws( FWS ) ),
}, vec![
MarkFWS,
Text(" abc".into()),
MarkFWS,
Text(" ".into())
] ),
( Word {
left_padding: None,
input: "abc".into(),
right_padding: Some( CFWS::SingleFws( FWS ) ),
}, vec![
Text("abc".into()),
MarkFWS,
Text(" ".into())
] )
];
for &( ref word, ref expection) in words.iter() {
let mut encoder = EncodingBuffer::new(MailType::Ascii);
{
let mut handle = encoder.writer();
do_encode_word( word, &mut handle, None ).unwrap();
mem::forget(handle);
}
assert_eq!(
&simplify_trace_tokens(encoder.trace.into_iter()),
expection
);
}
}
}