Implement COPY
This commit is contained in:
parent
db4ffd7135
commit
54c467d3f7
3 changed files with 73 additions and 25 deletions
|
@ -1,13 +1,12 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
use boitalettres::proto::Request;
|
use boitalettres::proto::Request;
|
||||||
use boitalettres::proto::Response;
|
use boitalettres::proto::Response;
|
||||||
use imap_codec::types::command::CommandBody;
|
use imap_codec::types::command::CommandBody;
|
||||||
|
|
||||||
use imap_codec::types::flag::{Flag, StoreResponse, StoreType};
|
use imap_codec::types::flag::{Flag, StoreResponse, StoreType};
|
||||||
use imap_codec::types::mailbox::Mailbox as MailboxCodec;
|
use imap_codec::types::mailbox::Mailbox as MailboxCodec;
|
||||||
|
use imap_codec::types::response::Code;
|
||||||
use imap_codec::types::sequence::SequenceSet;
|
use imap_codec::types::sequence::SequenceSet;
|
||||||
|
|
||||||
use crate::imap::command::examined;
|
use crate::imap::command::examined;
|
||||||
|
@ -91,10 +90,41 @@ impl<'a> SelectedContext<'a> {
|
||||||
|
|
||||||
async fn copy(
|
async fn copy(
|
||||||
self,
|
self,
|
||||||
_sequence_set: &SequenceSet,
|
sequence_set: &SequenceSet,
|
||||||
_mailbox: &MailboxCodec,
|
mailbox: &MailboxCodec,
|
||||||
_uid: &bool,
|
uid: &bool,
|
||||||
) -> Result<(Response, flow::Transition)> {
|
) -> 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,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,6 +168,7 @@ impl MailboxView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO: handle _response
|
||||||
self.update().await
|
self.update().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +190,33 @@ impl MailboxView {
|
||||||
self.update().await
|
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
|
/// Looks up state changes in the mailbox and produces a set of IMAP
|
||||||
/// responses describing the new state.
|
/// responses describing the new state.
|
||||||
pub async fn fetch(
|
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>> {
|
fn try_collect_shime<T>(acc: Result<Vec<T>>, elem: Result<T>) -> Result<Vec<T>> {
|
||||||
match (acc, elem) {
|
match (acc, elem) {
|
||||||
(Err(e), _) | (_, Err(e)) => Err(e),
|
(Err(e), _) | (_, Err(e)) => Err(e),
|
||||||
|
|
|
@ -138,7 +138,7 @@ impl Mailbox {
|
||||||
|
|
||||||
/// Copy an email from an other Mailbox to this 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)
|
/// (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 {
|
if self.id == from.id {
|
||||||
bail!("Cannot copy into same mailbox");
|
bail!("Cannot copy into same mailbox");
|
||||||
}
|
}
|
||||||
|
@ -412,9 +412,14 @@ impl MailboxInternal {
|
||||||
Ok(())
|
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();
|
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<()> {
|
async fn move_from(&mut self, from: &mut MailboxInternal, id: UniqueIdent) -> Result<()> {
|
||||||
|
|
Loading…
Reference in a new issue