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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
use std::{
    sync::Arc,
    default::Default,
    ops::{Deref, DerefMut}
};

#[cfg(feature="serde")]
use serde::{
    Serialize, Deserialize,
    ser::{Serializer},
    de::{Deserializer}
};

use internals::bind::{base64, quoted_printable};
use headers::header_components::{
    MediaType,
    FileMeta,
    TransferEncoding,
    ContentId
};



/// POD type containing FileMeta, Content-Type and Content-Id
///
/// The file meta contains optional information like file name and read
/// as well as last modification data.
///
/// The media type will be used for the content type header which is used
/// to determine how a mail client will handle the file. It is also used
/// to get a hint on how to best transfer encode the file.
///
/// The content id is used to identify the "data" and refer to it
/// from some other place. For example in a mail the html body could
/// refer to a image contained in the mail to embed it in the mail.
///
/// As Content-Id's are supposed to be world unique they could also
/// be used for some caching and similar but that plays hardly any
/// role any more, except maybe for "external" mail bodies.
#[derive(Debug, Clone)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct Metadata {
    /// File meta like file name or file read time.
    #[cfg_attr(feature="serde", serde(flatten))]
    pub file_meta: FileMeta,

    /// The media type of the data.
    pub media_type: MediaType,

    /// The content id associated with the data.
    pub content_id: ContentId
}

impl Deref for Metadata {
    type Target = FileMeta;

    fn deref(&self) -> &Self::Target {
        &self.file_meta
    }
}

impl DerefMut for Metadata {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.file_meta
    }
}

/// A type containing some data and metadata for it.
///
/// This often, but not always, corresponds to data which could potentially
/// have been a file in a file system. For example a image or a text
/// document.
///
/// This type is mainly used when having auto generated content as content
/// provided through a file should be loaded from a source and as such
/// will be directly loaded and transfer encoded.
///
/// # Clone
///
/// `Data` is made to be cheap to clone and share.
/// For this it uses `Arc` internally.
#[derive(Debug, Clone)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct Data {
    #[cfg_attr(feature="serde", serde(with="arc_buffer_serde"))]
    buffer: Arc<[u8]>,
    #[cfg_attr(feature="serde", serde(flatten))]
    #[cfg_attr(feature="serde", serde(with="arc_serde"))]
    meta: Arc<Metadata>
}


impl Data {

    /// Create a new data instance.
    pub fn new(
        buffer: impl Into<Arc<[u8]>>,
        meta: impl Into<Arc<Metadata>>
    ) -> Self {
        Data {
            buffer: buffer.into(),
            meta: meta.into()
        }
    }

    pub fn plain_text(text: impl Into<String>, cid: ContentId) -> Data {
        let text = text.into();
        let buf = text.into_bytes();
        let meta = Metadata {
            file_meta: Default::default(),
            media_type: MediaType::parse("text/plain; charset=utf-8").unwrap(),
            content_id: cid
        };
        Self::new(buf, meta)
    }

    /// Access the raw data buffer of this instance.
    pub fn buffer(&self) -> &Arc<[u8]> {
        &self.buffer
    }

    /// Access the metadata.
    pub fn metadata(&self) -> &Arc<Metadata> {
        &self.meta
    }

    /// Access the file meta metadata.Fn
    pub fn file_meta(&self) -> &FileMeta {
        &self.meta.file_meta
    }

    /// Access the content type.
    pub fn media_type(&self) -> &MediaType {
        &self.meta.media_type
    }

    /// Access the content id.
    pub fn content_id(&self) -> &ContentId {
        &self.meta.content_id
    }

    /// Transfer encode the given data.
    ///
    /// This function will be called by the context implementation when
    /// loading and/or transfer encoding data. The context implementation
    /// might also not call it if it has a cached version of the transfer
    /// encoded data.
    ///
    /// This functions expect a boundary pool and will remove all boundaries
    /// which do appear in the encoded representation of the data.
    #[inline(always)]
    pub fn transfer_encode(
        &self,
        encoding_hint: TransferEncodingHint,
    ) -> EncData {
        // delegated to free function at end of file for
        // readability
        transfer_encode(self, encoding_hint)
    }
}

/// `EncData` is like `Data` but the buffer contains transfer encoded data.
///
/// # Clone
///
/// `Data` is made to be cheap to clone and share.
/// For this it uses `Arc` internally.
#[derive(Debug, Clone)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct EncData {
    #[cfg_attr(feature="serde", serde(with="arc_buffer_serde"))]
    buffer: Arc<[u8]>,
    #[cfg_attr(feature="serde", serde(flatten))]
    #[cfg_attr(feature="serde", serde(with="arc_serde"))]
    meta: Arc<Metadata>,
    encoding: TransferEncoding
}

impl EncData {

