imap: add status_response() parser
This commit is contained in:
parent
c7835ccc13
commit
c08ceae97c
2 changed files with 79 additions and 1 deletions
|
@ -300,7 +300,7 @@ impl MailBackend for ImapType {
|
|||
.chain_err_summary(|| {
|
||||
format!("Could not select mailbox {}", mailbox_path)
|
||||
})?;
|
||||
let examine_response = protocol_parser::select_response(&response)
|
||||
let mut examine_response = protocol_parser::select_response(&response)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not parse select response for mailbox {}",
|
||||
|
@ -345,6 +345,24 @@ impl MailBackend for ImapType {
|
|||
let mut exists: usize = examine_response.exists;
|
||||
/* reselecting the same mailbox with EXAMINE prevents expunging it */
|
||||
conn.examine_mailbox(mailbox_hash, &mut response)?;
|
||||
if examine_response.uidnext == 0 {
|
||||
/* UIDNEXT shouldn't be 0, since exists != 0 at this point */
|
||||
conn.send_command(
|
||||
format!("STATUS \"{}\" (UIDNEXT)", mailbox_path).as_bytes(),
|
||||
)?;
|
||||
conn.read_response(&mut response, RequiredResponses::STATUS)?;
|
||||
let (_, status) = protocol_parser::status_response(response.as_bytes())?;
|
||||
if let Some(uidnext) = status.uidnext {
|
||||
if uidnext == 0 {
|
||||
return Err(MeliError::new(
|
||||
"IMAP server error: zero UIDNEXt with nonzero exists.",
|
||||
));
|
||||
}
|
||||
examine_response.uidnext = uidnext;
|
||||
} else {
|
||||
return Err(MeliError::new("IMAP server did not reply with UIDNEXT"));
|
||||
}
|
||||
}
|
||||
|
||||
let mut tag_lck = uid_store.tag_index.write().unwrap();
|
||||
|
||||
|
|
|
@ -1402,6 +1402,66 @@ pub fn bodystructure_has_attachments(input: &[u8]) -> bool {
|
|||
input.rfind(b" \"mixed\" ").is_some() || input.rfind(b" \"MIXED\" ").is_some()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct StatusResponse {
|
||||
pub messages: Option<usize>,
|
||||
pub recent: Option<usize>,
|
||||
pub uidnext: Option<usize>,
|
||||
pub uidvalidity: Option<usize>,
|
||||
pub unseen: Option<usize>,
|
||||
}
|
||||
|
||||
// status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")"
|
||||
// status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" / "UNSEEN"
|
||||
pub fn status_response(input: &[u8]) -> IResult<&[u8], StatusResponse> {
|
||||
let (input, _) = tag("* STATUS ")(input)?;
|
||||
let (input, _) = take_until(" (")(input)?;
|
||||
let (input, _) = tag(" (")(input)?;
|
||||
let (input, result) = permutation((
|
||||
opt(preceded(
|
||||
tag("MESSAGES "),
|
||||
map_res(digit1, |s| {
|
||||
usize::from_str(unsafe { std::str::from_utf8_unchecked(s) })
|
||||
}),
|
||||
)),
|
||||
opt(preceded(
|
||||
tag("RECENT "),
|
||||
map_res(digit1, |s| {
|
||||
usize::from_str(unsafe { std::str::from_utf8_unchecked(s) })
|
||||
}),
|
||||
)),
|
||||
opt(preceded(
|
||||
tag("UIDNEXT "),
|
||||
map_res(digit1, |s| {
|
||||
usize::from_str(unsafe { std::str::from_utf8_unchecked(s) })
|
||||
}),
|
||||
)),
|
||||
opt(preceded(
|
||||
tag("UIDVALIDITY "),
|
||||
map_res(digit1, |s| {
|
||||
usize::from_str(unsafe { std::str::from_utf8_unchecked(s) })
|
||||
}),
|
||||
)),
|
||||
opt(preceded(
|
||||
tag("UNSEEN "),
|
||||
map_res(digit1, |s| {
|
||||
usize::from_str(unsafe { std::str::from_utf8_unchecked(s) })
|
||||
}),
|
||||
)),
|
||||
))(input)?;
|
||||
let (input, _) = tag(")\r\n")(input)?;
|
||||
Ok((
|
||||
input,
|
||||
StatusResponse {
|
||||
messages: result.0,
|
||||
recent: result.1,
|
||||
uidnext: result.2,
|
||||
uidvalidity: result.3,
|
||||
unseen: result.4,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// mailbox = "INBOX" / astring
|
||||
// ; INBOX is case-insensitive. All case variants of
|
||||
// ; INBOX (e.g., "iNbOx") MUST be interpreted as INBOX
|
||||
|
|
Loading…
Add table
Reference in a new issue