io_jmap/rfc8621/email/
get.rs1use core::fmt;
66
67use alloc::{string::String, vec, vec::Vec};
68
69use log::trace;
70use secrecy::SecretString;
71use serde::Serialize;
72use thiserror::Error;
73
74use crate::{
75 coroutine::*,
76 jmap_try,
77 rfc8620::{CORE_CAPABILITY, JmapBatch, JmapSession, get::*, send::*},
78 rfc8621::{
79 MAIL_CAPABILITY,
80 email::{JmapEmail, JmapEmailProperty},
81 },
82};
83
84#[derive(Debug, Error)]
86pub enum JmapEmailGetError {
87 #[error("JMAP Email/get failed: {0}")]
88 Send(#[from] JmapSendError),
89 #[error("JMAP Email/get failed: serialize args: {0}")]
90 SerializeArgs(#[source] serde_json::Error),
91 #[error("JMAP Email/get failed: {0}")]
92 Get(#[from] JmapGetError),
93}
94
95#[derive(Clone, Debug, Default)]
97pub struct JmapEmailGetOptions {
98 pub properties: Option<Vec<JmapEmailProperty>>,
100 pub fetch_text_body_values: bool,
102 pub fetch_html_body_values: bool,
104 pub max_body_value_bytes: u64,
106}
107
108#[derive(Clone, Debug)]
110pub struct JmapEmailGetOutput {
111 pub emails: Vec<JmapEmail>,
112 pub not_found: Vec<String>,
113 pub new_state: String,
114 pub keep_alive: bool,
115}
116
117pub struct JmapEmailGet {
119 state: State,
120}
121
122impl JmapEmailGet {
123 pub fn new(
124 session: &JmapSession,
125 http_auth: &SecretString,
126 ids: Vec<String>,
127 opts: JmapEmailGetOptions,
128 ) -> Result<Self, JmapEmailGetError> {
129 let account_id = session
130 .primary_accounts
131 .get(MAIL_CAPABILITY)
132 .cloned()
133 .unwrap_or_default();
134 let api_url = &session.api_url;
135
136 let args = serde_json::to_value(EmailGetArgs {
137 account_id,
138 ids,
139 properties: opts.properties,
140 fetch_text_body_values: opts.fetch_text_body_values,
141 fetch_html_body_values: opts.fetch_html_body_values,
142 max_body_value_bytes: opts.max_body_value_bytes,
143 })
144 .map_err(JmapEmailGetError::SerializeArgs)?;
145
146 let mut batch = JmapBatch::new();
147 batch.add("Email/get", args);
148 let request = batch.into_request(vec![CORE_CAPABILITY.into(), MAIL_CAPABILITY.into()]);
149
150 let send = JmapSend::new(http_auth, api_url, request)?;
151 Ok(Self {
152 state: State::Get(JmapGet::from_send(send)),
153 })
154 }
155}
156
157impl JmapCoroutine for JmapEmailGet {
158 type Yield = JmapYield;
159 type Return = Result<JmapEmailGetOutput, JmapEmailGetError>;
160
161 fn resume(&mut self, arg: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
162 trace!("Email/get: {}", self.state);
163 match &mut self.state {
164 State::Get(get) => {
165 let JmapGetOutput {
166 list,
167 not_found,
168 state,
169 keep_alive,
170 } = jmap_try!(get, arg);
171 JmapCoroutineState::Complete(Ok(JmapEmailGetOutput {
172 emails: list,
173 not_found,
174 new_state: state,
175 keep_alive,
176 }))
177 }
178 }
179 }
180}
181
182enum State {
183 Get(JmapGet<JmapEmail>),
184}
185
186impl fmt::Display for State {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match self {
189 Self::Get(_) => f.write_str("get"),
190 }
191 }
192}
193
194#[derive(Serialize)]
195#[serde(rename_all = "camelCase")]
196struct EmailGetArgs {
197 account_id: String,
198 ids: Vec<String>,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 properties: Option<Vec<JmapEmailProperty>>,
201 #[serde(skip_serializing_if = "is_false")]
202 fetch_text_body_values: bool,
203 #[serde(rename = "fetchHTMLBodyValues", skip_serializing_if = "is_false")]
204 fetch_html_body_values: bool,
205 #[serde(skip_serializing_if = "is_zero")]
206 max_body_value_bytes: u64,
207}
208
209fn is_false(b: &bool) -> bool {
210 !b
211}
212
213fn is_zero(v: &u64) -> bool {
214 *v == 0
215}