Expose mailbox read-only flag

This commit is contained in:
Jon Gjengset 2021-03-06 15:02:48 -08:00
parent 9b78550394
commit 18ca65dd3f
3 changed files with 25 additions and 14 deletions

View file

@ -599,12 +599,8 @@ impl<T: Read + Write> Session<T> {
/// `EXISTS`, `FETCH`, and `EXPUNGE` responses. You can get them from the /// `EXISTS`, `FETCH`, and `EXPUNGE` responses. You can get them from the
/// `unsolicited_responses` channel of the [`Session`](struct.Session.html). /// `unsolicited_responses` channel of the [`Session`](struct.Session.html).
pub fn select<S: AsRef<str>>(&mut self, mailbox_name: S) -> Result<Mailbox> { pub fn select<S: AsRef<str>>(&mut self, mailbox_name: S) -> Result<Mailbox> {
// TODO: also note READ/WRITE vs READ-only mode! self.run(&format!("SELECT {}", validate_str(mailbox_name.as_ref())?))
self.run_command_and_read_response(&format!( .and_then(|(lines, _)| parse_mailbox(&lines[..], &mut self.unsolicited_responses_tx))
"SELECT {}",
validate_str(mailbox_name.as_ref())?
))
.and_then(|lines| parse_mailbox(&lines[..], &mut self.unsolicited_responses_tx))
} }
/// The `EXAMINE` command is identical to [`Session::select`] and returns the same output; /// The `EXAMINE` command is identical to [`Session::select`] and returns the same output;
@ -612,11 +608,8 @@ impl<T: Read + Write> Session<T> {
/// of the mailbox, including per-user state, will happen in a mailbox opened with `examine`; /// of the mailbox, including per-user state, will happen in a mailbox opened with `examine`;
/// in particular, messagess cannot lose [`Flag::Recent`] in an examined mailbox. /// in particular, messagess cannot lose [`Flag::Recent`] in an examined mailbox.
pub fn examine<S: AsRef<str>>(&mut self, mailbox_name: S) -> Result<Mailbox> { pub fn examine<S: AsRef<str>>(&mut self, mailbox_name: S) -> Result<Mailbox> {
self.run_command_and_read_response(&format!( self.run(&format!("EXAMINE {}", validate_str(mailbox_name.as_ref())?))
"EXAMINE {}", .and_then(|(lines, _)| parse_mailbox(&lines[..], &mut self.unsolicited_responses_tx))
validate_str(mailbox_name.as_ref())?
))
.and_then(|lines| parse_mailbox(&lines[..], &mut self.unsolicited_responses_tx))
} }
/// Fetch retrieves data associated with a set of messages in the mailbox. /// Fetch retrieves data associated with a set of messages in the mailbox.
@ -1756,6 +1749,7 @@ mod tests {
uid_next: Some(2), uid_next: Some(2),
uid_validity: Some(1257842737), uid_validity: Some(1257842737),
highest_mod_seq: None, highest_mod_seq: None,
is_read_only: true,
}; };
let mailbox_name = "INBOX"; let mailbox_name = "INBOX";
let command = format!("a1 EXAMINE {}\r\n", quote!(mailbox_name)); let command = format!("a1 EXAMINE {}\r\n", quote!(mailbox_name));
@ -1803,6 +1797,7 @@ mod tests {
uid_next: Some(2), uid_next: Some(2),
uid_validity: Some(1257842737), uid_validity: Some(1257842737),
highest_mod_seq: None, highest_mod_seq: None,
is_read_only: true,
}; };
let mailbox_name = "INBOX"; let mailbox_name = "INBOX";
let command = format!("a1 SELECT {}\r\n", quote!(mailbox_name)); let command = format!("a1 SELECT {}\r\n", quote!(mailbox_name));

View file

@ -1,4 +1,4 @@
use imap_proto::{self, MailboxDatum, Response}; use imap_proto::{MailboxDatum, Response, ResponseCode};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use std::collections::HashSet; use std::collections::HashSet;
@ -236,6 +236,17 @@ pub fn parse_mailbox(
loop { loop {
match imap_proto::parser::parse_response(lines) { match imap_proto::parser::parse_response(lines) {
Ok((rest, Response::Done { status, code, .. })) => {
assert!(rest.is_empty());
lines = rest;
// We wouldn't get to parsing if this wasn't an Ok response.
assert_eq!(status, imap_proto::Status::Ok);
if let Some(ResponseCode::ReadOnly) = code {
mailbox.is_read_only = true;
}
}
Ok((rest, Response::Data { status, code, .. })) => { Ok((rest, Response::Data { status, code, .. })) => {
lines = rest; lines = rest;
@ -245,7 +256,6 @@ pub fn parse_mailbox(
unreachable!(); unreachable!();
} }
use imap_proto::ResponseCode;
match code { match code {
Some(ResponseCode::HighestModSeq(seq)) => { Some(ResponseCode::HighestModSeq(seq)) => {
mailbox.highest_mod_seq = Some(seq); mailbox.highest_mod_seq = Some(seq);

View file

@ -40,6 +40,10 @@ pub struct Mailbox {
/// The highest mod sequence for this mailbox. Used with /// The highest mod sequence for this mailbox. Used with
/// [Conditional STORE](https://tools.ietf.org/html/rfc4551#section-3.1.1). /// [Conditional STORE](https://tools.ietf.org/html/rfc4551#section-3.1.1).
pub highest_mod_seq: Option<u64>, pub highest_mod_seq: Option<u64>,
/// The mailbox is selected read-only, or its access while selected has changed from read-write
/// to read-only.
pub is_read_only: bool,
} }
impl Default for Mailbox { impl Default for Mailbox {
@ -53,6 +57,7 @@ impl Default for Mailbox {
uid_next: None, uid_next: None,
uid_validity: None, uid_validity: None,
highest_mod_seq: None, highest_mod_seq: None,
is_read_only: false,
} }
} }
} }
@ -62,7 +67,7 @@ impl fmt::Display for Mailbox {
write!( write!(
f, f,
"flags: {:?}, exists: {}, recent: {}, unseen: {:?}, permanent_flags: {:?},\ "flags: {:?}, exists: {}, recent: {}, unseen: {:?}, permanent_flags: {:?},\
uid_next: {:?}, uid_validity: {:?}, highest_mod_seq: {:?}", uid_next: {:?}, uid_validity: {:?}, highest_mod_seq: {:?}, is_read_only: {:?}",
self.flags, self.flags,
self.exists, self.exists,
self.recent, self.recent,
@ -71,6 +76,7 @@ impl fmt::Display for Mailbox {
self.uid_next, self.uid_next,
self.uid_validity, self.uid_validity,
self.highest_mod_seq, self.highest_mod_seq,
self.is_read_only,
) )
} }
} }