1use chrono::{DateTime, FixedOffset};
2use nom::combinator::map;
3
4use crate::header;
5use crate::imf::address::{address_list, mailbox_list, nullable_address_list, AddressList};
6use crate::imf::datetime::section as date;
7use crate::imf::identification::{msg_id, msg_list, MessageID, MessageIDList};
8use crate::imf::mailbox::{mailbox, AddrSpec, MailboxList, MailboxRef};
9use crate::imf::mime::{version, Version};
10use crate::imf::trace::{received_log, return_path, ReceivedLog};
11use crate::text::misc_token::{phrase_list, unstructured, PhraseList, Unstructured};
12
13#[derive(Debug, PartialEq)]
14pub enum Field<'a> {
15 Date(Option<DateTime<FixedOffset>>),
17
18 From(MailboxList<'a>),
20 Sender(MailboxRef<'a>),
21 ReplyTo(AddressList<'a>),
22
23 To(AddressList<'a>),
25 Cc(AddressList<'a>),
26 Bcc(AddressList<'a>),
27
28 MessageID(MessageID<'a>),
30 InReplyTo(MessageIDList<'a>),
31 References(MessageIDList<'a>),
32
33 Subject(Unstructured<'a>),
35 Comments(Unstructured<'a>),
36 Keywords(PhraseList<'a>),
37
38 Received(ReceivedLog<'a>),
41 ReturnPath(Option<AddrSpec<'a>>),
42
43 MIMEVersion(Version),
44}
45impl<'a> TryFrom<&header::Field<'a>> for Field<'a> {
46 type Error = ();
47 fn try_from(f: &header::Field<'a>) -> Result<Self, Self::Error> {
48 let content = match f {
49 header::Field::Good(header::Kv2(key, value)) => {
50 match key.to_ascii_lowercase().as_slice() {
51 b"date" => map(date, Field::Date)(value),
52 b"from" => map(mailbox_list, Field::From)(value),
53 b"sender" => map(mailbox, Field::Sender)(value),
54 b"reply-to" => map(address_list, Field::ReplyTo)(value),
55 b"to" => map(address_list, Field::To)(value),
56 b"cc" => map(address_list, Field::Cc)(value),
57 b"bcc" => map(nullable_address_list, Field::Bcc)(value),
58 b"message-id" => map(msg_id, Field::MessageID)(value),
59 b"in-reply-to" => map(msg_list, Field::InReplyTo)(value),
60 b"references" => map(msg_list, Field::References)(value),
61 b"subject" => map(unstructured, Field::Subject)(value),
62 b"comments" => map(unstructured, Field::Comments)(value),
63 b"keywords" => map(phrase_list, Field::Keywords)(value),
64 b"return-path" => map(return_path, Field::ReturnPath)(value),
65 b"received" => map(received_log, Field::Received)(value),
66 b"mime-version" => map(version, Field::MIMEVersion)(value),
67 _ => return Err(()),
68 }
69 }
70 _ => return Err(()),
71 };
72
73 content.map(|(_, content)| content).or(Err(()))
74 }
75}