Skip to content

Commit

Permalink
Add support for APPENDUID response data
Browse files Browse the repository at this point in the history
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 jonhoo#131.
  • Loading branch information
bitfehler committed Jul 6, 2022
1 parent db29117 commit afe86f1
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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))
}
}

Expand Down
34 changes: 34 additions & 0 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,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>,
Expand Down
40 changes: 40 additions & 0 deletions src/types/appended.rs
Original file line number Diff line number Diff line change
@@ -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,
)
}
}
3 changes: 3 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit afe86f1

Please sign in to comment.