1use abnf_core::streaming::CRLF;
3use nom::{
4 branch::alt,
5 bytes::streaming::{tag, tag_no_case},
6 combinator::{map_res, opt, recognize},
7 multi::many1,
8 sequence::tuple,
9 IResult,
10};
11
12use crate::parse::{
13 address::address_literal,
14 command::{Mailbox, Path, Reverse_path},
15 imf::{
16 datetime::date_time,
17 folding_ws_and_comment::{CFWS, FWS},
18 identification::msg_id,
19 },
20 Atom, Domain, String,
21};
22
23pub fn Return_path_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
25 let parser = tuple((tag_no_case(b"Return-Path:"), FWS, Reverse_path, CRLF));
26
27 let (remaining, parsed) = recognize(parser)(input)?;
28
29 Ok((remaining, parsed))
30}
31
32pub fn Time_stamp_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
34 let parser = tuple((tag_no_case(b"Received:"), FWS, Stamp, CRLF));
35
36 let (remaining, parsed) = recognize(parser)(input)?;
37
38 Ok((remaining, parsed))
39}
40
41pub fn Stamp(input: &[u8]) -> IResult<&[u8], &[u8]> {
47 let parser = tuple((
48 From_domain,
49 By_domain,
50 Opt_info,
51 opt(CFWS),
52 tag(b";"),
53 FWS,
54 date_time,
55 ));
56
57 let (remaining, parsed) = recognize(parser)(input)?;
58
59 Ok((remaining, parsed))
60}
61
62pub fn From_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
64 let parser = tuple((tag_no_case(b"FROM"), FWS, Extended_Domain));
65
66 let (remaining, parsed) = recognize(parser)(input)?;
67
68 Ok((remaining, parsed))
69}
70
71pub fn By_domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
73 let parser = tuple((CFWS, tag_no_case(b"BY"), FWS, Extended_Domain));
74
75 let (remaining, parsed) = recognize(parser)(input)?;
76
77 Ok((remaining, parsed))
78}
79
80pub fn Extended_Domain(input: &[u8]) -> IResult<&[u8], &[u8]> {
84 let parser = alt((
85 recognize(Domain),
86 recognize(tuple((Domain, FWS, tag(b"("), TCP_info, tag(b")")))),
87 recognize(tuple((
88 address_literal,
89 FWS,
90 tag(b"("),
91 TCP_info,
92 tag(b")"),
93 ))),
94 ));
95
96 let (remaining, parsed) = recognize(parser)(input)?;
97
98 Ok((remaining, parsed))
99}
100
101pub fn TCP_info(input: &[u8]) -> IResult<&[u8], &[u8]> {
105 let parser = alt((
106 recognize(address_literal),
107 recognize(tuple((Domain, FWS, address_literal))),
108 ));
109
110 let (remaining, parsed) = recognize(parser)(input)?;
111
112 Ok((remaining, parsed))
113}
114
115pub fn Opt_info(input: &[u8]) -> IResult<&[u8], &[u8]> {
117 let parser = tuple((
118 opt(Via),
119 opt(With),
120 opt(ID),
121 opt(For),
122 opt(Additional_Registered_Clauses),
123 ));
124
125 let (remaining, parsed) = recognize(parser)(input)?;
126
127 Ok((remaining, parsed))
128}
129
130pub fn Via(input: &[u8]) -> IResult<&[u8], &[u8]> {
132 let parser = tuple((CFWS, tag_no_case(b"VIA"), FWS, Link));
133
134 let (remaining, parsed) = recognize(parser)(input)?;
135
136 Ok((remaining, parsed))
137}
138
139pub fn With(input: &[u8]) -> IResult<&[u8], &[u8]> {
141 let parser = tuple((CFWS, tag_no_case(b"WITH"), FWS, Protocol));
142
143 let (remaining, parsed) = recognize(parser)(input)?;
144
145 Ok((remaining, parsed))
146}
147
148pub fn ID(input: &[u8]) -> IResult<&[u8], &[u8]> {
151 let parser = tuple((
152 CFWS,
153 tag_no_case(b"ID"),
154 FWS,
155 recognize(alt((recognize(Atom), msg_id))),
156 ));
157
158 let (remaining, parsed) = recognize(parser)(input)?;
159
160 Ok((remaining, parsed))
161}
162
163pub fn For(input: &[u8]) -> IResult<&[u8], &[u8]> {
165 let parser = tuple((
166 CFWS,
167 tag_no_case(b"FOR"),
168 FWS,
169 alt((recognize(Path), Mailbox)),
170 ));
171
172 let (remaining, parsed) = recognize(parser)(input)?;
173
174 Ok((remaining, parsed))
175}
176
177pub fn Additional_Registered_Clauses(input: &[u8]) -> IResult<&[u8], &[u8]> {
182 let parser = many1(tuple((CFWS, Atom, FWS, String)));
183
184 let (remaining, parsed) = recognize(parser)(input)?;
185
186 Ok((remaining, parsed))
187}
188
189pub fn Link(input: &[u8]) -> IResult<&[u8], &str> {
191 alt((map_res(tag_no_case("TCP"), std::str::from_utf8), Addtl_Link))(input)
192}
193
194pub fn Addtl_Link(input: &[u8]) -> IResult<&[u8], &str> {
200 Atom(input)
201}
202
203pub fn Protocol(input: &[u8]) -> IResult<&[u8], &str> {
205 alt((
206 map_res(tag_no_case(b"ESMTP"), std::str::from_utf8),
207 map_res(tag_no_case(b"SMTP"), std::str::from_utf8),
208 Attdl_Protocol,
209 ))(input)
210}
211
212pub fn Attdl_Protocol(input: &[u8]) -> IResult<&[u8], &str> {
218 Atom(input)
219}