Skip to main content

io_email/mailbox/jmap/
delete.rs

1//! JMAP mailbox-delete coroutine wrapping Mailbox/set { destroy }
2//! with onDestroyRemoveEmails to match IMAP semantics.
3//!
4//! # Example
5//!
6//! ```rust,ignore
7//! use io_email::mailbox::jmap::delete::JmapMailboxDelete;
8//!
9//! client.run(JmapMailboxDelete::new(&session, &auth, "mailbox-id")?)?;
10//! ```
11
12use alloc::{string::String, vec};
13use core::mem;
14
15use io_jmap::{
16    coroutine::{JmapCoroutine, JmapCoroutineState, JmapYield},
17    rfc8620::JmapSession,
18    rfc8621::mailbox::set::{
19        JmapMailboxSet as InnerSet, JmapMailboxSetArgs, JmapMailboxSetError as SetErr,
20    },
21};
22use log::trace;
23use secrecy::SecretString;
24use thiserror::Error;
25
26/// Errors produced by [`JmapMailboxDelete`].
27#[derive(Debug, Error)]
28pub enum JmapMailboxDeleteError {
29    #[error(transparent)]
30    Set(#[from] SetErr),
31    #[error("Mailbox/set did not destroy `{0}`")]
32    NotDestroyed(String),
33    #[error("coroutine was resumed after completion")]
34    ResumedAfterDone,
35}
36
37/// I/O-free coroutine deleting a JMAP mailbox by id.
38pub struct JmapMailboxDelete {
39    state: State,
40    id: String,
41}
42
43impl JmapMailboxDelete {
44    pub fn new(
45        session: &JmapSession,
46        http_auth: &SecretString,
47        id: &str,
48    ) -> Result<Self, JmapMailboxDeleteError> {
49        trace!("prepare JMAP mailbox delete");
50        let args = JmapMailboxSetArgs {
51            destroy: Some(vec![id.into()]),
52            on_destroy_remove_emails: Some(true),
53            ..JmapMailboxSetArgs::default()
54        };
55        let set = InnerSet::new(session, http_auth, args)?;
56        Ok(Self {
57            state: State::Destroying(set),
58            id: id.into(),
59        })
60    }
61}
62
63enum State {
64    Destroying(InnerSet),
65    Done,
66}
67
68impl JmapCoroutine for JmapMailboxDelete {
69    type Yield = JmapYield;
70    type Return = Result<(), JmapMailboxDeleteError>;
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::Destroying(mut set) => match set.resume(bytes) {
75                JmapCoroutineState::Complete(Ok(ok)) => {
76                    if ok.destroyed.iter().any(|d| d == &self.id) {
77                        JmapCoroutineState::Complete(Ok(()))
78                    } else {
79                        JmapCoroutineState::Complete(Err(JmapMailboxDeleteError::NotDestroyed(
80                            mem::take(&mut self.id),
81                        )))
82                    }
83                }
84                JmapCoroutineState::Yielded(y) => {
85                    self.state = State::Destroying(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(JmapMailboxDeleteError::ResumedAfterDone))
94            }
95        }
96    }
97}