    /// Create a new instance from transfer encoded data
    /// as well as metadata and the encoding used to transfer
    /// encode the data.
    ///
    /// If the `buffer` was created by transfer encoding data
    /// from a `Data` instance the `Arc<Metadata>` from that
    /// `Data` instance can be passed in directly as `meta`.
    pub(crate) fn new(
        buffer: impl Into<Arc<[u8]>>,
        meta: impl Into<Arc<Metadata>>,
        encoding: TransferEncoding
    ) -> Self {
        EncData {
            buffer: buffer.into(),
            meta: meta.into(),
            encoding
        }
    }

    /// Access the raw transfer encoded data.
    pub fn transfer_encoded_buffer(&self) -> &Arc<[u8]> {
        &self.buffer
    }

    /// Access the metadata.
    pub fn metadata(&self) -> &Arc<Metadata> {
        &self.meta
    }

    /// Access the file meta metadata.Fn
    pub fn file_meta(&self) -> &FileMeta {
        &self.meta.file_meta
    }

    /// Access the content type.
    pub fn media_type(&self) -> &MediaType {
        &self.meta.media_type
    }


    /// Access the transfer encoding used to encode the buffer.
    pub fn encoding(&self) -> TransferEncoding {
        self.encoding
    }

    /// Access the content id.
    ///
    /// The content id is for the data itself so it should not
    /// change just because the data had been transfer encoded.
    ///
    /// # Note about fixed newlines:
    ///
    /// The encoding functions of this library will always "fix"
    /// line endings even if the transfer encoding is to not have
    /// any encoding, it could be said that this is a modification
    /// of the data and as such the content id should change. But
    /// as this is done _always_ and as such only the transfer encoded
    /// data is "send" out this works out fine.
    pub fn content_id(&self) -> &ContentId {
        &self.meta.content_id
    }
}

/// Hint to change how data should be transfer encoded.
#[derive(Debug, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub enum TransferEncodingHint {
    /// Use Base64 encoding.
    UseBase64,

    /// Use Quoted-Printable encoding.
    UseQuotedPrintable,

    // /// Do not assume Mime8Bit is available.
    // ///
    // /// As such do not encode ascii/utf-8 "as is" (e.g. not encoding them).
    // ///
    // /// Note: This is the default until I'm more sure about the whole thing
    // /// with puthing things in unecoded.
    // DoNotUseNoEncoding,

    /// No hint for transfer encoding.
    NoHint,

    #[cfg_attr(feature="serde", serde(skip))]
    #[doc(hidden)]
    __NonExhaustive { }
}

impl Default for TransferEncodingHint {
    fn default() -> Self {
        TransferEncodingHint::UseBase64
    }
}

/// Transfer encodes Data.
///
/// Util we have a reasonable "non latin letter text" heuristic
/// or enable none encoded text as default this will always encode
/// with `Base64` except if asked not to do so.
///
/// # Panic
///
/// Panics if TransferEncodingHint::__NonExhaustive
/// is passed to the function.
fn transfer_encode(
    data: &Data,
    encoding_hint: TransferEncodingHint,
) -> EncData {
    use self::TransferEncodingHint::*;

    match encoding_hint {
        UseQuotedPrintable => tenc_quoted_printable(data),
        UseBase64 | NoHint => tenc_base64(data),
        __NonExhaustive { .. } => panic!("__NonExhaustive encoding should not be passed to any place")
    }
}

fn tenc_base64(data: &Data) -> EncData {
    let enc_data = base64::normal_encode(data.buffer())
        .into_bytes();

    EncData::new(enc_data, data.metadata().clone(),
        TransferEncoding::Base64)
}

fn tenc_quoted_printable(data: &Data) -> EncData {
    let enc_data = quoted_printable::normal_encode(data.buffer())
        .into_bytes();

    EncData::new(enc_data, data.metadata().clone(),
        TransferEncoding::QuotedPrintable)
}


#[cfg(feature="serde")]
mod arc_buffer_serde {
    use super::*;

    pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Arc<[u8]>, D::Error>
        where D: Deserializer<'de>
    {
        let bytes = <Vec<u8>>::deserialize(deserializer)?;
        Ok(bytes.into())
    }

    pub(crate) fn serialize<S>(data: &Arc<[u8]>, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        serializer.serialize_bytes(data)
    }
}

#[cfg(feature="serde")]
mod arc_serde {
    use super::*;

    pub(crate) fn deserialize<'de, OUT, D>(deserializer: D) -> Result<Arc<OUT>, D::Error>
        where D: Deserializer<'de>, OUT: Deserialize<'de>
    {
        let value = OUT::deserialize(deserializer)?;
        Ok(Arc::new(value))
    }

    pub(crate) fn serialize<S, IN>(data: &Arc<IN>, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer, IN: Serialize
    {
        IN::serialize(&**data, serializer)
    }
}