From 68f9d1220bbbd023a184aea3565149c8d45dbfe5 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Wed, 2 Dec 2020 16:15:48 +0200 Subject: [PATCH] melib/imap: remove DoubleEndedIterator for ImapLineIterator --- melib/src/backends/imap.rs | 16 ++-- melib/src/backends/imap/protocol_parser.rs | 105 ++++++++++++++------- melib/src/backends/imap/watch.rs | 8 +- 3 files changed, 82 insertions(+), 47 deletions(-) diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index 4129bb66..f1cb52b9 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -1422,10 +1422,10 @@ impl ImapType { .await?; } debug!("LIST reply: {}", String::from_utf8_lossy(&res)); - let mut lines = res.split_rn(); - /* Remove "M__ OK .." line */ - lines.next_back(); - for l in lines { + for l in res.split_rn() { + if !l.starts_with(b"*") { + continue; + } if let Ok(mut mailbox) = protocol_parser::list_mailbox_result(&l).map(|(_, v)| v) { if let Some(parent) = mailbox.parent { if mailboxes.contains_key(&parent) { @@ -1472,11 +1472,11 @@ impl ImapType { conn.send_command(b"LSUB \"\" \"*\"").await?; conn.read_response(&mut res, RequiredResponses::LSUB_REQUIRED) .await?; - let mut lines = res.split_rn(); debug!("LSUB reply: {}", String::from_utf8_lossy(&res)); - /* Remove "M__ OK .." line */ - lines.next_back(); - for l in lines { + for l in res.split_rn() { + if !l.starts_with(b"*") { + continue; + } if let Ok(subscription) = protocol_parser::list_mailbox_result(&l).map(|(_, v)| v) { if let Some(f) = mailboxes.get_mut(&subscription.hash()) { if f.special_usage() == SpecialUsageMailbox::Normal diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index 32a7a50c..4b4a22d1 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -314,46 +314,30 @@ fn test_imap_response() { assert_eq!(ImapResponse::try_from(&b"M12 NO [CANNOT] Invalid mailbox name: Name must not have \'/\' characters (0.000 + 0.098 + 0.097 secs).\r\n"[..]).unwrap(), ImapResponse::No(ResponseCode::Alert("Invalid mailbox name: Name must not have '/' characters".to_string()))); } -impl<'a> std::iter::DoubleEndedIterator for ImapLineIterator<'a> { - fn next_back(&mut self) -> Option { - if self.slice.is_empty() { - None - } else if let Some(pos) = self.slice.rfind(b"\r\n") { - if self.slice.get(..pos).unwrap_or_default().is_empty() { - self.slice = self.slice.get(..pos).unwrap_or_default(); - None - } else if let Some(prev_pos) = self.slice.get(..pos).unwrap_or_default().rfind(b"\r\n") - { - let ret = self.slice.get(prev_pos + 2..pos + 2).unwrap_or_default(); - self.slice = self.slice.get(..prev_pos + 2).unwrap_or_default(); - Some(ret) - } else { - let ret = self.slice; - self.slice = self.slice.get(ret.len()..).unwrap_or_default(); - Some(ret) - } - } else { - let ret = self.slice; - self.slice = self.slice.get(ret.len()..).unwrap_or_default(); - Some(ret) - } - } -} - impl<'a> Iterator for ImapLineIterator<'a> { type Item = &'a [u8]; fn next(&mut self) -> Option<&'a [u8]> { if self.slice.is_empty() { - None - } else if let Some(pos) = self.slice.find(b"\r\n") { - let ret = self.slice.get(..pos + 2).unwrap_or_default(); - self.slice = self.slice.get(pos + 2..).unwrap_or_default(); - Some(ret) - } else { - let ret = self.slice; - self.slice = self.slice.get(ret.len()..).unwrap_or_default(); - Some(ret) + return None; + } + let mut i = 0; + loop { + let cur_slice = &self.slice[i..]; + if let Some(pos) = cur_slice.find(b"\r\n") { + /* Skip literal continuation line */ + if cur_slice.get(pos.saturating_sub(1)) == Some(&b'}') { + i += pos + 2; + continue; + } + let ret = self.slice.get(..i + pos + 2).unwrap_or_default(); + self.slice = self.slice.get(i + pos + 2..).unwrap_or_default(); + return Some(ret); + } else { + let ret = self.slice; + self.slice = self.slice.get(ret.len()..).unwrap_or_default(); + return Some(ret); + } } } } @@ -372,6 +356,57 @@ macro_rules! to_str ( ($v:expr) => (unsafe{ std::str::from_utf8_unchecked($v) }) ); +#[test] +fn test_imap_line_iterator() { + { + let s = b"* 1429 FETCH (UID 1505 FLAGS (\\Seen) RFC822 {26}\r\nReturn-Path: ( { diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index 48a2e80b..d1a5590c 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -275,10 +275,10 @@ pub async fn examine_updates( "list return status out: {}", String::from_utf8_lossy(&response) ); - let mut lines = response.split_rn(); - /* Remove "M__ OK .." line */ - lines.next_back(); - for l in lines { + for l in response.split_rn() { + if !l.starts_with(b"*") { + continue; + } if let Ok(status) = protocol_parser::status_response(&l).map(|(_, v)| v) { if Some(mailbox_hash) == status.mailbox { if let Some(total) = status.messages {