io_email/envelope/jmap/
list.rs1use alloc::vec::Vec;
16use core::mem;
17
18use io_jmap::{
19 coroutine::{JmapCoroutine, JmapCoroutineState, JmapYield},
20 rfc8620::JmapSession,
21 rfc8621::email::{
22 JmapEmailFilter,
23 query::{
24 JmapEmailQuery as InnerQuery, JmapEmailQueryError as QueryErr, JmapEmailQueryOptions,
25 },
26 },
27};
28use log::trace;
29use secrecy::SecretString;
30use thiserror::Error;
31
32use crate::{
33 envelope::types::Envelope,
34 jmap::convert::{compute_position_limit, envelope_from, envelope_properties},
35};
36
37#[derive(Debug, Error)]
39pub enum JmapEnvelopeListError {
40 #[error(transparent)]
41 EmailQuery(#[from] QueryErr),
42 #[error("coroutine was resumed after completion")]
43 ResumedAfterDone,
44}
45
46pub struct JmapEnvelopeList {
48 state: State,
49}
50
51impl JmapEnvelopeList {
52 pub fn new(
53 session: &JmapSession,
54 http_auth: &SecretString,
55 mailbox: &str,
56 page: Option<u32>,
57 page_size: Option<u32>,
58 ) -> Result<Self, JmapEnvelopeListError> {
59 trace!("prepare JMAP envelope listing");
60 let (position, limit) = compute_position_limit(page, page_size);
61 let filter = JmapEmailFilter {
62 in_mailbox: Some(mailbox.into()),
63 ..JmapEmailFilter::default()
64 };
65 let opts = JmapEmailQueryOptions {
66 filter: Some(filter.into()),
67 position,
68 limit,
69 properties: Some(envelope_properties()),
70 ..Default::default()
71 };
72 let inner = InnerQuery::new(session, http_auth, opts)?;
73 Ok(Self {
74 state: State::Listing(inner),
75 })
76 }
77}
78
79enum State {
80 Listing(InnerQuery),
81 Done,
82}
83
84impl JmapCoroutine for JmapEnvelopeList {
85 type Yield = JmapYield;
86 type Return = Result<Vec<Envelope>, JmapEnvelopeListError>;
87
88 fn resume(&mut self, bytes: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
89 match mem::replace(&mut self.state, State::Done) {
90 State::Listing(mut query) => match query.resume(bytes) {
91 JmapCoroutineState::Complete(Ok(ok)) => {
92 let envelopes = ok.emails.into_iter().map(envelope_from).collect();
93 JmapCoroutineState::Complete(Ok(envelopes))
94 }
95 JmapCoroutineState::Yielded(y) => {
96 self.state = State::Listing(query);
97 JmapCoroutineState::Yielded(y)
98 }
99 JmapCoroutineState::Complete(Err(err)) => {
100 JmapCoroutineState::Complete(Err(err.into()))
101 }
102 },
103 State::Done => {
104 JmapCoroutineState::Complete(Err(JmapEnvelopeListError::ResumedAfterDone))
105 }
106 }
107 }
108}