Get/Set implementation for all RFC8620/8261 objects.
parent
1680fdcd30
commit
cd74566ca3
|
@ -17,6 +17,7 @@ serde_json = "1.0"
|
||||||
chrono = { version = "0.4", features = ["serde"]}
|
chrono = { version = "0.4", features = ["serde"]}
|
||||||
reqwest = "0.11"
|
reqwest = "0.11"
|
||||||
ece = "2.2"
|
ece = "2.2"
|
||||||
|
base64 = "0.13"
|
||||||
|
|
||||||
#[dev-dependencies]
|
#[dev-dependencies]
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
@ -66,4 +67,46 @@ pub enum SetErrorType {
|
||||||
InvalidProperties,
|
InvalidProperties,
|
||||||
#[serde(rename = "singleton")]
|
#[serde(rename = "singleton")]
|
||||||
Singleton,
|
Singleton,
|
||||||
|
#[serde(rename = "mailboxHasChild")]
|
||||||
|
MailboxHasChild,
|
||||||
|
#[serde(rename = "mailboxHasEmail")]
|
||||||
|
MailboxHasEmail,
|
||||||
|
#[serde(rename = "blobNotFound")]
|
||||||
|
BlobNotFound,
|
||||||
|
#[serde(rename = "tooManyKeywords")]
|
||||||
|
TooManyKeywords,
|
||||||
|
#[serde(rename = "tooManyMailboxes")]
|
||||||
|
TooManyMailboxes,
|
||||||
|
#[serde(rename = "forbiddenFrom")]
|
||||||
|
ForbiddenFrom,
|
||||||
|
#[serde(rename = "invalidEmail")]
|
||||||
|
InvalidEmail,
|
||||||
|
#[serde(rename = "tooManyRecipients")]
|
||||||
|
TooManyRecipients,
|
||||||
|
#[serde(rename = "noRecipients")]
|
||||||
|
NoRecipients,
|
||||||
|
#[serde(rename = "invalidRecipients")]
|
||||||
|
InvalidRecipients,
|
||||||
|
#[serde(rename = "forbiddenMailFrom")]
|
||||||
|
ForbiddenMailFrom,
|
||||||
|
#[serde(rename = "forbiddenToSend")]
|
||||||
|
ForbiddenToSend,
|
||||||
|
#[serde(rename = "cannotUnsend")]
|
||||||
|
CannotUnsend,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_timestamp(timestamp: i64) -> DateTime<Utc> {
|
||||||
|
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(timestamp, 0), Utc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_not_set(string: &Option<String>) -> bool {
|
||||||
|
matches!(string, Some(string) if string.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn date_not_set(date: &Option<DateTime<Utc>>) -> bool {
|
||||||
|
matches!(date, Some(date) if date.timestamp() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_not_set<T>(list: &Option<Vec<T>>) -> bool {
|
||||||
|
matches!(list, Some(list) if list.is_empty() )
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
use crate::Get;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Email, EmailAddress, EmailAddressGroup, EmailBodyPart, EmailBodyValue, EmailHeader, Field,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Email<Get> {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
self.id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blob_id(&self) -> &str {
|
||||||
|
self.blob_id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn thread_id(&self) -> &str {
|
||||||
|
self.thread_id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mailbox_ids(&self) -> Vec<&str> {
|
||||||
|
self.mailbox_ids
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| **v)
|
||||||
|
.map(|(k, _)| k.as_str())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keywords(&self) -> Vec<&str> {
|
||||||
|
self.keywords
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| **v)
|
||||||
|
.map(|(k, _)| k.as_str())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.size.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn received_at(&self) -> i64 {
|
||||||
|
self.received_at.as_ref().unwrap().timestamp()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message_id(&self) -> Option<&[String]> {
|
||||||
|
self.message_id.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn in_reply_to(&self) -> Option<&[String]> {
|
||||||
|
self.in_reply_to.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn references(&self) -> Option<&[String]> {
|
||||||
|
self.references.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sender(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.sender.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.from.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.to.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cc(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.cc.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bcc(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.bcc.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subject(&self) -> Option<&str> {
|
||||||
|
self.subject.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sent_at(&self) -> Option<i64> {
|
||||||
|
self.sent_at.as_ref().map(|v| v.timestamp())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_structure(&self) -> Option<&EmailBodyPart> {
|
||||||
|
self.body_structure.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_value(&self, id: &str) -> Option<&EmailBodyValue> {
|
||||||
|
self.body_values.as_ref().and_then(|v| v.get(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_body(&self) -> Option<&[EmailBodyPart]> {
|
||||||
|
self.text_body.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_body(&self) -> Option<&[EmailBodyPart]> {
|
||||||
|
self.html_body.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attachments(&self) -> Option<&[EmailBodyPart]> {
|
||||||
|
self.attachments.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_attachment(&self) -> bool {
|
||||||
|
*self.has_attachment.as_ref().unwrap_or(&false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header(&self, id: &str) -> Option<&Field> {
|
||||||
|
self.others.get(id).and_then(|v| v.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_header(&self, id: &str) -> bool {
|
||||||
|
self.others.contains_key(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailBodyPart<Get> {
|
||||||
|
pub fn part_id(&self) -> Option<&str> {
|
||||||
|
self.part_id.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blob_id(&self) -> Option<&str> {
|
||||||
|
self.blob_id.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
*self.size.as_ref().unwrap_or(&0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn headers(&self) -> Option<&[EmailHeader]> {
|
||||||
|
self.headers.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn charset(&self) -> Option<&str> {
|
||||||
|
self.charset.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_type(&self) -> Option<&str> {
|
||||||
|
self.type_.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_disposition(&self) -> Option<&str> {
|
||||||
|
self.disposition.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_id(&self) -> Option<&str> {
|
||||||
|
self.cid.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_language(&self) -> Option<&[String]> {
|
||||||
|
self.language.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_location(&self) -> Option<&str> {
|
||||||
|
self.location.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_parts(&self) -> Option<&[EmailBodyPart]> {
|
||||||
|
self.sub_parts.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailBodyValue<Get> {
|
||||||
|
pub fn value(&self) -> &str {
|
||||||
|
self.value.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_encoding_problem(&self) -> bool {
|
||||||
|
self.is_encoding_problem
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_truncated(&self) -> bool {
|
||||||
|
self.is_truncated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailAddress<Get> {
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email(&self) -> &str {
|
||||||
|
self.email.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailAddressGroup<Get> {
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addresses(&self) -> &[EmailAddress] {
|
||||||
|
self.addresses.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailHeader<Get> {
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &str {
|
||||||
|
self.value.as_str()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,307 @@
|
||||||
|
pub mod get;
|
||||||
|
pub mod set;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::Get;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Email<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
blob_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "threadId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
thread_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "mailboxIds")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
mailbox_ids: Option<HashMap<String, bool>>,
|
||||||
|
|
||||||
|
#[serde(rename = "keywords")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
keywords: Option<HashMap<String, bool>>,
|
||||||
|
|
||||||
|
#[serde(rename = "size")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
size: Option<usize>,
|
||||||
|
|
||||||
|
#[serde(rename = "receivedAt")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
received_at: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
#[serde(rename = "messageId", alias = "header:Message-ID:asMessageIds")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
message_id: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "inReplyTo", alias = "header:In-Reply-To:asMessageIds")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
in_reply_to: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "references", alias = "header:References:asMessageIds")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
references: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "sender", alias = "header:Sender:asAddresses")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
sender: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "from", alias = "header:From:asAddresses")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
from: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "to", alias = "header:To:asAddresses")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
to: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "cc", alias = "header:Cc:asAddresses")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
cc: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "bcc", alias = "header:Bcc:asAddresses")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
bcc: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "replyTo", alias = "header:Reply-To:asAddresses")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
reply_to: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "subject", alias = "header:Subject:asText")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
subject: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "sentAt", alias = "header:Date:asDate")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
sent_at: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
#[serde(rename = "bodyStructure")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
body_structure: Option<Box<EmailBodyPart>>,
|
||||||
|
|
||||||
|
#[serde(rename = "bodyValues")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
body_values: Option<HashMap<String, EmailBodyValue>>,
|
||||||
|
|
||||||
|
#[serde(rename = "textBody")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
text_body: Option<Vec<EmailBodyPart>>,
|
||||||
|
|
||||||
|
#[serde(rename = "htmlBody")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
html_body: Option<Vec<EmailBodyPart>>,
|
||||||
|
|
||||||
|
#[serde(rename = "attachments")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
attachments: Option<Vec<EmailBodyPart>>,
|
||||||
|
|
||||||
|
#[serde(rename = "hasAttachment")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
has_attachment: Option<bool>,
|
||||||
|
|
||||||
|
#[serde(rename = "preview")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
preview: Option<String>,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
#[serde(skip_serializing_if = "HashMap::is_empty")]
|
||||||
|
others: HashMap<String, Option<Field>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EmailBodyPart<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "partId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
part_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
blob_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "size")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
size: Option<usize>,
|
||||||
|
|
||||||
|
#[serde(rename = "headers")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
headers: Option<Vec<EmailHeader>>,
|
||||||
|
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
name: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
type_: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "charset")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
charset: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "disposition")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
disposition: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "cid")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
cid: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "language")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
language: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "location")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
location: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "subParts")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
sub_parts: Option<Vec<EmailBodyPart>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EmailBodyValue<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "value")]
|
||||||
|
value: String,
|
||||||
|
|
||||||
|
#[serde(rename = "isEncodingProblem")]
|
||||||
|
is_encoding_problem: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "isTruncated")]
|
||||||
|
is_truncated: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Field {
|
||||||
|
Text(String),
|
||||||
|
TextList(Vec<String>),
|
||||||
|
Date(DateTime<Utc>),
|
||||||
|
Addresses(Vec<EmailAddress>),
|
||||||
|
GroupedAddresses(Vec<EmailAddressGroup>),
|
||||||
|
Bool(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EmailAddress<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
name: Option<String>,
|
||||||
|
email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EmailAddressGroup<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
name: Option<String>,
|
||||||
|
addresses: Vec<EmailAddress>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EmailHeader<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum EmailProperty {
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
Id,
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
BlobId,
|
||||||
|
#[serde(rename = "threadId")]
|
||||||
|
ThreadId,
|
||||||
|
#[serde(rename = "mailboxIds")]
|
||||||
|
MailboxIds,
|
||||||
|
#[serde(rename = "keywords")]
|
||||||
|
Keywords,
|
||||||
|
#[serde(rename = "size")]
|
||||||
|
Size,
|
||||||
|
#[serde(rename = "receivedAt")]
|
||||||
|
ReceivedAt,
|
||||||
|
#[serde(rename = "messageId")]
|
||||||
|
MessageId,
|
||||||
|
#[serde(rename = "inReplyTo")]
|
||||||
|
InReplyTo,
|
||||||
|
#[serde(rename = "references")]
|
||||||
|
References,
|
||||||
|
#[serde(rename = "sender")]
|
||||||
|
Sender,
|
||||||
|
#[serde(rename = "from")]
|
||||||
|
From,
|
||||||
|
#[serde(rename = "to")]
|
||||||
|
To,
|
||||||
|
#[serde(rename = "cc")]
|
||||||
|
Cc,
|
||||||
|
#[serde(rename = "bcc")]
|
||||||
|
Bcc,
|
||||||
|
#[serde(rename = "replyTo")]
|
||||||
|
ReplyTo,
|
||||||
|
#[serde(rename = "subject")]
|
||||||
|
Subject,
|
||||||
|
#[serde(rename = "sentAt")]
|
||||||
|
SentAt,
|
||||||
|
#[serde(rename = "bodyStructure")]
|
||||||
|
BodyStructure,
|
||||||
|
#[serde(rename = "bodyValues")]
|
||||||
|
BodyValues,
|
||||||
|
#[serde(rename = "textBody")]
|
||||||
|
TextBody,
|
||||||
|
#[serde(rename = "htmlBody")]
|
||||||
|
HtmlBody,
|
||||||
|
#[serde(rename = "attachments")]
|
||||||
|
Attachments,
|
||||||
|
#[serde(rename = "hasAttachment")]
|
||||||
|
HasAttachment,
|
||||||
|
#[serde(rename = "preview")]
|
||||||
|
Preview,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum EmailBodyProperty {
|
||||||
|
#[serde(rename = "partId")]
|
||||||
|
PartId,
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
BlobId,
|
||||||
|
#[serde(rename = "size")]
|
||||||
|
Size,
|
||||||
|
#[serde(rename = "headers")]
|
||||||
|
Headers,
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
Name,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
Type,
|
||||||
|
#[serde(rename = "charset")]
|
||||||
|
Charset,
|
||||||
|
#[serde(rename = "disposition")]
|
||||||
|
Disposition,
|
||||||
|
#[serde(rename = "cid")]
|
||||||
|
Cid,
|
||||||
|
#[serde(rename = "language")]
|
||||||
|
Language,
|
||||||
|
#[serde(rename = "location")]
|
||||||
|
Location,
|
||||||
|
#[serde(rename = "subParts")]
|
||||||
|
SubParts,
|
||||||
|
}
|
|
@ -0,0 +1,355 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{core::set::from_timestamp, Set};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
Email, EmailAddress, EmailAddressGroup, EmailBodyPart, EmailBodyValue, EmailHeader, Field,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Email<Set> {
|
||||||
|
pub fn mailbox_ids(mut self, mailbox_ids: impl Iterator<Item = String>) -> Self {
|
||||||
|
self.mailbox_ids = Some(mailbox_ids.into_iter().map(|s| (s, true)).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mailbox_id(mut self, mailbox_id: &str, set: bool) -> Self {
|
||||||
|
self.mailbox_ids = None;
|
||||||
|
self.others.insert(
|
||||||
|
format!("mailboxIds/{}", mailbox_id),
|
||||||
|
Field::Bool(set).into(),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keywords(mut self, keywords: impl Iterator<Item = String>) -> Self {
|
||||||
|
self.keywords = Some(keywords.into_iter().map(|s| (s, true)).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keyword(mut self, keyword: &str, set: bool) -> Self {
|
||||||
|
self.keywords = None;
|
||||||
|
self.others
|
||||||
|
.insert(format!("keywords/{}", keyword), Field::Bool(set).into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message_id(mut self, message_id: impl Iterator<Item = String>) -> Self {
|
||||||
|
self.message_id = Some(message_id.into_iter().collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn in_reply_to(mut self, in_reply_to: impl Iterator<Item = String>) -> Self {
|
||||||
|
self.in_reply_to = Some(in_reply_to.into_iter().collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn references(mut self, references: impl Iterator<Item = String>) -> Self {
|
||||||
|
self.references = Some(references.into_iter().collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sender<T, U>(mut self, sender: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.sender = Some(sender.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from<T, U>(mut self, from: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.from = Some(from.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to<T, U>(mut self, to: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.to = Some(to.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cc<T, U>(mut self, cc: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.cc = Some(cc.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bcc<T, U>(mut self, bcc: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.bcc = Some(bcc.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reply_to<T, U>(mut self, reply_to: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.reply_to = Some(reply_to.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subject(mut self, subject: String) -> Self {
|
||||||
|
self.subject = Some(subject);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sent_at(mut self, sent_at: i64) -> Self {
|
||||||
|
self.sent_at = Some(from_timestamp(sent_at));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_structure(mut self, body_structure: EmailBodyPart) -> Self {
|
||||||
|
self.body_structure = Some(body_structure.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_value(mut self, id: String, body_value: impl Into<EmailBodyValue>) -> Self {
|
||||||
|
self.body_values
|
||||||
|
.get_or_insert_with(HashMap::new)
|
||||||
|
.insert(id, body_value.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_body(mut self, text_body: EmailBodyPart) -> Self {
|
||||||
|
self.text_body.get_or_insert_with(Vec::new).push(text_body);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_body(mut self, html_body: EmailBodyPart) -> Self {
|
||||||
|
self.html_body.get_or_insert_with(Vec::new).push(html_body);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attachment(mut self, attachment: EmailBodyPart) -> Self {
|
||||||
|
self.attachments
|
||||||
|
.get_or_insert_with(Vec::new)
|
||||||
|
.push(attachment);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header(mut self, header: String, value: impl Into<Field>) -> Self {
|
||||||
|
self.others.insert(header, Some(value.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Email {
|
||||||
|
pub fn new() -> Email<Set> {
|
||||||
|
Email {
|
||||||
|
_state: Default::default(),
|
||||||
|
id: Default::default(),
|
||||||
|
blob_id: Default::default(),
|
||||||
|
thread_id: Default::default(),
|
||||||
|
mailbox_ids: Default::default(),
|
||||||
|
keywords: Default::default(),
|
||||||
|
size: Default::default(),
|
||||||
|
received_at: Default::default(),
|
||||||
|
message_id: Default::default(),
|
||||||
|
in_reply_to: Default::default(),
|
||||||
|
references: Default::default(),
|
||||||
|
sender: Default::default(),
|
||||||
|
from: Default::default(),
|
||||||
|
to: Default::default(),
|
||||||
|
cc: Default::default(),
|
||||||
|
bcc: Default::default(),
|
||||||
|
reply_to: Default::default(),
|
||||||
|
subject: Default::default(),
|
||||||
|
sent_at: Default::default(),
|
||||||
|
body_structure: Default::default(),
|
||||||
|
body_values: Default::default(),
|
||||||
|
text_body: Default::default(),
|
||||||
|
html_body: Default::default(),
|
||||||
|
attachments: Default::default(),
|
||||||
|
has_attachment: Default::default(),
|
||||||
|
preview: Default::default(),
|
||||||
|
others: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailBodyPart {
|
||||||
|
pub fn new() -> EmailBodyPart<Set> {
|
||||||
|
EmailBodyPart {
|
||||||
|
part_id: None,
|
||||||
|
blob_id: None,
|
||||||
|
size: None,
|
||||||
|
headers: None,
|
||||||
|
name: None,
|
||||||
|
type_: None,
|
||||||
|
charset: None,
|
||||||
|
disposition: None,
|
||||||
|
cid: None,
|
||||||
|
language: None,
|
||||||
|
location: None,
|
||||||
|
sub_parts: None,
|
||||||
|
_state: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailBodyPart<Set> {
|
||||||
|
pub fn part_id(mut self, part_id: String) -> Self {
|
||||||
|
self.part_id = Some(part_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blob_id(mut self, blob_id: String) -> Self {
|
||||||
|
self.blob_id = Some(blob_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(mut self, name: String) -> Self {
|
||||||
|
self.name = Some(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_type(mut self, content_type: String) -> Self {
|
||||||
|
self.type_ = Some(content_type);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_id(mut self, content_id: String) -> Self {
|
||||||
|
self.cid = Some(content_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_language(mut self, content_language: impl Iterator<Item = String>) -> Self {
|
||||||
|
self.language = Some(content_language.into_iter().collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_location(mut self, content_location: String) -> Self {
|
||||||
|
self.location = Some(content_location);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_part(mut self, sub_part: EmailBodyPart) -> Self {
|
||||||
|
self.sub_parts.get_or_insert_with(Vec::new).push(sub_part);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for EmailBodyValue {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
EmailBodyValue {
|
||||||
|
value,
|
||||||
|
is_encoding_problem: false,
|
||||||
|
is_truncated: false,
|
||||||
|
_state: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for EmailBodyValue {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
EmailBodyValue {
|
||||||
|
value: value.to_string(),
|
||||||
|
is_encoding_problem: false,
|
||||||
|
is_truncated: false,
|
||||||
|
_state: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailAddress {
|
||||||
|
pub fn new(email: String) -> EmailAddress<Set> {
|
||||||
|
EmailAddress {
|
||||||
|
_state: Default::default(),
|
||||||
|
name: None,
|
||||||
|
email,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailAddress<Set> {
|
||||||
|
pub fn name(mut self, name: String) -> Self {
|
||||||
|
self.name = Some(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for EmailAddress {
|
||||||
|
fn from(email: String) -> Self {
|
||||||
|
EmailAddress {
|
||||||
|
_state: Default::default(),
|
||||||
|
name: None,
|
||||||
|
email,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(String, String)> for EmailAddress {
|
||||||
|
fn from(parts: (String, String)) -> Self {
|
||||||
|
EmailAddress {
|
||||||
|
_state: Default::default(),
|
||||||
|
name: parts.0.into(),
|
||||||
|
email: parts.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for EmailAddress {
|
||||||
|
fn from(email: &str) -> Self {
|
||||||
|
EmailAddress {
|
||||||
|
_state: Default::default(),
|
||||||
|
name: None,
|
||||||
|
email: email.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&str, &str)> for EmailAddress {
|
||||||
|
fn from(parts: (&str, &str)) -> Self {
|
||||||
|
EmailAddress {
|
||||||
|
_state: Default::default(),
|
||||||
|
name: parts.0.to_string().into(),
|
||||||
|
email: parts.1.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailAddressGroup {
|
||||||
|
pub fn new() -> EmailAddressGroup<Set> {
|
||||||
|
EmailAddressGroup {
|
||||||
|
_state: Default::default(),
|
||||||
|
name: None,
|
||||||
|
addresses: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailAddressGroup<Set> {
|
||||||
|
pub fn name(mut self, name: String) -> Self {
|
||||||
|
self.name = Some(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn address(mut self, address: impl Into<EmailAddress>) -> Self {
|
||||||
|
self.addresses.push(address.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailHeader {
|
||||||
|
pub fn new(name: String, value: String) -> EmailHeader<Set> {
|
||||||
|
EmailHeader {
|
||||||
|
_state: Default::default(),
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
use crate::Get;
|
||||||
|
|
||||||
|
use super::{Address, Delivered, DeliveryStatus, Displayed, EmailSubmission, UndoStatus};
|
||||||
|
|
||||||
|
impl EmailSubmission<Get> {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
self.id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identity_id(&self) -> &str {
|
||||||
|
self.identity_id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email_id(&self) -> &str {
|
||||||
|
self.email_id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn thread_id(&self) -> &str {
|
||||||
|
self.thread_id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mail_from(&self) -> Option<&Address> {
|
||||||
|
self.envelope.as_ref().map(|e| &e.mail_from)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rcpt_to(&self) -> Option<&[Address]> {
|
||||||
|
self.envelope.as_ref().map(|e| e.rcpt_to.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_at(&self) -> i64 {
|
||||||
|
self.send_at.as_ref().unwrap().timestamp()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn undo_status(&self) -> &UndoStatus {
|
||||||
|
self.undo_status.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delivery_status(&self, email: &str) -> Option<&DeliveryStatus> {
|
||||||
|
self.delivery_status.as_ref().and_then(|ds| ds.get(email))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dsn_blob_ids(&self) -> Option<&[String]> {
|
||||||
|
self.dsn_blob_ids.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mdn_blob_ids(&self) -> Option<&[String]> {
|
||||||
|
self.mdn_blob_ids.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address<Get> {
|
||||||
|
pub fn email(&self) -> &str {
|
||||||
|
&self.email
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parameter(&self, param: &str) -> Option<&str> {
|
||||||
|
self.parameters.as_ref()?.get(param)?.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_parameter(&self, param: &str) -> bool {
|
||||||
|
self.parameters
|
||||||
|
.as_ref()
|
||||||
|
.map(|ps| ps.contains_key(param))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeliveryStatus {
|
||||||
|
pub fn smtp_reply(&self) -> &str {
|
||||||
|
&self.smtp_reply
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delivered(&self) -> &Delivered {
|
||||||
|
&self.delivered
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn displayed(&self) -> &Displayed {
|
||||||
|
&self.displayed
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
pub mod get;
|
||||||
|
pub mod set;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::Get;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct EmailSubmission<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "identityId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
identity_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "emailId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
email_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "threadId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
thread_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "envelope")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
envelope: Option<Envelope>,
|
||||||
|
|
||||||
|
#[serde(rename = "sendAt")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
send_at: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
#[serde(rename = "undoStatus")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
undo_status: Option<UndoStatus>,
|
||||||
|
|
||||||
|
#[serde(rename = "deliveryStatus")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
delivery_status: Option<HashMap<String, DeliveryStatus>>,
|
||||||
|
|
||||||
|
#[serde(rename = "dsnBlobIds")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
dsn_blob_ids: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "mdnBlobIds")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
mdn_blob_ids: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Envelope {
|
||||||
|
#[serde(rename = "mailFrom")]
|
||||||
|
mail_from: Address,
|
||||||
|
|
||||||
|
#[serde(rename = "rcptTo")]
|
||||||
|
rcpt_to: Vec<Address>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Address<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
email: String,
|
||||||
|
parameters: Option<HashMap<String, Option<String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum UndoStatus {
|
||||||
|
#[serde(rename = "pending")]
|
||||||
|
Pending,
|
||||||
|
#[serde(rename = "final")]
|
||||||
|
Final,
|
||||||
|
#[serde(rename = "canceled")]
|
||||||
|
Canceled,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct DeliveryStatus {
|
||||||
|
#[serde(rename = "smtpReply")]
|
||||||
|
smtp_reply: String,
|
||||||
|
|
||||||
|
#[serde(rename = "delivered")]
|
||||||
|
delivered: Delivered,
|
||||||
|
|
||||||
|
#[serde(rename = "displayed")]
|
||||||
|
displayed: Displayed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum Delivered {
|
||||||
|
#[serde(rename = "queued")]
|
||||||
|
Queued,
|
||||||
|
#[serde(rename = "yes")]
|
||||||
|
Yes,
|
||||||
|
#[serde(rename = "no")]
|
||||||
|
No,
|
||||||
|
#[serde(rename = "unknown")]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum Displayed {
|
||||||
|
#[serde(rename = "unknown")]
|
||||||
|
Unknown,
|
||||||
|
#[serde(rename = "yes")]
|
||||||
|
Yes,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum EmailSubmissionProperty {
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
Id,
|
||||||
|
#[serde(rename = "identityId")]
|
||||||
|
IdentityId,
|
||||||
|
#[serde(rename = "emailId")]
|
||||||
|
EmailId,
|
||||||
|
#[serde(rename = "threadId")]
|
||||||
|
ThreadId,
|
||||||
|
#[serde(rename = "envelope")]
|
||||||
|
Envelope,
|
||||||
|
#[serde(rename = "sendAt")]
|
||||||
|
SendAt,
|
||||||
|
#[serde(rename = "undoStatus")]
|
||||||
|
UndoStatus,
|
||||||
|
#[serde(rename = "deliveryStatus")]
|
||||||
|
DeliveryStatus,
|
||||||
|
#[serde(rename = "dsnBlobIds")]
|
||||||
|
DsnBlobIds,
|
||||||
|
#[serde(rename = "mdnBlobIds")]
|
||||||
|
MdnBlobIds,
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::Set;
|
||||||
|
|
||||||
|
use super::{Address, EmailSubmission, Envelope, UndoStatus};
|
||||||
|
|
||||||
|
impl EmailSubmission<Set> {
|
||||||
|
pub fn identity_id(mut self, identity_id: String) -> Self {
|
||||||
|
self.identity_id = Some(identity_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email_id(mut self, email_id: String) -> Self {
|
||||||
|
self.email_id = Some(email_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn envelope<T, U>(mut self, mail_from: U, rcpt_to: T) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<Address>,
|
||||||
|
{
|
||||||
|
self.envelope = Some(Envelope {
|
||||||
|
mail_from: mail_from.into(),
|
||||||
|
rcpt_to: rcpt_to.map(|s| s.into()).collect(),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn undo_status(mut self, undo_status: UndoStatus) -> Self {
|
||||||
|
self.undo_status = Some(undo_status);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailSubmission {
|
||||||
|
pub fn new() -> EmailSubmission<Set> {
|
||||||
|
EmailSubmission {
|
||||||
|
_state: Default::default(),
|
||||||
|
id: None,
|
||||||
|
identity_id: None,
|
||||||
|
email_id: None,
|
||||||
|
thread_id: None,
|
||||||
|
envelope: None,
|
||||||
|
send_at: None,
|
||||||
|
undo_status: None,
|
||||||
|
delivery_status: None,
|
||||||
|
dsn_blob_ids: None,
|
||||||
|
mdn_blob_ids: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address {
|
||||||
|
pub fn new(email: String) -> Address<Set> {
|
||||||
|
Address {
|
||||||
|
_state: Default::default(),
|
||||||
|
email,
|
||||||
|
parameters: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address<Set> {
|
||||||
|
pub fn parameter(mut self, parameter: String, value: Option<String>) -> Self {
|
||||||
|
self.parameters
|
||||||
|
.get_or_insert_with(HashMap::new)
|
||||||
|
.insert(parameter, value);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Address {
|
||||||
|
fn from(email: String) -> Self {
|
||||||
|
Address {
|
||||||
|
_state: Default::default(),
|
||||||
|
email,
|
||||||
|
parameters: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Address {
|
||||||
|
fn from(email: &str) -> Self {
|
||||||
|
Address {
|
||||||
|
_state: Default::default(),
|
||||||
|
email: email.to_string(),
|
||||||
|
parameters: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
use crate::{email::EmailAddress, Get};
|
||||||
|
|
||||||
|
use super::Identity;
|
||||||
|
|
||||||
|
impl Identity<Get> {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
self.id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email(&self) -> &str {
|
||||||
|
self.email.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reply_to(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.reply_to.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bcc(&self) -> Option<&[EmailAddress]> {
|
||||||
|
self.bcc.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_signature(&self) -> Option<&str> {
|
||||||
|
self.text_signature.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_signature(&self) -> Option<&str> {
|
||||||
|
self.html_signature.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_delete(&self) -> bool {
|
||||||
|
self.may_delete.unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
pub mod get;
|
||||||
|
pub mod set;
|
||||||
|
|
||||||
|
use crate::core::set::list_not_set;
|
||||||
|
use crate::{email::EmailAddress, Get};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Identity<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub name: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "email")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub email: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "replyTo")]
|
||||||
|
#[serde(skip_serializing_if = "list_not_set")]
|
||||||
|
pub reply_to: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "bcc")]
|
||||||
|
#[serde(skip_serializing_if = "list_not_set")]
|
||||||
|
pub bcc: Option<Vec<EmailAddress>>,
|
||||||
|
|
||||||
|
#[serde(rename = "textSignature")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub text_signature: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "htmlSignature")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub html_signature: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "mayDelete")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub may_delete: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum IdentityProperty {
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
Id,
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
Name,
|
||||||
|
#[serde(rename = "email")]
|
||||||
|
Email,
|
||||||
|
#[serde(rename = "replyTo")]
|
||||||
|
ReplyTo,
|
||||||
|
#[serde(rename = "bcc")]
|
||||||
|
Bcc,
|
||||||
|
#[serde(rename = "textSignature")]
|
||||||
|
TextSignature,
|
||||||
|
#[serde(rename = "htmlSignature")]
|
||||||
|
HtmlSignature,
|
||||||
|
#[serde(rename = "mayDelete")]
|
||||||
|
MayDelete,
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::{email::EmailAddress, Set};
|
||||||
|
|
||||||
|
use super::Identity;
|
||||||
|
|
||||||
|
impl Identity<Set> {
|
||||||
|
pub fn name(mut self, name: String) -> Self {
|
||||||
|
self.name = Some(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email(mut self, email: String) -> Self {
|
||||||
|
self.email = Some(email);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bcc<T, U>(mut self, bcc: Option<T>) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.bcc = bcc.map(|s| s.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reply_to<T, U>(mut self, reply_to: Option<T>) -> Self
|
||||||
|
where
|
||||||
|
T: Iterator<Item = U>,
|
||||||
|
U: Into<EmailAddress>,
|
||||||
|
{
|
||||||
|
self.reply_to = reply_to.map(|s| s.map(|s| s.into()).collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_signature(mut self, text_signature: String) -> Self {
|
||||||
|
self.text_signature = Some(text_signature);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_signature(mut self, html_signature: String) -> Self {
|
||||||
|
self.html_signature = Some(html_signature);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Identity {
|
||||||
|
pub fn new() -> Identity<Set> {
|
||||||
|
Identity {
|
||||||
|
_state: Default::default(),
|
||||||
|
id: None,
|
||||||
|
name: None,
|
||||||
|
email: None,
|
||||||
|
reply_to: Vec::with_capacity(0).into(),
|
||||||
|
bcc: Vec::with_capacity(0).into(),
|
||||||
|
text_signature: None,
|
||||||
|
html_signature: None,
|
||||||
|
may_delete: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/lib.rs
12
src/lib.rs
|
@ -4,7 +4,13 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod blob;
|
pub mod blob;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
pub mod email;
|
||||||
|
pub mod email_submission;
|
||||||
|
pub mod identity;
|
||||||
|
pub mod mailbox;
|
||||||
pub mod push_subscription;
|
pub mod push_subscription;
|
||||||
|
pub mod thread;
|
||||||
|
pub mod vacation_response;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
|
||||||
pub enum URI {
|
pub enum URI {
|
||||||
|
@ -94,6 +100,7 @@ pub enum Object {
|
||||||
Mailbox,
|
Mailbox,
|
||||||
Thread,
|
Thread,
|
||||||
Email,
|
Email,
|
||||||
|
EmailDelivery,
|
||||||
SearchSnippet,
|
SearchSnippet,
|
||||||
Identity,
|
Identity,
|
||||||
EmailSubmission,
|
EmailSubmission,
|
||||||
|
@ -112,3 +119,8 @@ pub struct StateChange {
|
||||||
pub type_: StateChangeType,
|
pub type_: StateChangeType,
|
||||||
pub changed: HashMap<String, HashMap<Object, String>>,
|
pub changed: HashMap<String, HashMap<Object, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Get;
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Set;
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
use crate::Get;
|
||||||
|
|
||||||
|
use super::{Mailbox, Role};
|
||||||
|
|
||||||
|
impl Mailbox<Get> {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
self.id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.name.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent_id(&self) -> Option<&str> {
|
||||||
|
self.parent_id.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn role(&self) -> Role {
|
||||||
|
self.role.as_ref().cloned().unwrap_or(Role::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sort_order(&self) -> u32 {
|
||||||
|
self.sort_order.as_ref().copied().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn total_emails(&self) -> usize {
|
||||||
|
self.total_emails.as_ref().copied().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unread_emails(&self) -> usize {
|
||||||
|
self.unread_emails.as_ref().copied().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn total_threads(&self) -> usize {
|
||||||
|
self.total_threads.as_ref().copied().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unread_threads(&self) -> usize {
|
||||||
|
self.unread_threads.as_ref().copied().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_subscribed(&self) -> bool {
|
||||||
|
*self.is_subscribed.as_ref().unwrap_or(&false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_read_items(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_read_items
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_add_items(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_add_items
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_remove_items(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_remove_items
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_set_seen(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_set_seen
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_set_keywords(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_set_keywords
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_create_child(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_create_child
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_rename(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_rename
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_delete(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_delete
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_submit(&self) -> bool {
|
||||||
|
self.my_rights.as_ref().unwrap().may_submit
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
pub mod get;
|
||||||
|
pub mod set;
|
||||||
|
|
||||||
|
use crate::core::set::string_not_set;
|
||||||
|
use crate::mailbox::set::role_not_set;
|
||||||
|
use crate::Get;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Mailbox<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
name: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "parentId")]
|
||||||
|
#[serde(skip_serializing_if = "string_not_set")]
|
||||||
|
parent_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "role")]
|
||||||
|
#[serde(skip_serializing_if = "role_not_set")]
|
||||||
|
role: Option<Role>,
|
||||||
|
|
||||||
|
#[serde(rename = "sortOrder")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
sort_order: Option<u32>,
|
||||||
|
|
||||||
|
#[serde(rename = "totalEmails")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
total_emails: Option<usize>,
|
||||||
|
|
||||||
|
#[serde(rename = "unreadEmails")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
unread_emails: Option<usize>,
|
||||||
|
|
||||||
|
#[serde(rename = "totalThreads")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
total_threads: Option<usize>,
|
||||||
|
|
||||||
|
#[serde(rename = "unreadThreads")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
unread_threads: Option<usize>,
|
||||||
|
|
||||||
|
#[serde(rename = "myRights")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
my_rights: Option<MailboxRights>,
|
||||||
|
|
||||||
|
#[serde(rename = "isSubscribed")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
is_subscribed: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum Role {
|
||||||
|
Archive,
|
||||||
|
Drafts,
|
||||||
|
Important,
|
||||||
|
Inbox,
|
||||||
|
Junk,
|
||||||
|
Sent,
|
||||||
|
Trash,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct MailboxRights {
|
||||||
|
#[serde(rename = "mayReadItems")]
|
||||||
|
may_read_items: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "mayAddItems")]
|
||||||
|
may_add_items: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "mayRemoveItems")]
|
||||||
|
may_remove_items: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "maySetSeen")]
|
||||||
|
may_set_seen: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "maySetKeywords")]
|
||||||
|
may_set_keywords: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "mayCreateChild")]
|
||||||
|
may_create_child: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "mayRename")]
|
||||||
|
may_rename: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "mayDelete")]
|
||||||
|
may_delete: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "maySubmit")]
|
||||||
|
may_submit: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum MailboxProperty {
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
Id,
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
Name,
|
||||||
|
#[serde(rename = "parentId")]
|
||||||
|
ParentId,
|
||||||
|
#[serde(rename = "role")]
|
||||||
|
Role,
|
||||||
|
#[serde(rename = "sortOrder")]
|
||||||
|
SortOrder,
|
||||||
|
#[serde(rename = "totalEmails")]
|
||||||
|
TotalEmails,
|
||||||
|
#[serde(rename = "unreadEmails")]
|
||||||
|
UnreadEmails,
|
||||||
|
#[serde(rename = "totalThreads")]
|
||||||
|
TotalThreads,
|
||||||
|
#[serde(rename = "unreadThreads")]
|
||||||
|
UnreadThreads,
|
||||||
|
#[serde(rename = "myRights")]
|
||||||
|
MyRights,
|
||||||
|
#[serde(rename = "isSubscribed")]
|
||||||
|
IsSubscribed,
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
use crate::Set;
|
||||||
|
|
||||||
|
use super::{Mailbox, Role};
|
||||||
|
|
||||||
|
impl Mailbox<Set> {
|
||||||
|
pub fn name(mut self, name: String) -> Self {
|
||||||
|
self.name = Some(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent_id(mut self, parent_id: Option<String>) -> Self {
|
||||||
|
self.parent_id = parent_id;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn role(mut self, role: Role) -> Self {
|
||||||
|
if !matches!(role, Role::None) {
|
||||||
|
self.role = Some(role);
|
||||||
|
} else {
|
||||||
|
self.role = None;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sort_order(mut self, sort_order: u32) -> Self {
|
||||||
|
self.sort_order = sort_order.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn role_not_set(role: &Option<Role>) -> bool {
|
||||||
|
matches!(role, Some(Role::None))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mailbox {
|
||||||
|
pub fn new() -> Mailbox<Set> {
|
||||||
|
Mailbox {
|
||||||
|
_state: Default::default(),
|
||||||
|
id: None,
|
||||||
|
name: None,
|
||||||
|
parent_id: "".to_string().into(),
|
||||||
|
role: Role::None.into(),
|
||||||
|
sort_order: None,
|
||||||
|
total_emails: None,
|
||||||
|
unread_emails: None,
|
||||||
|
total_threads: None,
|
||||||
|
unread_threads: None,
|
||||||
|
my_rights: None,
|
||||||
|
is_subscribed: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
use crate::{Get, Object};
|
||||||
|
|
||||||
|
use super::{Keys, PushSubscription};
|
||||||
|
|
||||||
|
impl PushSubscription<Get> {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
self.id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_client_id(&self) -> &str {
|
||||||
|
self.device_client_id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url(&self) -> &str {
|
||||||
|
self.url.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> Option<&Keys> {
|
||||||
|
self.keys.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verification_code(&self) -> Option<&str> {
|
||||||
|
self.verification_code.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expires(&self) -> Option<i64> {
|
||||||
|
self.expires.map(|v| v.timestamp())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn types(&self) -> Option<&[Object]> {
|
||||||
|
self.types.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keys {
|
||||||
|
pub fn p256dh(&self) -> Option<Vec<u8>> {
|
||||||
|
base64::decode_config(&self.p256dh, base64::URL_SAFE).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn auth(&self) -> Option<Vec<u8>> {
|
||||||
|
base64::decode_config(&self.auth, base64::URL_SAFE).ok()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,17 @@
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::Object;
|
|
||||||
|
|
||||||
pub mod get;
|
pub mod get;
|
||||||
pub mod set;
|
pub mod set;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::core::set::list_not_set;
|
||||||
|
use crate::{Get, Object};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PushSubscription {
|
pub struct PushSubscription<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
#[serde(rename = "id")]
|
#[serde(rename = "id")]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
id: Option<String>,
|
id: Option<String>,
|
||||||
|
@ -33,7 +37,7 @@ pub struct PushSubscription {
|
||||||
expires: Option<DateTime<Utc>>,
|
expires: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
#[serde(rename = "types")]
|
#[serde(rename = "types")]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "list_not_set")]
|
||||||
types: Option<Vec<Object>>,
|
types: Option<Vec<Object>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::{core::set::from_timestamp, Object, Set};
|
||||||
|
|
||||||
|
use super::{Keys, PushSubscription};
|
||||||
|
|
||||||
|
impl PushSubscription<Set> {
|
||||||
|
pub fn device_client_id(mut self, device_client_id: String) -> Self {
|
||||||
|
self.device_client_id = Some(device_client_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url(mut self, url: String) -> Self {
|
||||||
|
self.url = Some(url);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verification_code(mut self, verification_code: String) -> Self {
|
||||||
|
self.verification_code = Some(verification_code);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(mut self, keys: Keys) -> Self {
|
||||||
|
self.keys = Some(keys);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expires(mut self, expires: i64) -> Self {
|
||||||
|
self.expires = Some(from_timestamp(expires));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn types(mut self, types: Option<impl Iterator<Item = Object>>) -> Self {
|
||||||
|
self.types = types.map(|s| s.collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushSubscription {
|
||||||
|
pub fn new() -> PushSubscription<Set> {
|
||||||
|
PushSubscription {
|
||||||
|
_state: Default::default(),
|
||||||
|
id: None,
|
||||||
|
device_client_id: None,
|
||||||
|
url: None,
|
||||||
|
keys: None,
|
||||||
|
verification_code: None,
|
||||||
|
expires: None,
|
||||||
|
types: Vec::with_capacity(0).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keys {
|
||||||
|
pub fn new(p256dh: &[u8], auth: &[u8]) -> Self {
|
||||||
|
Keys {
|
||||||
|
p256dh: base64::encode_config(&p256dh, base64::URL_SAFE),
|
||||||
|
auth: base64::encode_config(&auth, base64::URL_SAFE),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate() -> Option<Self> {
|
||||||
|
let (p256dh, auth) = ece::generate_keypair_and_auth_secret().ok()?;
|
||||||
|
Self::new(&p256dh.pub_as_raw().ok()?, &auth).into()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
use super::Thread;
|
||||||
|
|
||||||
|
impl Thread {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email_ids(&self) -> &[String] {
|
||||||
|
&self.email_ids
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
pub mod get;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Thread {
|
||||||
|
id: String,
|
||||||
|
#[serde(rename = "emailIds")]
|
||||||
|
email_ids: Vec<String>,
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
use crate::Get;
|
||||||
|
|
||||||
|
use super::VacationResponse;
|
||||||
|
|
||||||
|
impl VacationResponse<Get> {
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
self.id.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.is_enabled.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_date(&self) -> Option<i64> {
|
||||||
|
self.from_date.as_ref().map(|dt| dt.timestamp())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_date(&self) -> Option<i64> {
|
||||||
|
self.to_date.as_ref().map(|dt| dt.timestamp())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subject(&self) -> Option<&str> {
|
||||||
|
self.subject.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_body(&self) -> Option<&str> {
|
||||||
|
self.text_body.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_body(&self) -> Option<&str> {
|
||||||
|
self.html_body.as_deref()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
pub mod get;
|
||||||
|
pub mod set;
|
||||||
|
|
||||||
|
use crate::core::set::date_not_set;
|
||||||
|
use crate::core::set::string_not_set;
|
||||||
|
use crate::Get;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct VacationResponse<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "isEnabled")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
is_enabled: Option<bool>,
|
||||||
|
|
||||||
|
#[serde(rename = "fromDate")]
|
||||||
|
#[serde(skip_serializing_if = "date_not_set")]
|
||||||
|
from_date: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
#[serde(rename = "toDate")]
|
||||||
|
#[serde(skip_serializing_if = "date_not_set")]
|
||||||
|
to_date: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
#[serde(rename = "subject")]
|
||||||
|
#[serde(skip_serializing_if = "string_not_set")]
|
||||||
|
subject: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "textBody")]
|
||||||
|
#[serde(skip_serializing_if = "string_not_set")]
|
||||||
|
text_body: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "htmlBody")]
|
||||||
|
#[serde(skip_serializing_if = "string_not_set")]
|
||||||
|
html_body: Option<String>,
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::{core::set::from_timestamp, Set};
|
||||||
|
|
||||||
|
use super::VacationResponse;
|
||||||
|
|
||||||
|
impl VacationResponse<Set> {
|
||||||
|
pub fn is_enabled(mut self, is_enabled: bool) -> Self {
|
||||||
|
self.is_enabled = Some(is_enabled);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_date(mut self, from_date: Option<i64>) -> Self {
|
||||||
|
self.from_date = from_date.map(from_timestamp);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_date(mut self, to_date: Option<i64>) -> Self {
|
||||||
|
self.to_date = to_date.map(from_timestamp);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subject(mut self, subject: Option<String>) -> Self {
|
||||||
|
self.subject = subject;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_body(mut self, text_body: Option<String>) -> Self {
|
||||||
|
self.text_body = text_body;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_body(mut self, html_body: Option<String>) -> Self {
|
||||||
|
self.html_body = html_body;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VacationResponse {
|
||||||
|
pub fn new() -> VacationResponse<Set> {
|
||||||
|
VacationResponse {
|
||||||
|
_state: Default::default(),
|
||||||
|
id: None,
|
||||||
|
is_enabled: None,
|
||||||
|
from_date: from_timestamp(0).into(),
|
||||||
|
to_date: from_timestamp(0).into(),
|
||||||
|
subject: "".to_string().into(),
|
||||||
|
text_body: "".to_string().into(),
|
||||||
|
html_body: "".to_string().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue