use alloc::{string::String, vec, vec::Vec};
use secrecy::SecretString;
use serde::Serialize;
use thiserror::Error;
use crate::{
coroutine::*,
jmap_try,
rfc8620::{JMAP_CORE_CAPABILITY, get::*, request::JmapBatch, send::*, session::JmapSession},
rfc8621::{
JMAP_MAIL_CAPABILITY,
email::{JmapEmail, JmapEmailProperty},
},
};
#[derive(Debug, Error)]
pub enum JmapEmailGetError {
#[error("JMAP Email/get failed: {0}")]
Send(#[from] JmapSendError),
#[error("JMAP Email/get failed: serialize args: {0}")]
SerializeArgs(#[source] serde_json::Error),
#[error("JMAP Email/get failed: {0}")]
Get(#[from] JmapGetError),
}
#[derive(Clone, Debug, Default)]
pub struct JmapEmailGetOptions {
pub properties: Option<Vec<JmapEmailProperty>>,
pub fetch_text_body_values: bool,
pub fetch_html_body_values: bool,
pub max_body_value_bytes: u64,
}
#[derive(Clone, Debug)]
pub struct JmapEmailGetOutput {
pub emails: Vec<JmapEmail>,
pub not_found: Vec<String>,
pub new_state: String,
pub keep_alive: bool,
}
pub struct JmapEmailGet {
state: State,
}
impl JmapEmailGet {
pub fn new(
session: &JmapSession,
http_auth: &SecretString,
ids: Vec<String>,
opts: JmapEmailGetOptions,
) -> Result<Self, JmapEmailGetError> {
let account_id = session
.primary_accounts
.get(JMAP_MAIL_CAPABILITY)
.cloned()
.unwrap_or_default();
let api_url = &session.api_url;
let args = serde_json::to_value(EmailGetArgs {
account_id,
ids,
properties: opts.properties,
fetch_text_body_values: opts.fetch_text_body_values,
fetch_html_body_values: opts.fetch_html_body_values,
max_body_value_bytes: opts.max_body_value_bytes,
})
.map_err(JmapEmailGetError::SerializeArgs)?;
let mut batch = JmapBatch::new();
batch.add("Email/get", args);
let request = batch.into_request(vec![
JMAP_CORE_CAPABILITY.into(),
JMAP_MAIL_CAPABILITY.into(),
]);
let send = JmapSend::new(http_auth, api_url, request)?;
Ok(Self {
state: State::Get(JmapGet::from_send(send)),
})
}
}
impl JmapCoroutine for JmapEmailGet {
type Yield = JmapYield;
type Return = Result<JmapEmailGetOutput, JmapEmailGetError>;
fn resume(&mut self, arg: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
match &mut self.state {
State::Get(get) => {
let JmapGetOutput {
list,
not_found,
state,
keep_alive,
} = jmap_try!(get, arg);
JmapCoroutineState::Complete(Ok(JmapEmailGetOutput {
emails: list,
not_found,
new_state: state,
keep_alive,
}))
}
}
}
}
enum State {
Get(JmapGet<JmapEmail>),
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct EmailGetArgs {
account_id: String,
ids: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
properties: Option<Vec<JmapEmailProperty>>,
#[serde(skip_serializing_if = "is_false")]
fetch_text_body_values: bool,
#[serde(rename = "fetchHTMLBodyValues", skip_serializing_if = "is_false")]
fetch_html_body_values: bool,
#[serde(skip_serializing_if = "is_zero")]
max_body_value_bytes: u64,
}
fn is_false(b: &bool) -> bool {
!b
}
fn is_zero(v: &u64) -> bool {
*v == 0
}