Skip to content

Commit a3d3055

Browse files
authored
Merge pull request #127 from dayo05/main
Add quotes for some commands (e.g. `COPY`) to support mailbox with whitespace
2 parents 15f80ea + b604ba9 commit a3d3055

File tree

1 file changed

+27
-23
lines changed

1 file changed

+27
-23
lines changed

src/client.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,8 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
594594
pub async fn rename<S1: AsRef<str>, S2: AsRef<str>>(&mut self, from: S1, to: S2) -> Result<()> {
595595
self.run_command_and_check_ok(&format!(
596596
"RENAME {} {}",
597-
quote!(from.as_ref()),
598-
quote!(to.as_ref())
597+
validate_str(from.as_ref())?,
598+
validate_str(to.as_ref())?
599599
))
600600
.await?;
601601

@@ -611,7 +611,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
611611
/// However, it will not unilaterally remove an existing mailbox name from the subscription
612612
/// list even if a mailbox by that name no longer exists.
613613
pub async fn subscribe<S: AsRef<str>>(&mut self, mailbox: S) -> Result<()> {
614-
self.run_command_and_check_ok(&format!("SUBSCRIBE {}", quote!(mailbox.as_ref())))
614+
self.run_command_and_check_ok(&format!("SUBSCRIBE {}", validate_str(mailbox.as_ref())?))
615615
.await?;
616616
Ok(())
617617
}
@@ -621,7 +621,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
621621
/// returned by [`Session::lsub`]. This command returns `Ok` only if the unsubscription is
622622
/// successful.
623623
pub async fn unsubscribe<S: AsRef<str>>(&mut self, mailbox: S) -> Result<()> {
624-
self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", quote!(mailbox.as_ref())))
624+
self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", validate_str(mailbox.as_ref())?))
625625
.await?;
626626
Ok(())
627627
}
@@ -839,7 +839,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
839839
self.run_command_and_check_ok(&format!(
840840
"COPY {} {}",
841841
sequence_set.as_ref(),
842-
mailbox_name.as_ref()
842+
validate_str(mailbox_name.as_ref())?
843843
))
844844
.await?;
845845

@@ -856,7 +856,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
856856
self.run_command_and_check_ok(&format!(
857857
"UID COPY {} {}",
858858
uid_set.as_ref(),
859-
mailbox_name.as_ref()
859+
validate_str(mailbox_name.as_ref())?
860860
))
861861
.await?;
862862

@@ -966,7 +966,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
966966
let id = self
967967
.run_command(&format!(
968968
"LIST {} {}",
969-
quote!(reference_name.unwrap_or("")),
969+
validate_str(reference_name.unwrap_or(""))?,
970970
mailbox_pattern.unwrap_or("\"\"")
971971
))
972972
.await?;
@@ -1002,8 +1002,8 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
10021002
let id = self
10031003
.run_command(&format!(
10041004
"LSUB {} {}",
1005-
quote!(reference_name.unwrap_or("")),
1006-
mailbox_pattern.unwrap_or("")
1005+
validate_str(reference_name.unwrap_or(""))?,
1006+
validate_str(mailbox_pattern.unwrap_or(""))?
10071007
))
10081008
.await?;
10091009
let names = parse_names(
@@ -1122,8 +1122,8 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
11221122
let content = content.as_ref();
11231123
let id = self
11241124
.run_command(&format!(
1125-
"APPEND \"{}\"{}{}{}{} {{{}}}",
1126-
mailbox.as_ref(),
1125+
"APPEND {}{}{}{}{} {{{}}}",
1126+
validate_str(mailbox.as_ref())?,
11271127
if flags.is_some() { " " } else { "" },
11281128
flags.unwrap_or(""),
11291129
if internaldate.is_some() { " " } else { "" },
@@ -1226,7 +1226,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
12261226
/// The [`GETQUOTA` command](https://tools.ietf.org/html/rfc2087#section-4.2)
12271227
pub async fn get_quota(&mut self, quota_root: &str) -> Result<Quota> {
12281228
let id = self
1229-
.run_command(format!("GETQUOTA {}", quote!(quota_root)))
1229+
.run_command(format!("GETQUOTA {}", validate_str(quota_root)?))
12301230
.await?;
12311231
let c = parse_get_quota(
12321232
&mut self.conn.stream,
@@ -1243,7 +1243,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
12431243
mailbox_name: &str,
12441244
) -> Result<(Vec<QuotaRoot>, Vec<Quota>)> {
12451245
let id = self
1246-
.run_command(format!("GETQUOTAROOT {}", quote!(mailbox_name)))
1246+
.run_command(format!("GETQUOTAROOT {}", validate_str(mailbox_name)?))
12471247
.await?;
12481248
let c = parse_get_quota_root(
12491249
&mut self.conn.stream,
@@ -1269,7 +1269,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
12691269
let id = self
12701270
.run_command(format!(
12711271
"GETMETADATA {} {}{}",
1272-
quote!(mailbox_name),
1272+
validate_str(mailbox_name)?,
12731273
options,
12741274
entry_specifier
12751275
))
@@ -2014,15 +2014,19 @@ mod tests {
20142014
F: 'a + FnOnce(Arc<Mutex<Session<MockStream>>>, &'a str, &'a str) -> K,
20152015
K: 'a + Future<Output = Result<T>>,
20162016
{
2017-
generic_with_uid(
2018-
"A0001 OK COPY completed\r\n",
2019-
"COPY",
2020-
"2:4",
2021-
"MEETING",
2022-
prefix,
2023-
op,
2024-
)
2025-
.await;
2017+
let resp = "A0001 OK COPY completed\r\n".as_bytes().to_vec();
2018+
let seq = "2:4";
2019+
let query = "MEETING";
2020+
let line = format!("A0001{prefix}COPY {seq} {}\r\n", quote!(query));
2021+
let session = Arc::new(Mutex::new(mock_session!(MockStream::new(resp))));
2022+
2023+
{
2024+
let _ = op(session.clone(), seq, query).await.unwrap();
2025+
}
2026+
assert!(
2027+
session.lock().await.stream.inner.written_buf == line.as_bytes().to_vec(),
2028+
"Invalid command"
2029+
);
20262030
}
20272031

20282032
#[cfg_attr(feature = "runtime-tokio", tokio::test)]

0 commit comments

Comments
 (0)