use alloc::{collections::BTreeMap, format, string::String, vec::Vec};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmail {
pub id: Option<String>,
pub blob_id: Option<String>,
pub thread_id: Option<String>,
pub mailbox_ids: Option<BTreeMap<String, bool>>,
pub keywords: Option<BTreeMap<String, bool>>,
pub size: Option<u64>,
pub received_at: Option<String>,
pub message_id: Option<Vec<String>>,
pub in_reply_to: Option<Vec<String>>,
pub references: Option<Vec<String>>,
pub sender: Option<Vec<JmapEmailAddress>>,
pub from: Option<Vec<JmapEmailAddress>>,
pub to: Option<Vec<JmapEmailAddress>>,
pub cc: Option<Vec<JmapEmailAddress>>,
pub bcc: Option<Vec<JmapEmailAddress>>,
pub reply_to: Option<Vec<JmapEmailAddress>>,
pub subject: Option<String>,
pub sent_at: Option<String>,
pub body_structure: Option<JmapEmailBodyPart>,
pub body_values: Option<BTreeMap<String, JmapEmailBodyValue>>,
pub text_body: Option<Vec<JmapEmailBodyPart>>,
pub html_body: Option<Vec<JmapEmailBodyPart>>,
pub attachments: Option<Vec<JmapEmailBodyPart>>,
pub has_attachment: Option<bool>,
pub preview: Option<String>,
pub headers: Option<Vec<JmapEmailHeader>>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailAddress {
pub name: Option<String>,
pub email: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailHeader {
pub name: String,
pub value: String,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailBodyPart {
pub part_id: Option<String>,
pub blob_id: Option<String>,
pub size: Option<u64>,
pub name: Option<String>,
pub r#type: Option<String>,
pub charset: Option<String>,
pub disposition: Option<String>,
pub cid: Option<String>,
pub language: Option<Vec<String>>,
pub location: Option<String>,
pub sub_parts: Option<Vec<JmapEmailBodyPart>>,
pub headers: Option<Vec<JmapEmailHeader>>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailBodyValue {
pub value: String,
pub is_encoding_problem: bool,
pub is_truncated: bool,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum JmapEmailProperty {
Id,
BlobId,
ThreadId,
MailboxIds,
Keywords,
Size,
ReceivedAt,
MessageId,
InReplyTo,
References,
Sender,
From,
To,
Cc,
Bcc,
ReplyTo,
Subject,
SentAt,
BodyStructure,
BodyValues,
TextBody,
HtmlBody,
Attachments,
HasAttachment,
Preview,
Headers,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum JmapEmailSortProperty {
ReceivedAt,
SentAt,
Size,
From,
To,
Subject,
HasAttachment,
Keyword,
AllInThreadHaveKeyword,
SomeInThreadHaveKeyword,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailFilter {
#[serde(skip_serializing_if = "Option::is_none")]
pub in_mailbox: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub in_mailbox_other_than: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub min_size: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_size: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub all_in_thread_have_keyword: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub some_in_thread_have_keyword: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub none_in_thread_have_keyword: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_keyword: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub not_keyword: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_attachment: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cc: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bcc: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailComparator {
pub property: JmapEmailSortProperty,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_ascending: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub collation: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keyword: Option<String>,
}
impl JmapEmailComparator {
pub fn received_at_desc() -> Self {
Self {
property: JmapEmailSortProperty::ReceivedAt,
is_ascending: Some(false),
collation: None,
keyword: None,
}
}
}
#[derive(Clone, Debug)]
pub enum JmapEmailPatchOp {
SetKeyword(String),
UnsetKeyword(String),
ReplaceKeywords(BTreeMap<String, bool>),
AddToMailbox(String),
RemoveFromMailbox(String),
ReplaceMailboxIds(BTreeMap<String, bool>),
}
#[derive(Clone, Debug, Default)]
pub struct JmapEmailPatch(pub Vec<JmapEmailPatchOp>);
impl JmapEmailPatch {
pub fn set_keyword(mut self, keyword: impl Into<String>) -> Self {
self.0.push(JmapEmailPatchOp::SetKeyword(keyword.into()));
self
}
pub fn unset_keyword(mut self, keyword: impl Into<String>) -> Self {
self.0.push(JmapEmailPatchOp::UnsetKeyword(keyword.into()));
self
}
pub fn replace_keywords(mut self, keywords: BTreeMap<String, bool>) -> Self {
self.0.push(JmapEmailPatchOp::ReplaceKeywords(keywords));
self
}
pub fn add_to_mailbox(mut self, id: impl Into<String>) -> Self {
self.0.push(JmapEmailPatchOp::AddToMailbox(id.into()));
self
}
pub fn remove_from_mailbox(mut self, id: impl Into<String>) -> Self {
self.0.push(JmapEmailPatchOp::RemoveFromMailbox(id.into()));
self
}
pub fn replace_mailbox_ids(mut self, ids: BTreeMap<String, bool>) -> Self {
self.0.push(JmapEmailPatchOp::ReplaceMailboxIds(ids));
self
}
}
impl Serialize for JmapEmailPatch {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut map = s.serialize_map(Some(self.0.len()))?;
for op in &self.0 {
match op {
JmapEmailPatchOp::SetKeyword(kw) => {
map.serialize_entry(&format!("keywords/{kw}"), &true)?
}
JmapEmailPatchOp::UnsetKeyword(kw) => {
map.serialize_entry(&format!("keywords/{kw}"), &Option::<bool>::None)?
}
JmapEmailPatchOp::ReplaceKeywords(kws) => map.serialize_entry("keywords", kws)?,
JmapEmailPatchOp::AddToMailbox(id) => {
map.serialize_entry(&format!("mailboxIds/{id}"), &true)?
}
JmapEmailPatchOp::RemoveFromMailbox(id) => {
map.serialize_entry(&format!("mailboxIds/{id}"), &Option::<bool>::None)?
}
JmapEmailPatchOp::ReplaceMailboxIds(ids) => {
map.serialize_entry("mailboxIds", ids)?
}
}
}
map.end()
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailImportArgs {
pub blob_id: String,
pub mailbox_ids: BTreeMap<String, bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<BTreeMap<String, bool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub received_at: Option<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapEmailCopyArgs {
pub id: String,
pub mailbox_ids: BTreeMap<String, bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keywords: Option<BTreeMap<String, bool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub received_at: Option<String>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum JmapEmailSetItemError {
TooManyKeywords { description: Option<String> },
TooManyMailboxes { description: Option<String> },
BlobNotFound { description: Option<String> },
NotFound { description: Option<String> },
InvalidPatch { description: Option<String> },
WillDestroy { description: Option<String> },
InvalidProperties {
description: Option<String>,
#[serde(default)]
properties: Vec<String>,
},
Singleton { description: Option<String> },
#[serde(other)]
Unknown,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum JmapEmailImportItemError {
InvalidEmail { description: Option<String> },
NotFound { description: Option<String> },
InvalidProperties {
description: Option<String>,
#[serde(default)]
properties: Vec<String>,
},
#[serde(other)]
Unknown,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum JmapEmailCopyItemError {
AlreadyExists { description: Option<String> },
NotFound { description: Option<String> },
InvalidProperties {
description: Option<String>,
#[serde(default)]
properties: Vec<String>,
},
#[serde(other)]
Unknown,
}