mail_parser/parsers/
mime.rs1use std::borrow::Cow;
8
9use super::MessageStream;
10
11impl<'x> MessageStream<'x> {
12 pub fn seek_next_part(&mut self, boundary: &[u8]) -> bool {
13 if !boundary.is_empty() {
14 let mut last_ch = 0;
15
16 self.checkpoint();
17
18 while let Some(&ch) = self.next() {
19 if ch == b'-' && last_ch == b'-' && self.try_skip(boundary) {
20 return true;
21 }
22
23 last_ch = ch;
24 }
25
26 self.restore();
27 }
28
29 false
30 }
31
32 pub fn seek_next_part_offset(&mut self, boundary: &[u8]) -> Option<usize> {
33 let mut last_ch = b'\n';
34 let mut offset_pos = self.offset();
35 self.checkpoint();
36
37 while let Some(&ch) = self.next() {
38 if ch == b'\n' {
39 offset_pos = if last_ch == b'\r' {
40 self.offset() - 2
41 } else {
42 self.offset() - 1
43 };
44 } else if ch == b'-' && last_ch == b'-' && self.try_skip(boundary) {
45 return offset_pos.into();
46 }
47
48 last_ch = ch;
49 }
50
51 self.restore();
52
53 None
54 }
55
56 pub fn mime_part(&mut self, boundary: &[u8]) -> (usize, Cow<'x, [u8]>) {
57 let mut last_ch = b'\n';
58 let mut before_last_ch = 0;
59 let start_pos = self.offset();
60 let mut end_pos = self.offset();
61
62 self.checkpoint();
63
64 while let Some(&ch) = self.next() {
65 if ch == b'\n' {
66 end_pos = if last_ch == b'\r' {
67 self.offset() - 2
68 } else {
69 self.offset() - 1
70 };
71 } else if ch == b'-'
72 && !boundary.is_empty()
73 && last_ch == b'-'
74 && self.try_skip(boundary)
75 {
76 if before_last_ch != b'\n' {
77 end_pos = self.offset() - boundary.len() - 2;
78 }
79 return (end_pos, self.bytes(start_pos..end_pos).into());
80 }
81
82 before_last_ch = last_ch;
83 last_ch = ch;
84 }
85
86 (
87 if boundary.is_empty() {
88 self.offset()
89 } else {
90 self.restore();
91 usize::MAX
92 },
93 self.bytes(start_pos..self.len()).into(),
94 )
95 }
96
97 pub fn seek_part_end(&mut self, boundary: Option<&[u8]>) -> (usize, bool) {
98 let mut last_ch = b'\n';
99 let mut before_last_ch = 0;
100 let mut end_pos = self.offset();
101
102 if let Some(boundary) = boundary {
103 while let Some(&ch) = self.next() {
104 if ch == b'\n' {
105 end_pos = if last_ch == b'\r' {
106 self.offset() - 2
107 } else {
108 self.offset() - 1
109 };
110 } else if ch == b'-' && last_ch == b'-' && self.try_skip(boundary) {
111 if before_last_ch != b'\n' {
112 end_pos = self.offset() - boundary.len() - 2;
113 }
114 return (end_pos, true);
115 }
116
117 before_last_ch = last_ch;
118 last_ch = ch;
119 }
120
121 (self.offset(), false)
122 } else {
123 self.seek_end();
124 (self.offset(), true)
125 }
126 }
127
128 pub fn is_multipart_end(&mut self) -> bool {
129 self.checkpoint();
130
131 match (self.next(), self.peek()) {
132 (Some(b'\r'), Some(b'\n')) => {
133 self.next();
134 false
135 }
136 (Some(b'-'), Some(b'-')) => {
137 self.next();
138 true
139 }
140 (Some(b'\n'), _) => false,
141 (Some(&a), _) if a.is_ascii_whitespace() => {
142 self.skip_crlf();
143 false
144 }
145 _ => {
146 self.restore();
147 false
148 }
149 }
150 }
151
152 #[inline(always)]
153 pub fn skip_crlf(&mut self) {
154 while let Some(ch) = self.peek() {
155 match ch {
156 b'\r' | b' ' | b'\t' => {
157 self.next();
158 }
159 b'\n' => {
160 self.next();
161 break;
162 }
163 _ => break,
164 }
165 }
166 }
167}