1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use quoted_string::spec::{
    GeneralQSSpec,
    PartialCodePoint,
    WithoutQuotingValidator
};

use media_type_impl_utils::quoted_string;
use ::MailType;

/// A Quoted String specification in context of Mail ([rfc5322](https://tools.ietf.org/html/rfc5322#section-2.2.3))
///
/// This implementation of MailQsSpec _does not_ include support for the obsolete parts of the grammar
/// as it's meant for generation/encoding and no obsolete parts should be generated at all (Through
/// a parser would have to be able to parse them for compatibility reasons).
///
#[derive(Copy, Clone, Debug, Default)]
pub struct MailQsSpec;

impl GeneralQSSpec for MailQsSpec {
    type Quoting = quoted_string::NormalQuoting;
    type Parsing = quoted_string::MimeParsing;
}


/// A Quoted String specification in context of Mail ([rfc5322](https://tools.ietf.org/html/rfc5322#section-2.2.3))
///
/// This implementation of MailQsSpec _does not_ include support for the obsolete parts of the grammar
/// as it's meant for generation/encoding and no obsolete parts should be generated at all (Through
/// a parser would have to be able to parse them for compatibility reasons).
#[derive(Copy, Clone, Debug, Default)]
pub struct InternationalizedMailQsSpec;

impl GeneralQSSpec for InternationalizedMailQsSpec {
    type Quoting = quoted_string::NormalUtf8Quoting;
    type Parsing = quoted_string::MimeParsingUtf8;
}

pub use self::quoted_string::MimeTokenValidator as UnquotedTokenValidator;


#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct UnquotedATextValidator {
    mail_type: MailType
}

impl UnquotedATextValidator {
    pub fn new(mail_type: MailType) -> Self {
        UnquotedATextValidator { mail_type }
    }
}

impl WithoutQuotingValidator for UnquotedATextValidator {
    fn next(&mut self, pcp: PartialCodePoint) -> bool {
       is_atext(pcp, self.mail_type)
    }
}


#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct UnquotedDotAtomTextValidator {
    mail_type: MailType,
    allow_dot: bool
}

impl UnquotedDotAtomTextValidator {
    pub fn new(mail_type: MailType) -> Self {
        UnquotedDotAtomTextValidator { mail_type, allow_dot: false }
    }
}

impl WithoutQuotingValidator for UnquotedDotAtomTextValidator {
    fn next(&mut self, pcp: PartialCodePoint) -> bool {
        if is_atext(pcp, self.mail_type) {
            self.allow_dot = true;
            true
        } else if self.allow_dot && pcp.as_u8() == b'.' {
            self.allow_dot = false;
            true
        } else {
            false
        }
    }

    fn end(&self) -> bool {
        // it can't end in a dot so it's the same as allow_dot
        // (as empty or starting with a dot is also not allowed)
        self.allow_dot
    }
}


//TODO replace with lookup table (which could be placed in `::grammar`)!
fn is_atext(pcp: PartialCodePoint, mail_type: MailType) -> bool {
    use grammar::is_special;
    let iu8 = pcp.as_u8();
    if iu8 > 0x7f {
        mail_type == MailType::Internationalized
    } else {
        b'!' <= iu8 && iu8 <= b'~' && !is_special(iu8 as char)
    }
}