Browse Source

melib/imap: remove DoubleEndedIterator for ImapLineIterator

jmap-eventsource
Manos Pitsidianakis 11 months ago
parent
commit
68f9d1220b
Signed by untrusted user: epilys GPG Key ID: 73627C2F690DF710
  1. 16
      melib/src/backends/imap.rs
  2. 105
      melib/src/backends/imap/protocol_parser.rs
  3. 8
      melib/src/backends/imap/watch.rs

16
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

105
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)* )) => (
{

8
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 {

Loading…
Cancel
Save