From 75e5d7cf79e92f2672211918e5fff37fe53250ff Mon Sep 17 00:00:00 2001 From: Conrad Hoffmann Date: Wed, 6 Jul 2022 12:27:50 +0200 Subject: [PATCH] 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. --- src/client.rs | 6 ++++-- src/parse.rs | 34 ++++++++++++++++++++++++++++++++++ src/types/appended.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/types/mod.rs | 3 +++ 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/types/appended.rs diff --git a/src/client.rs b/src/client.rs index a6197001..a0696133 100644 --- a/src/client.rs +++ b/src/client.rs @@ -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 { 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)) } } diff --git a/src/parse.rs b/src/parse.rs index eb818456..d84f8dd4 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -124,6 +124,40 @@ pub fn parse_expunge( } } +pub fn parse_append( + mut lines: &[u8], + unsolicited: &mut mpsc::Sender, +) -> Result { + 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, unsolicited: &mut mpsc::Sender, diff --git a/src/types/appended.rs b/src/types/appended.rs new file mode 100644 index 00000000..c1fd9153 --- /dev/null +++ b/src/types/appended.rs @@ -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, + + /// 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>, +} + +#[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, + ) + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 0e6438dd..fd3b462a 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -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;