Fix list wildcards
This commit is contained in:
parent
15a354f949
commit
c703e3e2b8
5 changed files with 85 additions and 31 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -30,7 +30,6 @@ dependencies = [
|
|||
"clap",
|
||||
"duplexify",
|
||||
"futures",
|
||||
"globset",
|
||||
"hex",
|
||||
"im",
|
||||
"imap-codec",
|
||||
|
@ -444,15 +443,6 @@ dependencies = [
|
|||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.10.0"
|
||||
|
@ -973,19 +963,6 @@ dependencies = [
|
|||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"fnv",
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.4"
|
||||
|
|
|
@ -15,7 +15,6 @@ clap = { version = "3.1.18", features = ["derive", "env"] }
|
|||
duplexify = "1.1.0"
|
||||
hex = "0.4"
|
||||
futures = "0.3"
|
||||
globset = "0.4"
|
||||
im = "15"
|
||||
itertools = "0.10"
|
||||
lazy_static = "1.4"
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,8 +41,14 @@ impl State {
|
|||
match (self, tr) {
|
||||
(s, Transition::None) => Ok(s),
|
||||
(State::NotAuthenticated, Transition::Authenticate(u)) => Ok(State::Authenticated(u)),
|
||||
(State::Authenticated(u), Transition::Select(m)) => Ok(State::Selected(u, m)),
|
||||
(State::Authenticated(u), Transition::Examine(m)) => Ok(State::Examined(u, m)),
|
||||
(
|
||||
State::Authenticated(u) | State::Selected(u, _) | State::Examined(u, _),
|
||||
Transition::Select(m),
|
||||
) => Ok(State::Selected(u, m)),
|
||||
(
|
||||
State::Authenticated(u) | State::Selected(u, _) | State::Examined(u, _),
|
||||
Transition::Examine(m),
|
||||
) => Ok(State::Examined(u, m)),
|
||||
(State::Selected(u, _), Transition::Unselect) => Ok(State::Authenticated(u)),
|
||||
(State::Examined(u, _), Transition::Unselect) => Ok(State::Authenticated(u)),
|
||||
(_, Transition::Logout) => Ok(State::Logout),
|
||||
|
|
|
@ -140,7 +140,13 @@ impl Instance {
|
|||
let res = match ctrl {
|
||||
Ok((res, tr)) => {
|
||||
//@FIXME remove unwrap
|
||||
self.state = self.state.apply(tr).unwrap();
|
||||
self.state = match self.state.apply(tr) {
|
||||
Ok(new_state) => new_state,
|
||||
Err(e) => {
|
||||
tracing::error!("Invalid transition: {}, exiting", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
//@FIXME enrich here the command with some global status
|
||||
|
||||
|
|
Loading…
Reference in a new issue