deltachat/headerdef.rs
1//! # List of email headers.
2
3use mailparse::{MailHeader, MailHeaderMap};
4
5#[derive(Debug, Display, Clone, PartialEq, Eq, IntoStaticStr)]
6#[strum(serialize_all = "kebab_case")]
7#[allow(missing_docs)]
8pub enum HeaderDef {
9 MessageId,
10 Subject,
11 Date,
12 From_,
13 To,
14 AutoSubmitted,
15
16 /// Carbon copy.
17 Cc,
18 Disposition,
19
20 /// Used in the "Body Part Header" of MDNs as of RFC 8098.
21 /// Indicates the Message-ID of the message for which the MDN is being issued.
22 OriginalMessageId,
23
24 /// Delta Chat extension for message IDs in combined MDNs
25 AdditionalMessageIds,
26
27 /// Outlook-SMTP-server replace the `Message-ID:`-header
28 /// and write the original ID to `X-Microsoft-Original-Message-ID`.
29 /// To sort things correctly and to not show outgoing messages twice,
30 /// we need to check that header as well.
31 XMicrosoftOriginalMessageId,
32
33 /// Thunderbird header used to store Draft information.
34 ///
35 /// Thunderbird 78.11.0 does not set \Draft flag on messages saved as "Template", but sets this
36 /// header, so it can be used to ignore such messages.
37 XMozillaDraftInfo,
38
39 /// Mailing list ID defined in [RFC 2919](https://tools.ietf.org/html/rfc2919).
40 ListId,
41 ListPost,
42
43 /// List-Help header defined in [RFC 2369](https://datatracker.ietf.org/doc/html/rfc2369).
44 ListHelp,
45 References,
46
47 /// In-Reply-To header containing Message-ID of the parent message.
48 InReplyTo,
49
50 /// Used to detect mailing lists if contains "list" value
51 /// as described in [RFC 3834](https://tools.ietf.org/html/rfc3834)
52 Precedence,
53
54 ContentType,
55 ContentId,
56 ChatVersion,
57 ChatGroupId,
58 ChatGroupName,
59 ChatGroupNameChanged,
60 ChatGroupNameTimestamp,
61 ChatVerified,
62 ChatGroupAvatar,
63 ChatUserAvatar,
64 ChatVoiceMessage,
65 ChatGroupMemberRemoved,
66 ChatGroupMemberAdded,
67 ChatContent,
68
69 /// Past members of the group.
70 ChatGroupPastMembers,
71
72 /// Space-separated timestamps of member addition
73 /// for members listed in the `To` field
74 /// followed by timestamps of member removal
75 /// for members listed in the `Chat-Group-Past-Members` field.
76 ChatGroupMemberTimestamps,
77
78 /// Space-separated PGP key fingerprints
79 /// of group members listed in the `To` field
80 /// followed by fingerprints
81 /// of past members listed in the `Chat-Group-Past-Members` field.
82 ChatGroupMemberFpr,
83
84 /// Duration of the attached media file.
85 ChatDuration,
86
87 ChatDispositionNotificationTo,
88 ChatWebrtcRoom,
89 ChatWebrtcAccepted,
90
91 /// This message deletes the messages listed in the value by rfc724_mid.
92 ChatDelete,
93
94 /// This message obsoletes the text of the message defined here by rfc724_mid.
95 ChatEdit,
96
97 /// [Autocrypt](https://autocrypt.org/) header.
98 Autocrypt,
99 AutocryptGossip,
100 AutocryptSetupMessage,
101 SecureJoin,
102
103 /// Deprecated header containing Group-ID in `vg-request-with-auth` message.
104 ///
105 /// It is not used by Alice as Alice knows the group corresponding to the AUTH token.
106 /// Bob still sends it for backwards compatibility.
107 SecureJoinGroup,
108 SecureJoinFingerprint,
109 SecureJoinInvitenumber,
110 SecureJoinAuth,
111 Sender,
112
113 /// Ephemeral message timer.
114 EphemeralTimer,
115 Received,
116
117 /// A header that includes the results of the DKIM, SPF and DMARC checks.
118 /// See <https://datatracker.ietf.org/doc/html/rfc8601>
119 AuthenticationResults,
120
121 /// Node address from iroh where direct addresses have been removed.
122 ///
123 /// The node address sent in this header must have
124 /// a non-null relay URL as contacting home relay
125 /// is the only way to reach the node without
126 /// direct addresses and global discovery.
127 IrohNodeAddr,
128
129 /// Advertised gossip topic for one webxdc.
130 IrohGossipTopic,
131
132 #[cfg(test)]
133 TestHeader,
134}
135
136impl HeaderDef {
137 /// Returns the corresponding header string.
138 pub fn get_headername(&self) -> &'static str {
139 self.into()
140 }
141}
142
143#[allow(missing_docs)]
144pub trait HeaderDefMap {
145 /// Returns requested header value if it exists.
146 fn get_header_value(&self, headerdef: HeaderDef) -> Option<String>;
147
148 /// Returns requested header if it exists.
149 fn get_header(&self, headerdef: HeaderDef) -> Option<&MailHeader<'_>>;
150}
151
152impl HeaderDefMap for [MailHeader<'_>] {
153 fn get_header_value(&self, headerdef: HeaderDef) -> Option<String> {
154 self.get_first_value(headerdef.get_headername())
155 }
156 fn get_header(&self, headerdef: HeaderDef) -> Option<&MailHeader<'_>> {
157 self.get_first_header(headerdef.get_headername())
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 /// Test that kebab_case serialization works as expected
167 fn kebab_test() {
168 assert_eq!(HeaderDef::From_.get_headername(), "from");
169
170 assert_eq!(HeaderDef::TestHeader.get_headername(), "test-header");
171 }
172
173 #[test]
174 /// Test that headers are parsed case-insensitively
175 fn test_get_header_value_case() {
176 let (headers, _) =
177 mailparse::parse_headers(b"fRoM: Bob\naUtoCryPt-SeTup-MessAge: v99").unwrap();
178 assert_eq!(
179 headers.get_header_value(HeaderDef::AutocryptSetupMessage),
180 Some("v99".to_string())
181 );
182 assert_eq!(
183 headers.get_header_value(HeaderDef::From_),
184 Some("Bob".to_string())
185 );
186 assert_eq!(headers.get_header_value(HeaderDef::Autocrypt), None);
187 }
188}