io_email/message/jmap/
move.rs1use alloc::{string::String, vec::Vec};
13use core::mem;
14
15use io_jmap::{
16 coroutine::{JmapCoroutine, JmapCoroutineState, JmapYield},
17 rfc8620::JmapSession,
18 rfc8621::email::set::{
19 JmapEmailSet as InnerSet, JmapEmailSetArgs, JmapEmailSetError as SetErr,
20 },
21};
22use log::trace;
23use secrecy::SecretString;
24use thiserror::Error;
25
26#[derive(Debug, Error)]
28pub enum JmapMessageMoveError {
29 #[error(transparent)]
30 Set(#[from] SetErr),
31 #[error("Email/set returned per-id failures: {0:?}")]
32 NotUpdated(Vec<String>),
33 #[error("coroutine was resumed after completion")]
34 ResumedAfterDone,
35}
36
37pub struct JmapMessageMove {
39 state: State,
40}
41
42impl JmapMessageMove {
43 pub fn new(
44 session: &JmapSession,
45 http_auth: &SecretString,
46 from: &str,
47 to: &str,
48 ids: &[&str],
49 ) -> Result<Self, JmapMessageMoveError> {
50 trace!("prepare JMAP message move");
51 let mut args = JmapEmailSetArgs::default();
52 for id in ids {
53 args.add_to_mailbox(*id, to);
54 args.remove_from_mailbox(*id, from);
55 }
56 let set = InnerSet::new(session, http_auth, args)?;
57 Ok(Self {
58 state: State::Patching(set),
59 })
60 }
61}
62
63enum State {
64 Patching(InnerSet),
65 Done,
66}
67
68impl JmapCoroutine for JmapMessageMove {
69 type Yield = JmapYield;
70 type Return = Result<(), JmapMessageMoveError>;
71
72 fn resume(&mut self, bytes: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
73 match mem::replace(&mut self.state, State::Done) {
74 State::Patching(mut set) => match set.resume(bytes) {
75 JmapCoroutineState::Complete(Ok(ok)) => {
76 if ok.not_updated.is_empty() {
77 JmapCoroutineState::Complete(Ok(()))
78 } else {
79 JmapCoroutineState::Complete(Err(JmapMessageMoveError::NotUpdated(
80 ok.not_updated.into_keys().collect(),
81 )))
82 }
83 }
84 JmapCoroutineState::Yielded(y) => {
85 self.state = State::Patching(set);
86 JmapCoroutineState::Yielded(y)
87 }
88 JmapCoroutineState::Complete(Err(err)) => {
89 JmapCoroutineState::Complete(Err(err.into()))
90 }
91 },
92 State::Done => {
93 JmapCoroutineState::Complete(Err(JmapMessageMoveError::ResumedAfterDone))
94 }
95 }
96 }
97}