email_parser/parsing/
message.rs1use crate::parsing::fields::{fields, Field};
2use crate::prelude::*;
3use std::borrow::Cow;
4
5pub fn line(input: &[u8]) -> Res<Cow<str>> {
6 let max_idx = std::cmp::min(input.len(), 998);
7
8 unsafe {
10 for i in 0..max_idx {
11 if !is_text(*input.get_unchecked(i)) {
12 return Ok((
13 input.get_unchecked(i..),
14 from_slice(input.get_unchecked(..i)),
15 ));
16 }
17 }
18
19 Ok((
20 input.get_unchecked(max_idx..),
21 from_slice(input.get_unchecked(..max_idx)),
22 ))
23 }
24}
25
26pub fn check_line(input: &[u8]) -> Res<()> {
27 let max_idx = std::cmp::min(input.len(), 998);
28
29 unsafe {
31 for i in 0..max_idx {
32 if !is_text(*input.get_unchecked(i)) {
33 return Ok((input.get_unchecked(i..), ()));
34 }
35 }
36
37 Ok((input.get_unchecked(max_idx..), ()))
38 }
39}
40
41pub fn body_lines(input: &[u8]) -> Result<Vec<Cow<str>>, Error> {
42 if input.is_empty() {
43 return Ok(Vec::new());
44 }
45 let (mut input, ()) = tag(input, b"\r\n")?;
46
47 let mut lines = Vec::new();
48 loop {
49 let (new_input, new_line) = line(input)?;
50 match tag(new_input, b"\r\n") {
51 Ok((new_input, ())) => input = new_input,
52 Err(e) => {
53 if new_input.is_empty() {
54 lines.push(new_line);
55 break;
56 } else {
57 return Err(e);
58 }
59 }
60 }
61 lines.push(new_line);
62 }
63
64 Ok(lines)
65}
66
67pub fn body(input: &[u8]) -> Result<Option<Cow<str>>, Error> {
68 if input.is_empty() {
69 return Ok(None);
70 }
71
72 let (mut new_input, ()) = tag(input, b"\r\n")?;
73
74 loop {
75 let (new_input2, ()) = check_line(new_input)?;
76 match tag(new_input2, b"\r\n") {
77 Ok((new_input2, ())) => new_input = new_input2,
78 Err(e) => {
79 if new_input2.is_empty() {
80 break;
81 } else {
82 return Err(e);
83 }
84 }
85 }
86 }
87
88 Ok(Some(unsafe {
89 from_slice(input.get_unchecked(2..))
91 }))
92}
93
94#[cfg(not(feature = "mime"))]
95pub fn parse_message(input: &[u8]) -> Result<(Vec<Field>, Option<Cow<str>>), Error> {
96 let (input, fields) = fields(input)?;
97 let body = body(input)?;
98
99 Ok((fields, body))
100}
101
102#[cfg(feature = "mime")]
103pub fn parse_message(input: &[u8]) -> Result<(Vec<Field>, Option<&[u8]>), Error> {
104 let (input, fields) = fields(input)?;
105
106 if input.is_empty() {
107 return Ok((fields, None));
108 }
109
110 let (new_input, ()) = tag(input, b"\r\n")?;
111
112 Ok((fields, Some(new_input)))
113}
114
115#[cfg(test)]
116mod test {
117 use super::*;
118
119 #[test]
120 fn test_body() {
121 assert_eq!(
122 line(b"This is a line\r\nAnd this is a second line")
123 .unwrap()
124 .1,
125 "This is a line"
126 );
127 assert_eq!(
128 body_lines(b"\r\nThis is a line\r\nAnd this is a second line")
129 .unwrap()
130 .len(),
131 2
132 );
133 assert_eq!(
134 body(b"\r\nThis is a line\r\nAnd this is a second line")
135 .unwrap()
136 .unwrap(),
137 "This is a line\r\nAnd this is a second line"
138 );
139 }
140
141 #[test]
142 fn test_full_message() {
143 }
145}