imap: add UntaggedResponse::UIDFetch
parent
f41a1ffe3a
commit
031e81ac8f
|
@ -129,7 +129,7 @@ impl BackendOp for ImapOp {
|
|||
response.len(),
|
||||
response.lines().collect::<Vec<&str>>().len()
|
||||
);
|
||||
let v = protocol_parser::uid_fetch_flags_response(response.as_bytes())
|
||||
let v = protocol_parser::uid_fetch_flags_responses(response.as_bytes())
|
||||
.map(|(_, v)| v)
|
||||
.map_err(MeliError::from)?;
|
||||
if v.len() != 1 {
|
||||
|
|
|
@ -139,7 +139,7 @@ fn test_imap_required_responses() {
|
|||
}
|
||||
}
|
||||
assert_eq!(&ret, "* 1040 FETCH (UID 1064 FLAGS ())\r\n");
|
||||
let v = protocol_parser::uid_fetch_flags_response(response.as_bytes())
|
||||
let v = protocol_parser::uid_fetch_flags_responses(response.as_bytes())
|
||||
.unwrap()
|
||||
.1;
|
||||
assert_eq!(v.len(), 1);
|
||||
|
@ -727,24 +727,28 @@ pub fn uid_fetch_response_(
|
|||
)(input)
|
||||
}
|
||||
|
||||
pub fn uid_fetch_flags_response(input: &[u8]) -> IResult<&[u8], Vec<(usize, (Flag, Vec<String>))>> {
|
||||
many0(|input| -> IResult<&[u8], (usize, (Flag, Vec<String>))> {
|
||||
let (input, _) = tag("* ")(input)?;
|
||||
let (input, _msn) = take_while(is_digit)(input)?;
|
||||
let (input, _) = tag(" FETCH (")(input)?;
|
||||
let (input, uid_flags) = permutation((
|
||||
preceded(
|
||||
alt((tag("UID "), tag(" UID "))),
|
||||
map_res(digit1, |s| usize::from_str(to_str!(s))),
|
||||
),
|
||||
preceded(
|
||||
alt((tag("FLAGS "), tag(" FLAGS "))),
|
||||
delimited(tag("("), byte_flags, tag(")")),
|
||||
),
|
||||
))(input)?;
|
||||
let (input, _) = tag(")\r\n")(input)?;
|
||||
Ok((input, (uid_flags.0, uid_flags.1)))
|
||||
})(input)
|
||||
pub fn uid_fetch_flags_responses(
|
||||
input: &[u8],
|
||||
) -> IResult<&[u8], Vec<(usize, (Flag, Vec<String>))>> {
|
||||
many0(uid_fetch_flags_response)(input)
|
||||
}
|
||||
|
||||
pub fn uid_fetch_flags_response(input: &[u8]) -> IResult<&[u8], (usize, (Flag, Vec<String>))> {
|
||||
let (input, _) = tag("* ")(input)?;
|
||||
let (input, _msn) = take_while(is_digit)(input)?;
|
||||
let (input, _) = tag(" FETCH (")(input)?;
|
||||
let (input, uid_flags) = permutation((
|
||||
preceded(
|
||||
alt((tag("UID "), tag(" UID "))),
|
||||
map_res(digit1, |s| usize::from_str(to_str!(s))),
|
||||
),
|
||||
preceded(
|
||||
alt((tag("FLAGS "), tag(" FLAGS "))),
|
||||
delimited(tag("("), byte_flags, tag(")")),
|
||||
),
|
||||
))(input)?;
|
||||
let (input, _) = tag(")\r\n")(input)?;
|
||||
Ok((input, (uid_flags.0, uid_flags.1)))
|
||||
}
|
||||
|
||||
macro_rules! flags_to_imap_list {
|
||||
|
@ -871,18 +875,20 @@ pub enum UntaggedResponse {
|
|||
/// ```
|
||||
Recent(usize),
|
||||
Fetch(usize, (Flag, Vec<String>)),
|
||||
UIDFetch(UID, (Flag, Vec<String>)),
|
||||
Bye {
|
||||
reason: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn untagged_responses(input: &[u8]) -> IResult<&[u8], Option<UntaggedResponse>> {
|
||||
let orig_input = input;
|
||||
let (input, _) = tag("* ")(input)?;
|
||||
let (input, num) = map_res(digit1, |s| usize::from_str(to_str!(s)))(input)?;
|
||||
let (input, _) = tag(" ")(input)?;
|
||||
let (input, _tag) = take_until("\r\n")(input)?;
|
||||
let (input, _) = tag("\r\n")(input)?;
|
||||
debug!("Parse untagged response from {:?}", to_str!(input));
|
||||
debug!("Parse untagged response from {:?}", to_str!(orig_input));
|
||||
Ok((input, {
|
||||
use UntaggedResponse::*;
|
||||
match _tag {
|
||||
|
@ -890,18 +896,23 @@ pub fn untagged_responses(input: &[u8]) -> IResult<&[u8], Option<UntaggedRespons
|
|||
b"EXISTS" => Some(Exists(num)),
|
||||
b"RECENT" => Some(Recent(num)),
|
||||
_ if _tag.starts_with(b"FETCH ") => {
|
||||
let f = flags(unsafe {
|
||||
std::str::from_utf8_unchecked(&_tag[b"FETCH (FLAGS (".len()..])
|
||||
})
|
||||
.map(|(_, flags)| Fetch(num, flags));
|
||||
if let Err(ref err) = f {
|
||||
debug!(
|
||||
"untagged_response malformed fetch: {} {}",
|
||||
unsafe { std::str::from_utf8_unchecked(_tag) },
|
||||
err
|
||||
)
|
||||
if to_str!(_tag).contains("UID") {
|
||||
let (uid, flags) = uid_fetch_flags_response(orig_input)?.1;
|
||||
Some(UIDFetch(uid, flags))
|
||||
} else {
|
||||
let f = flags(unsafe {
|
||||
std::str::from_utf8_unchecked(&_tag[b"FETCH (FLAGS (".len()..])
|
||||
})
|
||||
.map(|(_, flags)| Fetch(num, flags));
|
||||
if let Err(ref err) = f {
|
||||
debug!(
|
||||
"untagged_response malformed fetch: {} {}",
|
||||
unsafe { std::str::from_utf8_unchecked(_tag) },
|
||||
err
|
||||
)
|
||||
}
|
||||
f.ok()
|
||||
}
|
||||
f.ok()
|
||||
}
|
||||
_ => {
|
||||
debug!("unknown untagged_response: {}", to_str!(_tag));
|
||||
|
|
|
@ -279,6 +279,24 @@ impl ImapConnection {
|
|||
}
|
||||
}
|
||||
}
|
||||
UntaggedResponse::UIDFetch(uid, flags) => {
|
||||
debug!("fetch uid {} {:?}", uid, flags);
|
||||
let lck = self.uid_store.uid_index.lock().unwrap();
|
||||
let env_hash = lck.get(&(mailbox_hash, uid)).copied();
|
||||
drop(lck);
|
||||
if let Some(env_hash) = env_hash {
|
||||
if !flags.0.intersects(crate::email::Flag::SEEN) {
|
||||
mailbox.unseen.lock().unwrap().insert_new(env_hash);
|
||||
} else {
|
||||
mailbox.unseen.lock().unwrap().remove(env_hash);
|
||||
}
|
||||
self.add_refresh_event(RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: NewFlags(env_hash, flags),
|
||||
});
|
||||
};
|
||||
}
|
||||
UntaggedResponse::Fetch(msg_seq, flags) => {
|
||||
/* a * {msg_seq} FETCH (FLAGS ({flags})) was received, so find out UID from msg_seq
|
||||
* and send update
|
||||
|
@ -288,7 +306,7 @@ impl ImapConnection {
|
|||
mailbox_hash,
|
||||
self.send_command(
|
||||
&[
|
||||
b"UID SEARCH ",
|
||||
b"UID SEARCH",
|
||||
format!("{}", msg_seq).as_bytes(),
|
||||
]
|
||||
.join(&b' '),
|
||||
|
|
|
@ -444,6 +444,27 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(UIDFetch(uid, flags))) => {
|
||||
let res = uid_store
|
||||
.uid_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&(mailbox_hash, uid))
|
||||
.map(|h| *h);
|
||||
if let Some(env_hash) = res {
|
||||
if !flags.0.intersects(crate::email::Flag::SEEN) {
|
||||
mailbox.unseen.lock().unwrap().insert_new(env_hash);
|
||||
} else {
|
||||
mailbox.unseen.lock().unwrap().remove(env_hash);
|
||||
}
|
||||
let mut conn = main_conn.lock().await;
|
||||
conn.add_refresh_event(RefreshEvent {
|
||||
account_hash: uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: NewFlags(env_hash, flags),
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(Some(Fetch(msg_seq, flags))) => {
|
||||
/* a * {msg_seq} FETCH (FLAGS ({flags})) was received, so find out UID from msg_seq
|
||||
* and send update
|
||||
|
@ -456,7 +477,7 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> {
|
|||
conn.examine_mailbox(mailbox_hash, &mut response, false).await
|
||||
conn.send_command(
|
||||
&[
|
||||
b"UID SEARCH ",
|
||||
b"UID SEARCH",
|
||||
format!("{}", msg_seq).as_bytes(),
|
||||
]
|
||||
.join(&b' '),
|
||||
|
|
Loading…
Reference in New Issue