1use super::{
2    is_body_char, is_parameter_char, parse_data_structure, parse_delimiter, parse_eol,
3    parse_string_parameter, parse_usize,
4};
5use crate::{Address, AuthResult, FilterKind, FilterPhase, MailResult, Method};
6use nom::branch::alt;
7use nom::bytes::streaming::{tag, take_while, take_while1};
8use nom::combinator::{map_res, opt};
9use nom::IResult;
10use std::net::SocketAddr;
11use std::path::PathBuf;
12
13pub(crate) fn parse_filter_auth(input: &[u8]) -> IResult<&[u8], String> {
14    let (input, _) = parse_delimiter(input)?;
15    let (input, s) = parse_string_parameter(input)?;
16    let (input, _) = parse_eol(input)?;
17    Ok((input, s))
18}
19
20pub(crate) fn parse_filter_connect(
21    input: &[u8],
22) -> IResult<&[u8], (String, String, Address, Address)> {
23    let (input, _) = parse_delimiter(input)?;
24    let (input, rdns) = parse_string_parameter(input)?;
25    let (input, _) = parse_delimiter(input)?;
26    let (input, fcrdns) = parse_string_parameter(input)?;
27    let (input, _) = parse_delimiter(input)?;
28    let (input, src) = parse_address(input)?;
29    let (input, _) = parse_delimiter(input)?;
30    let (input, dest) = parse_address(input)?;
31    let (input, _) = parse_eol(input)?;
32    Ok((input, (rdns, fcrdns, src, dest)))
33}
34
35pub(crate) fn parse_filter_data_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
36    let (input, _) = parse_delimiter(input)?;
37    let (input, s) = take_while(is_body_char)(input)?;
38    let (input, _) = parse_eol(input)?;
39    Ok((input, s))
40}
41
42pub(crate) fn parse_filter_ehlo(input: &[u8]) -> IResult<&[u8], String> {
43    let (input, _) = parse_delimiter(input)?;
44    let (input, s) = parse_string_parameter(input)?;
45    let (input, _) = parse_eol(input)?;
46    Ok((input, s))
47}
48
49pub(crate) fn parse_filter_helo(input: &[u8]) -> IResult<&[u8], String> {
50    let (input, _) = parse_delimiter(input)?;
51    let (input, s) = parse_string_parameter(input)?;
52    let (input, _) = parse_eol(input)?;
53    Ok((input, s))
54}
55
56pub(crate) fn parse_filter_mail_from(input: &[u8]) -> IResult<&[u8], String> {
57    let (input, _) = parse_delimiter(input)?;
58    let (input, s) = parse_string_parameter(input)?;
59    let (input, _) = parse_eol(input)?;
60    Ok((input, s))
61}
62
63pub(crate) fn parse_filter_rcpt_to(input: &[u8]) -> IResult<&[u8], String> {
64    let (input, _) = parse_delimiter(input)?;
65    let (input, s) = parse_string_parameter(input)?;
66    let (input, _) = parse_eol(input)?;
67    Ok((input, s))
68}
69
70pub(crate) fn parse_filter_starttls(input: &[u8]) -> IResult<&[u8], String> {
71    let (input, _) = parse_delimiter(input)?;
72    let (input, s) = parse_string_parameter(input)?;
73    let (input, _) = parse_eol(input)?;
74    Ok((input, s))
75}
76
77pub(crate) fn parse_report_link_auth(input: &[u8]) -> IResult<&[u8], (String, AuthResult)> {
78    let (input, _) = parse_delimiter(input)?;
79    let (input, username) = parse_string_parameter(input)?;
80    let (input, _) = parse_delimiter(input)?;
81    let (input, result) = parse_data_structure::<AuthResult>(input)?;
82    let (input, _) = parse_eol(input)?;
83    Ok((input, (username, result)))
84}
85
86pub(crate) fn parse_report_link_connect(
87    input: &[u8],
88) -> IResult<&[u8], (String, String, Address, Address)> {
89    let (input, _) = parse_delimiter(input)?;
90    let (input, rdns) = parse_string_parameter(input)?;
91    let (input, _) = parse_delimiter(input)?;
92    let (input, fcrdns) = parse_string_parameter(input)?;
93    let (input, _) = parse_delimiter(input)?;
94    let (input, src) = parse_address(input)?;
95    let (input, _) = parse_delimiter(input)?;
96    let (input, dest) = parse_address(input)?;
97    let (input, _) = parse_eol(input)?;
98    Ok((input, (rdns, fcrdns, src, dest)))
99}
100
101pub(crate) fn parse_report_link_greeting(input: &[u8]) -> IResult<&[u8], String> {
102    let (input, _) = parse_delimiter(input)?;
103    let (input, hostname) = parse_string_parameter(input)?;
104    let (input, _) = parse_eol(input)?;
105    Ok((input, hostname))
106}
107
108pub(crate) fn parse_report_link_identify(input: &[u8]) -> IResult<&[u8], (Method, String)> {
109    let (input, _) = parse_delimiter(input)?;
110    let (input, method) = parse_data_structure::<Method>(input)?;
111    let (input, _) = parse_delimiter(input)?;
112    let (input, identity) = parse_string_parameter(input)?;
113    let (input, _) = parse_eol(input)?;
114    Ok((input, (method, identity)))
115}
116
117pub(crate) fn parse_report_link_tls(input: &[u8]) -> IResult<&[u8], String> {
118    let (input, _) = parse_delimiter(input)?;
119    let (input, tls_string) = parse_string_parameter(input)?;
120    let (input, _) = parse_eol(input)?;
121    Ok((input, tls_string))
122}
123
124pub(crate) fn parse_report_tx_begin(input: &[u8]) -> IResult<&[u8], String> {
125    let (input, _) = parse_delimiter(input)?;
126    let (input, id) = parse_string_parameter(input)?;
127    let (input, _) = parse_eol(input)?;
128    Ok((input, id))
129}
130
131pub(crate) fn parse_report_tx_mail(input: &[u8]) -> IResult<&[u8], (String, MailResult, String)> {
132    let (input, _) = parse_delimiter(input)?;
133    let (input, id) = parse_string_parameter(input)?;
134    let (input, _) = parse_delimiter(input)?;
135    let (input, result) = parse_data_structure::<MailResult>(input)?;
136    let (input, _) = parse_delimiter(input)?;
137    let (input, addr) = parse_string_parameter(input)?;
138    let (input, _) = parse_eol(input)?;
139    Ok((input, (id, result, addr)))
140}
141
142pub(crate) fn parse_report_tx_reset(input: &[u8]) -> IResult<&[u8], Option<String>> {
143    let (input, id) = opt(parse_tx_reset_opt)(input)?;
144    let (input, _) = parse_eol(input)?;
145    Ok((input, id))
146}
147
148fn parse_tx_reset_opt(input: &[u8]) -> IResult<&[u8], String> {
149    let (input, _) = parse_delimiter(input)?;
150    let (input, id) = parse_string_parameter(input)?;
151    Ok((input, id))
152}
153
154pub(crate) fn parse_report_tx_rcpt(input: &[u8]) -> IResult<&[u8], (String, MailResult, String)> {
155    let (input, _) = parse_delimiter(input)?;
156    let (input, id) = parse_string_parameter(input)?;
157    let (input, _) = parse_delimiter(input)?;
158    let (input, result) = parse_data_structure::<MailResult>(input)?;
159    let (input, _) = parse_delimiter(input)?;
160    let (input, addr) = parse_string_parameter(input)?;
161    let (input, _) = parse_eol(input)?;
162    Ok((input, (id, result, addr)))
163}
164
165pub(crate) fn parse_report_tx_envelope(input: &[u8]) -> IResult<&[u8], (String, String)> {
166    let (input, _) = parse_delimiter(input)?;
167    let (input, msg) = parse_string_parameter(input)?;
168    let (input, _) = parse_delimiter(input)?;
169    let (input, env) = parse_string_parameter(input)?;
170    let (input, _) = parse_eol(input)?;
171    Ok((input, (msg, env)))
172}
173
174pub(crate) fn parse_report_tx_data(input: &[u8]) -> IResult<&[u8], (String, MailResult)> {
175    let (input, _) = parse_delimiter(input)?;
176    let (input, id) = parse_string_parameter(input)?;
177    let (input, _) = parse_delimiter(input)?;
178    let (input, result) = parse_data_structure::<MailResult>(input)?;
179    let (input, _) = parse_eol(input)?;
180    Ok((input, (id, result)))
181}
182
183pub(crate) fn parse_report_tx_commit(input: &[u8]) -> IResult<&[u8], (String, usize)> {
184    let (input, _) = parse_delimiter(input)?;
185    let (input, id) = parse_string_parameter(input)?;
186    let (input, _) = parse_delimiter(input)?;
187    let (input, s) = parse_usize(input)?;
188    let (input, _) = parse_eol(input)?;
189    Ok((input, (id, s)))
190}
191
192pub(crate) fn parse_report_tx_rollback(input: &[u8]) -> IResult<&[u8], String> {
193    let (input, _) = parse_delimiter(input)?;
194    let (input, id) = parse_string_parameter(input)?;
195    let (input, _) = parse_eol(input)?;
196    Ok((input, id))
197}
198
199pub(crate) fn parse_report_protocol_client(input: &[u8]) -> IResult<&[u8], String> {
200    let (input, _) = parse_delimiter(input)?;
201    let (input, cmd) = parse_string_parameter(input)?;
202    let (input, _) = parse_eol(input)?;
203    Ok((input, cmd))
204}
205
206pub(crate) fn parse_report_protocol_server(input: &[u8]) -> IResult<&[u8], String> {
207    let (input, _) = parse_delimiter(input)?;
208    let (input, res) = parse_string_parameter(input)?;
209    let (input, _) = parse_eol(input)?;
210    Ok((input, res))
211}
212
213pub(crate) fn parse_report_filter_response(
214    input: &[u8],
215) -> IResult<&[u8], (FilterPhase, String, Option<String>)> {
216    let (input, _) = parse_delimiter(input)?;
217    let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
218    let (input, _) = parse_delimiter(input)?;
219    let (input, res) = parse_string_parameter(input)?;
220    let (input, param) = opt(parse_filter_response_opt)(input)?;
221    let (input, _) = parse_eol(input)?;
222    Ok((input, (phase, res, param)))
223}
224
225fn parse_filter_response_opt(input: &[u8]) -> IResult<&[u8], String> {
226    let (input, _) = parse_delimiter(input)?;
227    parse_string_parameter(input)
228}
229
230pub(crate) fn parse_report_filter_report(
231    input: &[u8],
232) -> IResult<&[u8], (FilterKind, String, String)> {
233    let (input, _) = parse_delimiter(input)?;
234    let (input, kind) = parse_data_structure::<FilterKind>(input)?;
235    let (input, _) = parse_delimiter(input)?;
236    let (input, name) = parse_string_parameter(input)?;
237    let (input, _) = parse_delimiter(input)?;
238    let (input, message) = parse_string_parameter(input)?;
239    let (input, _) = parse_eol(input)?;
240    Ok((input, (kind, name, message)))
241}
242
243fn parse_address(input: &[u8]) -> IResult<&[u8], Address> {
244    alt((parse_unix_socket, parse_socketaddr))(input)
245}
246
247fn parse_socketaddr(input: &[u8]) -> IResult<&[u8], Address> {
248    map_res(
249        take_while1(is_parameter_char),
250        |s: &[u8]| -> Result<Address, String> {
251            let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
252            let addr = s.parse::<SocketAddr>().map_err(|e| e.to_string())?;
253            Ok(Address::Ip(addr))
254        },
255    )(input)
256}
257
258fn parse_unix_socket(input: &[u8]) -> IResult<&[u8], Address> {
259    let (input, _) = tag("unix:")(input)?;
260    map_res(
261        take_while1(is_parameter_char),
262        |s: &[u8]| -> Result<Address, String> {
263            let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
264            let addr = s.parse::<PathBuf>().map_err(|e| e.to_string())?;
265            Ok(Address::UnixSocket(addr))
266        },
267    )(input)
268}
269
270#[cfg(test)]
271mod tests {
272    use super::*;
273    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
274    use std::path::Path;
275
276    #[test]
277    fn test_ipv4_port() {
278        let res = parse_address(b"199.185.178.25:33174|");
279        assert!(res.is_ok());
280        let (i, addr) = res.unwrap();
281        assert_eq!(i, b"|");
282        match addr {
283            Address::Ip(addr) => {
284                assert!(addr.is_ipv4());
285                assert_eq!(addr.port(), 33174);
286                assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(199, 185, 178, 25)));
287            }
288            Address::UnixSocket(_) => assert!(false),
289        };
290    }
291
292    #[test]
293    fn test_ipv6_port() {
294        let res = parse_address(b"[2001:db8::42]:33174\n");
295        assert!(res.is_ok());
296        let (i, addr) = res.unwrap();
297        assert_eq!(i, b"\n");
298        match addr {
299            Address::Ip(addr) => {
300                assert!(addr.is_ipv6());
301                assert_eq!(addr.port(), 33174);
302                assert_eq!(
303                    addr.ip(),
304                    IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x42))
305                );
306            }
307            Address::UnixSocket(_) => assert!(false),
308        };
309    }
310
311    #[test]
312    fn test_unix_socket() {
313        let res = parse_address(b"unix:/var/something.sock|");
314        assert!(res.is_ok());
315        let (i, addr) = res.unwrap();
316        assert_eq!(i, b"|");
317        match addr {
318            Address::UnixSocket(addr) => {
319                assert_eq!(addr, Path::new("/var/something.sock").to_path_buf());
320            }
321            Address::Ip(_) => assert!(false),
322        };
323    }
324
325    #[test]
326    fn test_valid_parse_filter_auth() {
327        let test_vectors = vec![
328            ("|derp\n", "derp"),
329            ("|derp.derpson@example.com\r\n", "derp.derpson@example.com"),
330        ];
331        for (test, ref_auth) in test_vectors {
332            let res = parse_filter_auth(test.as_bytes());
333            assert!(res.is_ok());
334            let (input, auth) = res.unwrap();
335            assert_eq!(input, b"");
336            assert_eq!(auth, ref_auth.to_string());
337        }
338    }
339
340    #[test]
341    fn test_invalid_parse_filter_auth() {
342        let test_vectors = vec!["|\n", "|\r\n", "|derp", "|derp|derpson\n"];
343        for test in test_vectors {
344            let res = parse_filter_auth(test.as_bytes());
345            assert!(!res.is_ok());
346        }
347    }
348}