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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use lut::{Table, Any};
use lookup_tables::{
    MediaTypeChars,
    QText,
    QTextWs,
    DQuoteOrEscape, Ws,
    Token
};
use qs::error::CoreError;
use qs::spec::{
    PartialCodePoint,
    ParsingImpl,
    State,
    WithoutQuotingValidator,
    QuotingClassifier, QuotingClass,
};

use super::{MimeParsingExt, FWSState};

/// a type providing a `WithoutQuotingValidator` for token wrt. the mime grammar
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MimeTokenValidator;

impl MimeTokenValidator {
    /// create a new MimeTokenValidator
    pub fn new() -> Self {
        Default::default()
    }
}

impl WithoutQuotingValidator for MimeTokenValidator {
    fn next(&mut self, pcp: PartialCodePoint) -> bool {
        MediaTypeChars::check_at(pcp.as_u8() as usize, Token)
    }
    fn end(&self) -> bool {
        true
    }
}


/// a type providing a `QuotingClassifier` impl wrt. the obs mime grammar
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MimeObsQuoting;

impl QuotingClassifier for MimeObsQuoting {
    fn classify_for_quoting(pcp: PartialCodePoint) -> QuotingClass {
        let iu8 = pcp.as_u8();
        if MediaTypeChars::check_at(iu8 as usize, QTextWs) {
            QuotingClass::QText
        } else if iu8 <= 0x7f {
            QuotingClass::NeedsQuoting
        } else {
            QuotingClass::Invalid
        }
    }
}

/// a type providing a `QuotingClassifier` impl wrt. the internationalized, obs mime grammar
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MimeObsUtf8Quoting;

impl QuotingClassifier for MimeObsUtf8Quoting {
    fn classify_for_quoting(pcp: PartialCodePoint) -> QuotingClass {
        let iu8 = pcp.as_u8();
        if iu8 > 0x7f || MediaTypeChars::check_at(iu8 as usize, QTextWs) {
            QuotingClass::QText
        } else {
            QuotingClass::NeedsQuoting
        }
    }
}



macro_rules! def_mime_parsing {
    (
        $(#[$meta:meta])*
        pub struct $name:ident {
            utf8 = $utf8:tt;
            obsolte_syntax = $obs:tt;
        }
        fn can_be_quoted($nm:ident: PartialCodePoint) -> bool
            $body:block
    ) => (
        $(#[$meta])*
        #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
        pub struct $name(FWSState);
        impl MimeParsingExt for $name {
            const ALLOW_UTF8: bool = $utf8;
            const OBS: bool = $obs;

            fn custom_state(state: FWSState, emit: bool) -> (State<Self>, bool) {
                (State::Custom($name(state)), emit)
            }
        }

        impl ParsingImpl for $name {
            fn can_be_quoted($nm: PartialCodePoint) -> bool {
                $body
            }

            fn handle_normal_state(bch: PartialCodePoint) -> Result<(State<Self>, bool), CoreError> {
                <Self as MimeParsingExt>::handle_normal_state(bch)
            }

            fn advance(&self, bch: PartialCodePoint) -> Result<(State<Self>, bool), CoreError> {
                self.0.advance(bch)
            }
        }
    );
}

def_mime_parsing! {
    /// a type providing a `ParsingImpl`/`MimeParsingExt` impl wrt. the obs mime grammar
    pub struct MimeObsParsing {
        utf8 = false;
        obsolte_syntax = true;
    }
    fn can_be_quoted(bch: PartialCodePoint) -> bool {
        // obs syntax allows any us-ascii in quoted-pairs
        bch.as_u8() <= 0x7f
    }
}

def_mime_parsing! {
    /// a type providing a `ParsingImpl`/`MimeParsingExt` impl wrt. the internationalized obs mime grammar
    pub struct MimeObsParsingUtf8 {
        utf8 = true;
        obsolte_syntax = true;
    }
    fn can_be_quoted(bch: PartialCodePoint) -> bool {
        // Internationalized Mail does not extend quoted-pairs just qtext ...
        // obs syntax allows any us-ascii in quoted-pairs
        bch.as_u8() <= 0x7f
    }
}

def_mime_parsing! {
    /// a type providing a `ParsingImpl`/`MimeParsingExt` impl wrt. the modern, us-ascii mime grammar
    pub struct MimeParsing {
        utf8 = false;
        obsolte_syntax = false;
    }
    fn can_be_quoted(bch: PartialCodePoint) -> bool {
        // VCHAR / WS == QText + Ws + DQuoteOrEscape
        let idx = bch.as_u8() as usize;
        MediaTypeChars::check_at(idx, Any::new(Ws) | QText | DQuoteOrEscape)
    }
}

def_mime_parsing! {
    /// a type providing a `ParsingImpl`/`MimeParsingExt` impl wrt. the internationalized, modern mime grammar
    pub struct MimeParsingUtf8 {
        utf8 = true;
        obsolte_syntax = false;
    }
    fn can_be_quoted(bch: PartialCodePoint) -> bool {
        // Internationalized Mail does not extend quoted-pairs just qtext ...
        let idx = bch.as_u8() as usize;
        MediaTypeChars::check_at(idx, Any::new(Ws) | QText | DQuoteOrEscape)
    }
}