Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
Flag,
|
||||
store::{self, Operation},
|
||||
},
|
||||
receiver::{Request, Token, bad},
|
||||
};
|
||||
|
||||
use super::{parse_number, parse_sequence_set};
|
||||
|
||||
impl Request<Command> {
|
||||
pub fn parse_store(self) -> trc::Result<store::Arguments> {
|
||||
let mut tokens = self.tokens.into_iter().peekable();
|
||||
|
||||
// Sequence set
|
||||
let sequence_set = parse_sequence_set(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing sequence set."))?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
let mut unchanged_since = None;
|
||||
|
||||
// CONDSTORE parameters
|
||||
if let Some(Token::ParenthesisOpen) = tokens.peek() {
|
||||
tokens.next();
|
||||
while let Some(token) = tokens.next() {
|
||||
match token {
|
||||
Token::Argument(param) if param.eq_ignore_ascii_case(b"UNCHANGEDSINCE") => {
|
||||
unchanged_since = parse_number::<u64>(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Missing UNCHANGEDSINCE parameter.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
.into();
|
||||
}
|
||||
Token::ParenthesisClose => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
format_compact!("Unsupported parameter '{}'.", token),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Operation
|
||||
let operation = tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Missing message data item name.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes();
|
||||
let (is_silent, operation) = hashify::tiny_map_ignore_case!(operation.as_slice(),
|
||||
"FLAGS" => (false, Operation::Set),
|
||||
"FLAGS.SILENT" => (true, Operation::Set),
|
||||
"+FLAGS" => (false, Operation::Add),
|
||||
"+FLAGS.SILENT" => (true, Operation::Add),
|
||||
"-FLAGS" => (false, Operation::Clear),
|
||||
"-FLAGS.SILENT" => (true, Operation::Clear),
|
||||
)
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_compact_string(),
|
||||
format_compact!(
|
||||
"Unsupported message data item name: {:?}",
|
||||
String::from_utf8_lossy(&operation)
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
||||
// Flags
|
||||
let mut keywords = Vec::new();
|
||||
match tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing flags to set."))?
|
||||
{
|
||||
Token::ParenthesisOpen => {
|
||||
for token in tokens {
|
||||
match token {
|
||||
Token::Argument(flag) => {
|
||||
keywords.push(
|
||||
Flag::parse_imap(flag)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
Token::ParenthesisClose => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(self.tag.to_compact_string(), "Unsupported flag."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Token::Argument(flag) => {
|
||||
keywords.push(
|
||||
Flag::parse_imap(flag).map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Invalid flags parameter.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if !keywords.is_empty() || operation == Operation::Set {
|
||||
Ok(store::Arguments {
|
||||
tag: self.tag,
|
||||
sequence_set,
|
||||
operation,
|
||||
is_silent,
|
||||
keywords,
|
||||
unchanged_since,
|
||||
})
|
||||
} else {
|
||||
Err(bad(self.tag.to_compact_string(), "Missing flags to set."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
protocol::{
|
||||
Flag, Sequence,
|
||||
store::{self, Operation},
|
||||
},
|
||||
receiver::Receiver,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn parse_store() {
|
||||
let mut receiver = Receiver::new();
|
||||
|
||||
for (command, arguments) in [
|
||||
(
|
||||
"A003 STORE 2:4 +FLAGS (\\Deleted)\r\n",
|
||||
store::Arguments {
|
||||
sequence_set: Sequence::Range {
|
||||
start: 2.into(),
|
||||
end: 4.into(),
|
||||
},
|
||||
is_silent: false,
|
||||
operation: Operation::Add,
|
||||
keywords: vec![Flag::Deleted],
|
||||
tag: "A003".into(),
|
||||
unchanged_since: None,
|
||||
},
|
||||
),
|
||||
(
|
||||
"A004 STORE *:100 -FLAGS.SILENT ($Phishing $Junk)\r\n",
|
||||
store::Arguments {
|
||||
sequence_set: Sequence::Range {
|
||||
start: None,
|
||||
end: 100.into(),
|
||||
},
|
||||
is_silent: true,
|
||||
operation: Operation::Clear,
|
||||
keywords: vec![Flag::Phishing, Flag::Junk],
|
||||
tag: "A004".into(),
|
||||
unchanged_since: None,
|
||||
},
|
||||
),
|
||||
(
|
||||
"d105 STORE 7,5,9 (UNCHANGEDSINCE 320162338) +FLAGS.SILENT \\Deleted\r\n",
|
||||
store::Arguments {
|
||||
sequence_set: Sequence::List {
|
||||
items: vec![
|
||||
Sequence::Number { value: 7 },
|
||||
Sequence::Number { value: 5 },
|
||||
Sequence::Number { value: 9 },
|
||||
],
|
||||
},
|
||||
is_silent: true,
|
||||
operation: Operation::Add,
|
||||
keywords: vec![Flag::Deleted],
|
||||
tag: "d105".into(),
|
||||
unchanged_since: Some(320162338),
|
||||
},
|
||||
),
|
||||
] {
|
||||
assert_eq!(
|
||||
receiver
|
||||
.parse(&mut command.as_bytes().iter())
|
||||
.unwrap()
|
||||
.parse_store()
|
||||
.unwrap(),
|
||||
arguments
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user