parent
1055dd6e43
commit
55cd6465c7
4 changed files with 85 additions and 3 deletions
|
|
@ -1064,12 +1064,15 @@ impl<T: Read + Write> Session<T> {
|
||||||
mailbox_name: S1,
|
mailbox_name: S1,
|
||||||
data_items: S2,
|
data_items: S2,
|
||||||
) -> Result<Mailbox> {
|
) -> Result<Mailbox> {
|
||||||
|
let mailbox_name = mailbox_name.as_ref();
|
||||||
self.run_command_and_read_response(&format!(
|
self.run_command_and_read_response(&format!(
|
||||||
"STATUS {} {}",
|
"STATUS {} {}",
|
||||||
validate_str(mailbox_name.as_ref())?,
|
validate_str(mailbox_name)?,
|
||||||
data_items.as_ref()
|
data_items.as_ref()
|
||||||
))
|
))
|
||||||
.and_then(|lines| parse_mailbox(&lines[..], &mut self.unsolicited_responses_tx))
|
.and_then(|lines| {
|
||||||
|
parse_status(&lines[..], mailbox_name, &mut self.unsolicited_responses_tx)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method returns a handle that lets you use the [`IDLE`
|
/// This method returns a handle that lets you use the [`IDLE`
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,9 @@ pub enum Error {
|
||||||
/// or an unsolicited response that could not be converted into a local type in
|
/// or an unsolicited response that could not be converted into a local type in
|
||||||
/// [`UnsolicitedResponse`](crate::types::UnsolicitedResponse).
|
/// [`UnsolicitedResponse`](crate::types::UnsolicitedResponse).
|
||||||
Unexpected(Response<'static>),
|
Unexpected(Response<'static>),
|
||||||
|
/// In response to a STATUS command, the server sent OK without actually sending any STATUS
|
||||||
|
/// responses first.
|
||||||
|
MissingStatusResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IoError> for Error {
|
impl From<IoError> for Error {
|
||||||
|
|
@ -148,6 +151,7 @@ impl fmt::Display for Error {
|
||||||
Error::ConnectionLost => f.write_str("Connection Lost"),
|
Error::ConnectionLost => f.write_str("Connection Lost"),
|
||||||
Error::Append => f.write_str("Could not append mail to mailbox"),
|
Error::Append => f.write_str("Could not append mail to mailbox"),
|
||||||
Error::Unexpected(ref r) => write!(f, "Unexpected Response: {:?}", r),
|
Error::Unexpected(ref r) => write!(f, "Unexpected Response: {:?}", r),
|
||||||
|
Error::MissingStatusResponse => write!(f, "Missing STATUS Response"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -170,6 +174,7 @@ impl StdError for Error {
|
||||||
Error::ConnectionLost => "Connection lost",
|
Error::ConnectionLost => "Connection lost",
|
||||||
Error::Append => "Could not append mail to mailbox",
|
Error::Append => "Could not append mail to mailbox",
|
||||||
Error::Unexpected(_) => "Unexpected Response",
|
Error::Unexpected(_) => "Unexpected Response",
|
||||||
|
Error::MissingStatusResponse => "Missing STATUS Response",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
49
src/parse.rs
49
src/parse.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use imap_proto::{MailboxDatum, Response, ResponseCode};
|
use imap_proto::{MailboxDatum, Response, ResponseCode, StatusAttribute};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
@ -315,6 +315,53 @@ pub fn parse_mailbox(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_status(
|
||||||
|
mut lines: &[u8],
|
||||||
|
mailbox_name: &str,
|
||||||
|
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
||||||
|
) -> Result<Mailbox> {
|
||||||
|
let mut mailbox = Mailbox::default();
|
||||||
|
let mut got_anything = false;
|
||||||
|
while !lines.is_empty() {
|
||||||
|
match imap_proto::parser::parse_response(lines) {
|
||||||
|
Ok((
|
||||||
|
rest,
|
||||||
|
Response::MailboxData(MailboxDatum::Status {
|
||||||
|
mailbox: their_mailbox_name,
|
||||||
|
status,
|
||||||
|
}),
|
||||||
|
)) if their_mailbox_name == mailbox_name => {
|
||||||
|
lines = rest;
|
||||||
|
got_anything = true;
|
||||||
|
for attr in status {
|
||||||
|
match attr {
|
||||||
|
StatusAttribute::HighestModSeq(v) => mailbox.highest_mod_seq = Some(v),
|
||||||
|
StatusAttribute::Messages(v) => mailbox.exists = v,
|
||||||
|
StatusAttribute::Recent(v) => mailbox.recent = v,
|
||||||
|
StatusAttribute::UidNext(v) => mailbox.uid_next = Some(v),
|
||||||
|
StatusAttribute::UidValidity(v) => mailbox.uid_validity = Some(v),
|
||||||
|
StatusAttribute::Unseen(v) => mailbox.unseen = Some(v),
|
||||||
|
_ => {} // needed because StatusAttribute is #[non_exhaustive]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((rest, data)) => {
|
||||||
|
lines = rest;
|
||||||
|
if let Some(resp) = try_handle_unilateral(data, unsolicited) {
|
||||||
|
return Err(resp.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::Parse(ParseError::Invalid(lines.to_vec())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !got_anything {
|
||||||
|
return Err(Error::MissingStatusResponse);
|
||||||
|
}
|
||||||
|
Ok(mailbox)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_ids_with<T: Extend<u32>>(
|
fn parse_ids_with<T: Extend<u32>>(
|
||||||
lines: &[u8],
|
lines: &[u8],
|
||||||
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use lettre::Transport;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
|
||||||
use crate::imap::extensions::sort::{SortCharset, SortCriterion};
|
use crate::imap::extensions::sort::{SortCharset, SortCriterion};
|
||||||
|
use crate::imap::types::Mailbox;
|
||||||
|
|
||||||
fn tls() -> native_tls::TlsConnector {
|
fn tls() -> native_tls::TlsConnector {
|
||||||
native_tls::TlsConnector::builder()
|
native_tls::TlsConnector::builder()
|
||||||
|
|
@ -448,3 +449,29 @@ fn append_with_flags_and_date() {
|
||||||
let inbox = c.search("ALL").unwrap();
|
let inbox = c.search("ALL").unwrap();
|
||||||
assert_eq!(inbox.len(), 0);
|
assert_eq!(inbox.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn status() {
|
||||||
|
let mut s = session("readonly-test@localhost");
|
||||||
|
|
||||||
|
// Test all valid fields except HIGHESTMODSEQ, which apparently
|
||||||
|
// isn't supported by the IMAP server used for this test.
|
||||||
|
let mb = s.status("INBOX", "(MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN)").unwrap();
|
||||||
|
assert_eq!(mb.flags, Vec::new());
|
||||||
|
assert_eq!(mb.exists, 0);
|
||||||
|
assert_eq!(mb.recent, 0);
|
||||||
|
assert!(mb.unseen.is_some());
|
||||||
|
assert_eq!(mb.permanent_flags, Vec::new());
|
||||||
|
assert!(mb.uid_next.is_some());
|
||||||
|
assert!(mb.uid_validity.is_some());
|
||||||
|
assert_eq!(mb.highest_mod_seq, None);
|
||||||
|
assert_eq!(mb.is_read_only, false);
|
||||||
|
|
||||||
|
// If we only request one field, we should only get one field
|
||||||
|
// back. (A server could legally send an unsolicited STATUS
|
||||||
|
// response, but this one won't.)
|
||||||
|
let mb = s.status("INBOX", "(MESSAGES)").unwrap();
|
||||||
|
let mut expected = Mailbox::default();
|
||||||
|
expected.exists = 0;
|
||||||
|
assert_eq!(mb, expected);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue