Implement COPY

This commit is contained in:
Alex 2022-07-21 12:44:58 +02:00
parent db4ffd7135
commit 54c467d3f7
Signed by: lx
GPG key ID: 0E496D15096376BE
3 changed files with 73 additions and 25 deletions

View file

@ -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,
))
}
}

View file

@ -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),

View file

@ -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<()> {