summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-12-02 16:15:48 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-12-02 17:10:43 +0200
commit68f9d1220bbbd023a184aea3565149c8d45dbfe5 (patch)
tree9908e3f8739eea9dabaacc73ed058c0c2260b1c7
parent1408690a9a0d0976c17397be33bd4e886088a914 (diff)
melib/imap: remove DoubleEndedIterator for ImapLineIterator
-rw-r--r--melib/src/backends/imap.rs16
-rw-r--r--melib/src/backends/imap/protocol_parser.rs105
-rw-r--r--melib/src/backends/imap/watch.rs8
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<Self::Item> {
- 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: <blah blah...\r\n* 1430 FETCH (UID 1506 FLAGS (\\Seen)\r\n* 1431 FETCH (UID 1507 FLAGS (\\Seen)\r\n* 1432 FETCH (UID 1500 FLAGS (\\Seen) RFC822 {4}\r\nnull\r\n";
+ let line_a =
+ b"* 1429 FETCH (UID 1505 FLAGS (\\Seen) RFC822 {26}\r\nReturn-Path: <blah blah...\r\n";
+ let line_b = b"* 1430 FETCH (UID 1506 FLAGS (\\Seen)\r\n";
+ let line_c = b"* 1431 FETCH (UID 1507 FLAGS (\\Seen)\r\n";
+ let line_d = b"* 1432 FETCH (UID 1500 FLAGS (\\Seen) RFC822 {4}\r\nnull\r\n";
+
+ let mut iter = s.split_rn();
+
+ assert_eq!(to_str!(iter.next().unwrap()), to_str!(line_a));
+ assert_eq!(to_str!(iter.next().unwrap()), to_str!(line_b));
+ assert_eq!(to_str!(iter.next().unwrap()), to_str!(line_c));
+ assert_eq!(to_str!(iter.next().unwrap()), to_str!(line_d));
+ assert!(iter.next().is_none());
+ }
+
+ {
+ let s = b"* 23 FETCH (FLAGS (\\Seen) RFC822.SIZE 44827)\r\n";
+ let mut iter = s.split_rn();
+ assert_eq!(to_str!(iter.next().unwrap()), to_str!(s));
+ assert!(iter.next().is_none());
+ }
+
+ {
+ let s = b"";
+ let mut iter = s.split_rn();
+ assert!(iter.next().is_none());
+ }
+ {
+ let s = b"* 172 EXISTS\r\n* 1 RECENT\r\n* OK [UNSEEN 12] Message 12 is first unseen\r\n* OK [UIDVALIDITY 3857529045] UIDs valid\r\n* OK [UIDNEXT 4392] Predicted next UID\r\n* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n* OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)] Limited\r\n* OK [NOMODSEQ] Sorry, this mailbox format doesn't support modsequences\r\n* A142 OK [READ-WRITE] SELECT completed\r\n";
+ let mut iter = s.split_rn();
+ for l in &[
+ &b"* 172 EXISTS\r\n"[..],
+ &b"* 1 RECENT\r\n"[..],
+ &b"* OK [UNSEEN 12] Message 12 is first unseen\r\n"[..],
+ &b"* OK [UIDVALIDITY 3857529045] UIDs valid\r\n"[..],
+ &b"* OK [UIDNEXT 4392] Predicted next UID\r\n"[..],
+ &b"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n"[..],
+ &b"* OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)] Limited\r\n"[..],
+ &b"* OK [NOMODSEQ] Sorry, this mailbox format doesn't support modsequences\r\n"[..],
+ &b"* A142 OK [READ-WRITE] SELECT completed\r\n"[..],
+ ] {
+ assert_eq!(to_str!(iter.next().unwrap()), to_str!(l));
+ }
+ assert!(iter.next().is_none());
+ }
+}
+
/*macro_rules! dbg_dmp (
($i: expr, $submac:ident!( $($args:tt)* )) => (
{
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 {