diff options
author | Alex Auvolat <alex@adnab.me> | 2022-07-13 15:26:00 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2022-07-13 15:26:00 +0200 |
commit | c703e3e2b813cf74fc2d3d87b045dcc9fb93d190 (patch) | |
tree | e7aa3a1ca2922207bad4275c4a2afb111bf2f13a /src/imap/command/authenticated.rs | |
parent | 15a354f9499c82dff69db71d92097bec51ee54bf (diff) | |
download | aerogramme-c703e3e2b813cf74fc2d3d87b045dcc9fb93d190.tar.gz aerogramme-c703e3e2b813cf74fc2d3d87b045dcc9fb93d190.zip |
Fix list wildcards
Diffstat (limited to 'src/imap/command/authenticated.rs')
-rw-r--r-- | src/imap/command/authenticated.rs | 74 |
1 files changed, 70 insertions, 4 deletions
diff --git a/src/imap/command/authenticated.rs b/src/imap/command/authenticated.rs index 6c2e43b..5cf8cf9 100644 --- a/src/imap/command/authenticated.rs +++ b/src/imap/command/authenticated.rs @@ -121,6 +121,29 @@ impl<'a> AuthenticatedContext<'a> { )); } + let wildcard = String::try_from(mailbox_wildcard.clone())?; + if wildcard.is_empty() { + if is_lsub { + return Ok(( + Response::ok("LSUB complete")?.with_body(vec![Data::Lsub { + items: vec![], + delimiter: Some(MAILBOX_HIERARCHY_DELIMITER), + mailbox: "".try_into().unwrap(), + }]), + flow::Transition::None, + )); + } else { + return Ok(( + Response::ok("LIST complete")?.with_body(vec![Data::List { + items: vec![], + delimiter: Some(MAILBOX_HIERARCHY_DELIMITER), + mailbox: "".try_into().unwrap(), + }]), + flow::Transition::None, + )); + } + } + let mailboxes = self.user.list_mailboxes().await?; let mut vmailboxes = BTreeMap::new(); for mb in mailboxes.iter() { @@ -135,12 +158,9 @@ impl<'a> AuthenticatedContext<'a> { vmailboxes.insert(mb, true); } - let wildcard = String::try_from(mailbox_wildcard.clone())?; - let wildcard_pat = globset::Glob::new(&wildcard)?.compile_matcher(); - let mut ret = vec![]; for (mb, is_real) in vmailboxes.iter() { - if wildcard_pat.is_match(mb) { + if matches_wildcard(&wildcard, &mb) { let mailbox = mb .to_string() .try_into() @@ -378,3 +398,49 @@ impl<'a> AuthenticatedContext<'a> { Ok((mb, uidvalidity, uid)) } } + +fn matches_wildcard(wildcard: &str, name: &str) -> bool { + let wildcard = wildcard.chars().collect::<Vec<char>>(); + let name = name.chars().collect::<Vec<char>>(); + + let mut matches = vec![vec![false; wildcard.len() + 1]; name.len() + 1]; + + for i in 0..=name.len() { + for j in 0..=wildcard.len() { + matches[i][j] = (i == 0 && j == 0) + || (j > 0 + && matches[i][j - 1] + && (wildcard[j - 1] == '%' || wildcard[j - 1] == '*')) + || (i > 0 + && j > 0 + && matches[i - 1][j - 1] + && wildcard[j - 1] == name[i - 1] + && wildcard[j - 1] != '%' + && wildcard[j - 1] != '*') + || (i > 0 + && j > 0 + && matches[i - 1][j] + && (wildcard[j - 1] == '*' + || (wildcard[j - 1] == '%' && name[i - 1] != MAILBOX_HIERARCHY_DELIMITER))); + } + } + + matches[name.len()][wildcard.len()] +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_wildcard_matches() { + assert!(matches_wildcard("INBOX", "INBOX")); + assert!(matches_wildcard("*", "INBOX")); + assert!(matches_wildcard("%", "INBOX")); + assert!(!matches_wildcard("%", "Test.Azerty")); + assert!(!matches_wildcard("INBOX.*", "INBOX")); + assert!(matches_wildcard("Sent.*", "Sent.A")); + assert!(matches_wildcard("Sent.*", "Sent.A.B")); + assert!(!matches_wildcard("Sent.%", "Sent.A.B")); + } +} |