Add support for APPENDUID response data

If the `UIDPLUS` extension is supported, the server will reply to
`APPEND` commands with the UID of the new message. This can even be a
list of UIDs if the `MULTIAPPEND` extension is also supported.

Make this information available to the user as the result of an
`AppendCmd`. The added doc strings have links to the relevant RFCs.

Related to #131.
This commit is contained in:
Conrad Hoffmann 2022-07-06 12:27:50 +02:00
parent f616ea992e
commit 75e5d7cf79
4 changed files with 81 additions and 2 deletions

View file

@ -215,7 +215,7 @@ impl<'a, T: Read + Write> AppendCmd<'a, T> {
///
/// Note: be sure to set flags and optional date before you
/// finish the command.
pub fn finish(&mut self) -> Result<()> {
pub fn finish(&mut self) -> Result<Appended> {
let flagstr = self
.flags
.clone()
@ -246,7 +246,9 @@ impl<'a, T: Read + Write> AppendCmd<'a, T> {
self.session.stream.write_all(self.content)?;
self.session.stream.write_all(b"\r\n")?;
self.session.stream.flush()?;
self.session.read_response().map(|_| ())
self.session
.read_response()
.and_then(|(lines, _)| parse_append(&lines, &mut self.session.unsolicited_responses_tx))
}
}

View file

@ -124,6 +124,40 @@ pub fn parse_expunge(
}
}
pub fn parse_append(
mut lines: &[u8],
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
) -> Result<Appended> {
let mut appended = Appended::default();
loop {
match imap_proto::parser::parse_response(lines) {
Ok((rest, Response::Done { status, code, .. })) => {
lines = rest;
assert_eq!(status, imap_proto::Status::Ok);
if let Some(ResponseCode::AppendUid(validity, uids)) = code {
appended.uid_validity = Some(validity);
appended.uids = Some(uids);
}
}
Ok((rest, data)) => {
lines = rest;
if let Some(resp) = try_handle_unilateral(data, unsolicited) {
break Err(resp.into());
}
}
_ => {
return Err(Error::Parse(ParseError::Invalid(lines.to_vec())));
}
}
if lines.is_empty() {
break Ok(appended);
}
}
}
pub fn parse_noop(
lines: Vec<u8>,
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,

40
src/types/appended.rs Normal file
View file

@ -0,0 +1,40 @@
use imap_proto::UidSetMember;
use std::fmt;
/// Meta-information about a message, as returned by
/// [`APPEND`](https://tools.ietf.org/html/rfc3501#section-6.3.11).
/// Note that `APPEND` only returns any data if certain extensions are enabled,
/// for example [`UIDPLUS`](https://tools.ietf.org/html/rfc4315).
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct Appended {
/// The unique identifier validity value of the mailbox that the message was appended to.
/// See [`Uid`] for more details. Only present if server supports [`UIDPLUS`](https://tools.ietf.org/html/rfc4315).
pub uid_validity: Option<u32>,
/// The unique identifier value of the messages that were appended.
/// Only present if server supports [`UIDPLUS`](https://tools.ietf.org/html/rfc4315).
/// Contains only a single value unless the [`MULTIAPPEND`](https://tools.ietf.org/html/rfc3502) extension
/// was used to upload multiple messages.
pub uids: Option<Vec<UidSetMember>>,
}
#[allow(clippy::derivable_impls)]
impl Default for Appended {
fn default() -> Appended {
Appended {
uid_validity: None,
uids: None,
}
}
}
impl fmt::Display for Appended {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"uid_validity: {:?}, uids: {:?}",
self.uid_validity, self.uids,
)
}
}

View file

@ -123,3 +123,6 @@ pub use self::deleted::Deleted;
mod unsolicited_response;
pub use self::unsolicited_response::{AttributeValue, UnsolicitedResponse};
mod appended;
pub use self::appended::Appended;