aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-07-21 12:44:58 +0200
committerAlex Auvolat <alex@adnab.me>2022-07-21 12:44:58 +0200
commit54c467d3f77fae964400e9c1d78d32d9067c3b0f (patch)
tree4694e2b54d005c5c2283e6a51f530476f4ebac04
parentdb4ffd7135a3d780cf2f7929e9fb883e96157de4 (diff)
downloadaerogramme-54c467d3f77fae964400e9c1d78d32d9067c3b0f.tar.gz
aerogramme-54c467d3f77fae964400e9c1d78d32d9067c3b0f.zip
Implement COPY
-rw-r--r--src/imap/command/selected.rs44
-rw-r--r--src/imap/mailbox_view.rs43
-rw-r--r--src/mail/mailbox.rs11
3 files changed, 73 insertions, 25 deletions
diff --git a/src/imap/command/selected.rs b/src/imap/command/selected.rs
index 1978729..40e75e2 100644
--- a/src/imap/command/selected.rs
+++ b/src/imap/command/selected.rs
@@ -1,13 +1,12 @@
use std::sync::Arc;
-use anyhow::Result;
+use anyhow::{bail, Result};
use boitalettres::proto::Request;
use boitalettres::proto::Response;
use imap_codec::types::command::CommandBody;
-
use imap_codec::types::flag::{Flag, StoreResponse, StoreType};
use imap_codec::types::mailbox::Mailbox as MailboxCodec;
-
+use imap_codec::types::response::Code;
use imap_codec::types::sequence::SequenceSet;
use crate::imap::command::examined;
@@ -91,10 +90,41 @@ impl<'a> SelectedContext<'a> {
async fn copy(
self,
- _sequence_set: &SequenceSet,
- _mailbox: &MailboxCodec,
- _uid: &bool,
+ sequence_set: &SequenceSet,
+ mailbox: &MailboxCodec,
+ uid: &bool,
) -> Result<(Response, flow::Transition)> {
- Ok((Response::bad("Not implemented")?, flow::Transition::None))
+ let name = String::try_from(mailbox.clone())?;
+
+ let mb_opt = self.user.open_mailbox(&name).await?;
+ let mb = match mb_opt {
+ Some(mb) => mb,
+ None => bail!("Mailbox does not exist"),
+ };
+
+ let (uidval, uid_map) = self.mailbox.copy(sequence_set, mb, uid).await?;
+
+ let copyuid_str = format!(
+ "{} {} {}",
+ uidval,
+ uid_map
+ .iter()
+ .map(|(sid, _)| format!("{}", sid))
+ .collect::<Vec<_>>()
+ .join(","),
+ uid_map
+ .iter()
+ .map(|(_, tuid)| format!("{}", tuid))
+ .collect::<Vec<_>>()
+ .join(",")
+ );
+
+ Ok((
+ Response::ok("COPY completed")?.with_extra_code(Code::Other(
+ "COPYUID".try_into().unwrap(),
+ Some(copyuid_str),
+ )),
+ flow::Transition::None,
+ ))
}
}
diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs
index a886c8d..13ea9a7 100644
--- a/src/imap/mailbox_view.rs
+++ b/src/imap/mailbox_view.rs
@@ -168,6 +168,7 @@ impl MailboxView {
}
}
+ // @TODO: handle _response
self.update().await
}
@@ -189,6 +190,33 @@ impl MailboxView {
self.update().await
}
+ pub async fn copy(
+ &self,
+ sequence_set: &SequenceSet,
+ to: Arc<Mailbox>,
+ is_uid_copy: &bool,
+ ) -> Result<(ImapUidvalidity, Vec<(ImapUid, ImapUid)>)> {
+ let mails = self.get_mail_ids(sequence_set, *is_uid_copy)?;
+
+ let mut new_uuids = vec![];
+ for (_i, _uid, uuid) in mails.iter() {
+ new_uuids.push(to.copy_from(&self.mailbox, *uuid).await?);
+ }
+
+ let mut ret = vec![];
+ let to_state = to.current_uid_index().await;
+ for ((_i, uid, _uuid), new_uuid) in mails.iter().zip(new_uuids.iter()) {
+ let dest_uid = to_state
+ .table
+ .get(new_uuid)
+ .ok_or(anyhow!("copied mail not in destination mailbox"))?
+ .0;
+ ret.push((*uid, dest_uid));
+ }
+
+ Ok((to_state.uidvalidity, ret))
+ }
+
/// Looks up state changes in the mailbox and produces a set of IMAP
/// responses describing the new state.
pub async fn fetch(
@@ -841,21 +869,6 @@ fn build_imap_email_struct<'a>(msg: &Message<'a>, part: &MessagePart<'a>) -> Res
}
}
-fn count_lines(mut text: &[u8]) -> Result<u32> {
- while text.first().map(u8::is_ascii_whitespace).unwrap_or(false) {
- text = &text[1..];
- }
- while text.last().map(u8::is_ascii_whitespace).unwrap_or(false) {
- text = &text[..text.len() - 1];
- }
- if text.is_empty() {
- Ok(0)
- } else {
- let nlf = text.iter().filter(|x| **x == b'\n').count();
- Ok(u32::try_from(1 + nlf)?)
- }
-}
-
fn try_collect_shime<T>(acc: Result<Vec<T>>, elem: Result<T>) -> Result<Vec<T>> {
match (acc, elem) {
(Err(e), _) | (_, Err(e)) => Err(e),
diff --git a/src/mail/mailbox.rs b/src/mail/mailbox.rs
index 44ffe20..df7ede9 100644
--- a/src/mail/mailbox.rs
+++ b/src/mail/mailbox.rs
@@ -138,7 +138,7 @@ impl Mailbox {
/// Copy an email from an other Mailbox to this mailbox
/// (use this when possible, as it allows for a certain number of storage optimizations)
- pub async fn copy_from(&self, from: &Mailbox, uuid: UniqueIdent) -> Result<()> {
+ pub async fn copy_from(&self, from: &Mailbox, uuid: UniqueIdent) -> Result<UniqueIdent> {
if self.id == from.id {
bail!("Cannot copy into same mailbox");
}
@@ -412,9 +412,14 @@ impl MailboxInternal {
Ok(())
}
- async fn copy_from(&mut self, from: &MailboxInternal, source_id: UniqueIdent) -> Result<()> {
+ async fn copy_from(
+ &mut self,
+ from: &MailboxInternal,
+ source_id: UniqueIdent,
+ ) -> Result<UniqueIdent> {
let new_id = gen_ident();
- self.copy_internal(from, source_id, new_id).await
+ self.copy_internal(from, source_id, new_id).await?;
+ Ok(new_id)
}
async fn move_from(&mut self, from: &mut MailboxInternal, id: UniqueIdent) -> Result<()> {