JMAP for Sieve Scripts support.
parent
9f5e950f20
commit
6cd9019699
|
@ -1,3 +1,7 @@
|
||||||
|
jmap-client 0.2.0
|
||||||
|
================================
|
||||||
|
- JMAP for Sieve Scripts support.
|
||||||
|
|
||||||
jmap-client 0.1.0
|
jmap-client 0.1.0
|
||||||
================================
|
================================
|
||||||
- First release.
|
- First release.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "jmap-client"
|
name = "jmap-client"
|
||||||
description = "JMAP client library for Rust"
|
description = "JMAP client library for Rust"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = [ "Stalwart Labs Ltd. <hello@stalw.art>"]
|
authors = [ "Stalwart Labs Ltd. <hello@stalw.art>"]
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
|
|
|
@ -10,6 +10,7 @@ _jmap-client_ is a **JSON Meta Application Protocol (JMAP) library** written in
|
||||||
- JMAP Core ([RFC 8620](https://datatracker.ietf.org/doc/html/rfc8620))
|
- JMAP Core ([RFC 8620](https://datatracker.ietf.org/doc/html/rfc8620))
|
||||||
- JMAP for Mail ([RFC 8621](https://datatracker.ietf.org/doc/html/rfc8621))
|
- JMAP for Mail ([RFC 8621](https://datatracker.ietf.org/doc/html/rfc8621))
|
||||||
- JMAP over WebSocket ([RFC 8887](https://datatracker.ietf.org/doc/html/rfc8887)).
|
- JMAP over WebSocket ([RFC 8887](https://datatracker.ietf.org/doc/html/rfc8887)).
|
||||||
|
- JMAP for Sieve Scripts ([DRAFT-SIEVE-12](https://www.ietf.org/archive/id/draft-ietf-jmap-sieve-12.html)).
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::{
|
||||||
mailbox::Mailbox,
|
mailbox::Mailbox,
|
||||||
principal::Principal,
|
principal::Principal,
|
||||||
push_subscription::PushSubscription,
|
push_subscription::PushSubscription,
|
||||||
|
sieve::{validate::SieveScriptValidateRequest, SieveScript},
|
||||||
thread::Thread,
|
thread::Thread,
|
||||||
vacation_response::VacationResponse,
|
vacation_response::VacationResponse,
|
||||||
Error, Method, Set, URI,
|
Error, Method, Set, URI,
|
||||||
|
@ -92,6 +93,10 @@ pub enum Arguments {
|
||||||
EmailSubmissionSet(SetRequest<EmailSubmission<Set>>),
|
EmailSubmissionSet(SetRequest<EmailSubmission<Set>>),
|
||||||
VacationResponseGet(GetRequest<VacationResponse<Set>>),
|
VacationResponseGet(GetRequest<VacationResponse<Set>>),
|
||||||
VacationResponseSet(SetRequest<VacationResponse<Set>>),
|
VacationResponseSet(SetRequest<VacationResponse<Set>>),
|
||||||
|
SieveScriptGet(GetRequest<SieveScript<Set>>),
|
||||||
|
SieveScriptQuery(QueryRequest<SieveScript<Set>>),
|
||||||
|
SieveScriptValidate(SieveScriptValidateRequest),
|
||||||
|
SieveScriptSet(SetRequest<SieveScript<Set>>),
|
||||||
PrincipalGet(GetRequest<Principal<Set>>),
|
PrincipalGet(GetRequest<Principal<Set>>),
|
||||||
PrincipalQuery(QueryRequest<Principal<Set>>),
|
PrincipalQuery(QueryRequest<Principal<Set>>),
|
||||||
PrincipalQueryChanges(QueryChangesRequest<Principal<Set>>),
|
PrincipalQueryChanges(QueryChangesRequest<Principal<Set>>),
|
||||||
|
@ -202,6 +207,22 @@ impl Arguments {
|
||||||
Arguments::VacationResponseSet(SetRequest::new(params))
|
Arguments::VacationResponseSet(SetRequest::new(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_get(params: RequestParams) -> Self {
|
||||||
|
Arguments::SieveScriptGet(GetRequest::new(params))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_query(params: RequestParams) -> Self {
|
||||||
|
Arguments::SieveScriptQuery(QueryRequest::new(params))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_validate(params: RequestParams, blob_id: impl Into<String>) -> Self {
|
||||||
|
Arguments::SieveScriptValidate(SieveScriptValidateRequest::new(params, blob_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_set(params: RequestParams) -> Self {
|
||||||
|
Arguments::SieveScriptSet(SetRequest::new(params))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn principal_get(params: RequestParams) -> Self {
|
pub fn principal_get(params: RequestParams) -> Self {
|
||||||
Arguments::PrincipalGet(GetRequest::new(params))
|
Arguments::PrincipalGet(GetRequest::new(params))
|
||||||
}
|
}
|
||||||
|
@ -395,6 +416,34 @@ impl Arguments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_get_mut(&mut self) -> &mut GetRequest<SieveScript<Set>> {
|
||||||
|
match self {
|
||||||
|
Arguments::SieveScriptGet(ref mut r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_query_mut(&mut self) -> &mut QueryRequest<SieveScript<Set>> {
|
||||||
|
match self {
|
||||||
|
Arguments::SieveScriptQuery(ref mut r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_validate_mut(&mut self) -> &mut SieveScriptValidateRequest {
|
||||||
|
match self {
|
||||||
|
Arguments::SieveScriptValidate(ref mut r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_set_mut(&mut self) -> &mut SetRequest<SieveScript<Set>> {
|
||||||
|
match self {
|
||||||
|
Arguments::SieveScriptSet(ref mut r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn principal_get_mut(&mut self) -> &mut GetRequest<Principal<Set>> {
|
pub fn principal_get_mut(&mut self) -> &mut GetRequest<Principal<Set>> {
|
||||||
match self {
|
match self {
|
||||||
Arguments::PrincipalGet(ref mut r) => r,
|
Arguments::PrincipalGet(ref mut r) => r,
|
||||||
|
|
|
@ -24,6 +24,7 @@ use crate::{
|
||||||
mailbox::Mailbox,
|
mailbox::Mailbox,
|
||||||
principal::Principal,
|
principal::Principal,
|
||||||
push_subscription::PushSubscription,
|
push_subscription::PushSubscription,
|
||||||
|
sieve::{validate::SieveScriptValidateResponse, SieveScript},
|
||||||
thread::Thread,
|
thread::Thread,
|
||||||
vacation_response::VacationResponse,
|
vacation_response::VacationResponse,
|
||||||
Get, Method,
|
Get, Method,
|
||||||
|
@ -132,6 +133,8 @@ pub type EmailSubmissionGetResponse = GetResponse<EmailSubmission<Get>>;
|
||||||
pub type EmailSubmissionChangesResponse = ChangesResponse<EmailSubmission<Get>>;
|
pub type EmailSubmissionChangesResponse = ChangesResponse<EmailSubmission<Get>>;
|
||||||
pub type VacationResponseGetResponse = GetResponse<VacationResponse<Get>>;
|
pub type VacationResponseGetResponse = GetResponse<VacationResponse<Get>>;
|
||||||
pub type VacationResponseSetResponse = SetResponse<VacationResponse<Get>>;
|
pub type VacationResponseSetResponse = SetResponse<VacationResponse<Get>>;
|
||||||
|
pub type SieveScriptGetResponse = GetResponse<SieveScript<Get>>;
|
||||||
|
pub type SieveScriptSetResponse = SetResponse<SieveScript<Get>>;
|
||||||
pub type PrincipalChangesResponse = ChangesResponse<Principal<Get>>;
|
pub type PrincipalChangesResponse = ChangesResponse<Principal<Get>>;
|
||||||
pub type PrincipalSetResponse = SetResponse<Principal<Get>>;
|
pub type PrincipalSetResponse = SetResponse<Principal<Get>>;
|
||||||
pub type PrincipalGetResponse = GetResponse<Principal<Get>>;
|
pub type PrincipalGetResponse = GetResponse<Principal<Get>>;
|
||||||
|
@ -173,6 +176,10 @@ pub enum MethodResponse {
|
||||||
SetEmailSubmission(EmailSubmissionSetResponse),
|
SetEmailSubmission(EmailSubmissionSetResponse),
|
||||||
GetVacationResponse(VacationResponseGetResponse),
|
GetVacationResponse(VacationResponseGetResponse),
|
||||||
SetVacationResponse(VacationResponseSetResponse),
|
SetVacationResponse(VacationResponseSetResponse),
|
||||||
|
GetSieveScript(SieveScriptGetResponse),
|
||||||
|
QuerySieveScript(QueryResponse),
|
||||||
|
SetSieveScript(SieveScriptSetResponse),
|
||||||
|
ValidateSieveScript(SieveScriptValidateResponse),
|
||||||
|
|
||||||
GetPrincipal(PrincipalGetResponse),
|
GetPrincipal(PrincipalGetResponse),
|
||||||
ChangesPrincipal(PrincipalChangesResponse),
|
ChangesPrincipal(PrincipalChangesResponse),
|
||||||
|
@ -257,6 +264,16 @@ impl TaggedMethodResponse {
|
||||||
MethodResponse::SetVacationResponse(_),
|
MethodResponse::SetVacationResponse(_),
|
||||||
Method::SetVacationResponse
|
Method::SetVacationResponse
|
||||||
)
|
)
|
||||||
|
| (MethodResponse::GetSieveScript(_), Method::GetSieveScript)
|
||||||
|
| (
|
||||||
|
MethodResponse::ValidateSieveScript(_),
|
||||||
|
Method::ValidateSieveScript
|
||||||
|
)
|
||||||
|
| (
|
||||||
|
MethodResponse::QuerySieveScript(_),
|
||||||
|
Method::QuerySieveScript
|
||||||
|
)
|
||||||
|
| (MethodResponse::SetSieveScript(_), Method::SetSieveScript)
|
||||||
| (MethodResponse::GetPrincipal(_), Method::GetPrincipal)
|
| (MethodResponse::GetPrincipal(_), Method::GetPrincipal)
|
||||||
| (
|
| (
|
||||||
MethodResponse::ChangesPrincipal(_),
|
MethodResponse::ChangesPrincipal(_),
|
||||||
|
@ -509,6 +526,38 @@ impl TaggedMethodResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_get_sieve_script(self) -> crate::Result<SieveScriptGetResponse> {
|
||||||
|
match self.response {
|
||||||
|
MethodResponse::GetSieveScript(response) => Ok(response),
|
||||||
|
MethodResponse::Error(err) => Err(err.into()),
|
||||||
|
_ => Err("Response type mismatch".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_validate_sieve_script(self) -> crate::Result<SieveScriptValidateResponse> {
|
||||||
|
match self.response {
|
||||||
|
MethodResponse::ValidateSieveScript(response) => Ok(response),
|
||||||
|
MethodResponse::Error(err) => Err(err.into()),
|
||||||
|
_ => Err("Response type mismatch".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_set_sieve_script(self) -> crate::Result<SieveScriptSetResponse> {
|
||||||
|
match self.response {
|
||||||
|
MethodResponse::SetSieveScript(response) => Ok(response),
|
||||||
|
MethodResponse::Error(err) => Err(err.into()),
|
||||||
|
_ => Err("Response type mismatch".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_query_sieve_script(self) -> crate::Result<QueryResponse> {
|
||||||
|
match self.response {
|
||||||
|
MethodResponse::QuerySieveScript(response) => Ok(response),
|
||||||
|
MethodResponse::Error(err) => Err(err.into()),
|
||||||
|
_ => Err("Response type mismatch".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unwrap_get_principal(self) -> crate::Result<PrincipalGetResponse> {
|
pub fn unwrap_get_principal(self) -> crate::Result<PrincipalGetResponse> {
|
||||||
match self.response {
|
match self.response {
|
||||||
MethodResponse::GetPrincipal(response) => Ok(response),
|
MethodResponse::GetPrincipal(response) => Ok(response),
|
||||||
|
@ -708,6 +757,22 @@ impl<'de> Visitor<'de> for TaggedMethodResponseVisitor {
|
||||||
seq.next_element()?
|
seq.next_element()?
|
||||||
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
||||||
),
|
),
|
||||||
|
Method::GetSieveScript => MethodResponse::GetSieveScript(
|
||||||
|
seq.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
||||||
|
),
|
||||||
|
Method::SetSieveScript => MethodResponse::SetSieveScript(
|
||||||
|
seq.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
||||||
|
),
|
||||||
|
Method::QuerySieveScript => MethodResponse::QuerySieveScript(
|
||||||
|
seq.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
||||||
|
),
|
||||||
|
Method::ValidateSieveScript => MethodResponse::ValidateSieveScript(
|
||||||
|
seq.next_element()?
|
||||||
|
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
||||||
|
),
|
||||||
Method::GetPrincipal => MethodResponse::GetPrincipal(
|
Method::GetPrincipal => MethodResponse::GetPrincipal(
|
||||||
seq.next_element()?
|
seq.next_element()?
|
||||||
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
.ok_or_else(|| serde::de::Error::custom("Expected a method response"))?,
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub enum Capabilities {
|
||||||
Mail(MailCapabilities),
|
Mail(MailCapabilities),
|
||||||
Submission(SubmissionCapabilities),
|
Submission(SubmissionCapabilities),
|
||||||
WebSocket(WebSocketCapabilities),
|
WebSocket(WebSocketCapabilities),
|
||||||
|
Sieve(SieveCapabilities),
|
||||||
Empty(EmptyCapabilities),
|
Empty(EmptyCapabilities),
|
||||||
Other(serde_json::Value),
|
Other(serde_json::Value),
|
||||||
}
|
}
|
||||||
|
@ -107,6 +108,24 @@ pub struct WebSocketCapabilities {
|
||||||
supports_push: bool,
|
supports_push: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SieveCapabilities {
|
||||||
|
#[serde(rename(serialize = "maxSizeScriptName"))]
|
||||||
|
max_script_name: Option<usize>,
|
||||||
|
#[serde(rename(serialize = "maxSizeScript"))]
|
||||||
|
max_script_size: Option<usize>,
|
||||||
|
#[serde(rename(serialize = "maxNumberScripts"))]
|
||||||
|
max_scripts: Option<usize>,
|
||||||
|
#[serde(rename(serialize = "maxNumberRedirects"))]
|
||||||
|
max_redirects: Option<usize>,
|
||||||
|
#[serde(rename(serialize = "sieveExtensions"))]
|
||||||
|
extensions: Vec<String>,
|
||||||
|
#[serde(rename(serialize = "notificationMethods"))]
|
||||||
|
notification_methods: Option<Vec<String>>,
|
||||||
|
#[serde(rename(serialize = "externalLists"))]
|
||||||
|
ext_lists: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmptyCapabilities {}
|
pub struct EmptyCapabilities {}
|
||||||
|
|
||||||
|
@ -159,6 +178,15 @@ impl Session {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sieve_capabilities(&self) -> Option<&SieveCapabilities> {
|
||||||
|
self.capabilities
|
||||||
|
.get(URI::Sieve.as_ref())
|
||||||
|
.and_then(|v| match v {
|
||||||
|
Capabilities::Sieve(capabilities) => Some(capabilities),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn accounts(&self) -> impl Iterator<Item = &String> {
|
pub fn accounts(&self) -> impl Iterator<Item = &String> {
|
||||||
self.accounts.keys()
|
self.accounts.keys()
|
||||||
}
|
}
|
||||||
|
@ -262,6 +290,36 @@ impl WebSocketCapabilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SieveCapabilities {
|
||||||
|
pub fn max_script_name_size(&self) -> usize {
|
||||||
|
self.max_script_name.unwrap_or(512)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_script_size(&self) -> Option<usize> {
|
||||||
|
self.max_script_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_number_scripts(&self) -> Option<usize> {
|
||||||
|
self.max_scripts
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_number_redirects(&self) -> Option<usize> {
|
||||||
|
self.max_redirects
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_extensions(&self) -> &[String] {
|
||||||
|
&self.extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notification_methods(&self) -> Option<&[String]> {
|
||||||
|
self.notification_methods.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn external_lists(&self) -> Option<&[String]> {
|
||||||
|
self.ext_lists.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait URLParser: Sized {
|
pub trait URLParser: Sized {
|
||||||
fn parse(value: &str) -> Option<Self>;
|
fn parse(value: &str) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,12 @@ pub enum SetErrorType {
|
||||||
ForbiddenToSend,
|
ForbiddenToSend,
|
||||||
#[serde(rename = "cannotUnsend")]
|
#[serde(rename = "cannotUnsend")]
|
||||||
CannotUnsend,
|
CannotUnsend,
|
||||||
|
#[serde(rename = "alreadyExists")]
|
||||||
|
AlreadyExists,
|
||||||
|
#[serde(rename = "invalidScript")]
|
||||||
|
InvalidScript,
|
||||||
|
#[serde(rename = "scriptIsActive")]
|
||||||
|
ScriptIsActive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O: SetObject> SetRequest<O> {
|
impl<O: SetObject> SetRequest<O> {
|
||||||
|
@ -325,6 +331,24 @@ impl<O: SetObject> SetResponse<O> {
|
||||||
pub fn has_destroyed(&self) -> bool {
|
pub fn has_destroyed(&self) -> bool {
|
||||||
self.destroyed.as_ref().map_or(false, |m| !m.is_empty())
|
self.destroyed.as_ref().map_or(false, |m| !m.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_update_errors(&self) -> crate::Result<()> {
|
||||||
|
if let Some(errors) = &self.not_updated {
|
||||||
|
if let Some(err) = errors.values().next() {
|
||||||
|
return Err(err.to_string_error().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_create_errors(&self) -> crate::Result<()> {
|
||||||
|
if let Some(errors) = &self.not_created {
|
||||||
|
if let Some(err) = errors.values().next() {
|
||||||
|
return Err(err.to_string_error().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: Display> SetError<U> {
|
impl<U: Display> SetError<U> {
|
||||||
|
@ -376,28 +400,31 @@ impl<U: Display> Display for SetError<U> {
|
||||||
impl Display for SetErrorType {
|
impl Display for SetErrorType {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
SetErrorType::Forbidden => write!(f, "Forbidden"),
|
SetErrorType::Forbidden => write!(f, "forbidden"),
|
||||||
SetErrorType::OverQuota => write!(f, "OverQuota"),
|
SetErrorType::OverQuota => write!(f, "overQuota"),
|
||||||
SetErrorType::TooLarge => write!(f, "TooLarge"),
|
SetErrorType::TooLarge => write!(f, "tooLarge"),
|
||||||
SetErrorType::RateLimit => write!(f, "RateLimit"),
|
SetErrorType::RateLimit => write!(f, "rateLimit"),
|
||||||
SetErrorType::NotFound => write!(f, "NotFound"),
|
SetErrorType::NotFound => write!(f, "notFound"),
|
||||||
SetErrorType::InvalidPatch => write!(f, "InvalidPatch"),
|
SetErrorType::InvalidPatch => write!(f, "invalidPatch"),
|
||||||
SetErrorType::WillDestroy => write!(f, "WillDestroy"),
|
SetErrorType::WillDestroy => write!(f, "willDestroy"),
|
||||||
SetErrorType::InvalidProperties => write!(f, "InvalidProperties"),
|
SetErrorType::InvalidProperties => write!(f, "invalidProperties"),
|
||||||
SetErrorType::Singleton => write!(f, "Singleton"),
|
SetErrorType::Singleton => write!(f, "singleton"),
|
||||||
SetErrorType::MailboxHasChild => write!(f, "MailboxHasChild"),
|
SetErrorType::MailboxHasChild => write!(f, "mailboxHasChild"),
|
||||||
SetErrorType::MailboxHasEmail => write!(f, "MailboxHasEmail"),
|
SetErrorType::MailboxHasEmail => write!(f, "mailboxHasEmail"),
|
||||||
SetErrorType::BlobNotFound => write!(f, "BlobNotFound"),
|
SetErrorType::BlobNotFound => write!(f, "blobNotFound"),
|
||||||
SetErrorType::TooManyKeywords => write!(f, "TooManyKeywords"),
|
SetErrorType::TooManyKeywords => write!(f, "tooManyKeywords"),
|
||||||
SetErrorType::TooManyMailboxes => write!(f, "TooManyMailboxes"),
|
SetErrorType::TooManyMailboxes => write!(f, "tooManyMailboxes"),
|
||||||
SetErrorType::ForbiddenFrom => write!(f, "ForbiddenFrom"),
|
SetErrorType::ForbiddenFrom => write!(f, "forbiddenFrom"),
|
||||||
SetErrorType::InvalidEmail => write!(f, "InvalidEmail"),
|
SetErrorType::InvalidEmail => write!(f, "invalidEmail"),
|
||||||
SetErrorType::TooManyRecipients => write!(f, "TooManyRecipients"),
|
SetErrorType::TooManyRecipients => write!(f, "tooManyRecipients"),
|
||||||
SetErrorType::NoRecipients => write!(f, "NoRecipients"),
|
SetErrorType::NoRecipients => write!(f, "noRecipients"),
|
||||||
SetErrorType::InvalidRecipients => write!(f, "InvalidRecipients"),
|
SetErrorType::InvalidRecipients => write!(f, "invalidRecipients"),
|
||||||
SetErrorType::ForbiddenMailFrom => write!(f, "ForbiddenMailFrom"),
|
SetErrorType::ForbiddenMailFrom => write!(f, "forbiddenMailFrom"),
|
||||||
SetErrorType::ForbiddenToSend => write!(f, "ForbiddenToSend"),
|
SetErrorType::ForbiddenToSend => write!(f, "forbiddenToSend"),
|
||||||
SetErrorType::CannotUnsend => write!(f, "CannotUnsend"),
|
SetErrorType::CannotUnsend => write!(f, "cannotUnsend"),
|
||||||
|
SetErrorType::AlreadyExists => write!(f, "alreadyExists"),
|
||||||
|
SetErrorType::InvalidScript => write!(f, "invalidScript"),
|
||||||
|
SetErrorType::ScriptIsActive => write!(f, "scriptIsActive"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -21,6 +21,7 @@
|
||||||
//! - JMAP Core ([RFC 8620](https://datatracker.ietf.org/doc/html/rfc8620))
|
//! - JMAP Core ([RFC 8620](https://datatracker.ietf.org/doc/html/rfc8620))
|
||||||
//! - JMAP for Mail ([RFC 8621](https://datatracker.ietf.org/doc/html/rfc8621))
|
//! - JMAP for Mail ([RFC 8621](https://datatracker.ietf.org/doc/html/rfc8621))
|
||||||
//! - JMAP over WebSocket ([RFC 8887](https://datatracker.ietf.org/doc/html/rfc8887)).
|
//! - JMAP over WebSocket ([RFC 8887](https://datatracker.ietf.org/doc/html/rfc8887)).
|
||||||
|
//! - JMAP for Sieve Scripts ([DRAFT-SIEVE-12](https://www.ietf.org/archive/id/draft-ietf-jmap-sieve-12.html)).
|
||||||
//!
|
//!
|
||||||
//! Features:
|
//! Features:
|
||||||
//!
|
//!
|
||||||
|
@ -191,6 +192,7 @@ pub mod identity;
|
||||||
pub mod mailbox;
|
pub mod mailbox;
|
||||||
pub mod principal;
|
pub mod principal;
|
||||||
pub mod push_subscription;
|
pub mod push_subscription;
|
||||||
|
pub mod sieve;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
pub mod vacation_response;
|
pub mod vacation_response;
|
||||||
|
|
||||||
|
@ -220,6 +222,8 @@ pub enum URI {
|
||||||
Calendars,
|
Calendars,
|
||||||
#[serde(rename = "urn:ietf:params:jmap:websocket")]
|
#[serde(rename = "urn:ietf:params:jmap:websocket")]
|
||||||
WebSocket,
|
WebSocket,
|
||||||
|
#[serde(rename = "urn:ietf:params:jmap:sieve")]
|
||||||
|
Sieve,
|
||||||
#[serde(rename = "urn:ietf:params:jmap:principals")]
|
#[serde(rename = "urn:ietf:params:jmap:principals")]
|
||||||
Principals,
|
Principals,
|
||||||
#[serde(rename = "urn:ietf:params:jmap:principals:owner")]
|
#[serde(rename = "urn:ietf:params:jmap:principals:owner")]
|
||||||
|
@ -236,6 +240,7 @@ impl AsRef<str> for URI {
|
||||||
URI::Contacts => "urn:ietf:params:jmap:contacts",
|
URI::Contacts => "urn:ietf:params:jmap:contacts",
|
||||||
URI::Calendars => "urn:ietf:params:jmap:calendars",
|
URI::Calendars => "urn:ietf:params:jmap:calendars",
|
||||||
URI::WebSocket => "urn:ietf:params:jmap:websocket",
|
URI::WebSocket => "urn:ietf:params:jmap:websocket",
|
||||||
|
URI::Sieve => "urn:ietf:params:jmap:sieve",
|
||||||
URI::Principals => "urn:ietf:params:jmap:principals",
|
URI::Principals => "urn:ietf:params:jmap:principals",
|
||||||
URI::PrincipalsOwner => "urn:ietf:params:jmap:principals:owner",
|
URI::PrincipalsOwner => "urn:ietf:params:jmap:principals:owner",
|
||||||
}
|
}
|
||||||
|
@ -304,6 +309,14 @@ pub enum Method {
|
||||||
GetVacationResponse,
|
GetVacationResponse,
|
||||||
#[serde(rename = "VacationResponse/set")]
|
#[serde(rename = "VacationResponse/set")]
|
||||||
SetVacationResponse,
|
SetVacationResponse,
|
||||||
|
#[serde(rename = "SieveScript/get")]
|
||||||
|
GetSieveScript,
|
||||||
|
#[serde(rename = "SieveScript/set")]
|
||||||
|
SetSieveScript,
|
||||||
|
#[serde(rename = "SieveScript/query")]
|
||||||
|
QuerySieveScript,
|
||||||
|
#[serde(rename = "SieveScript/validate")]
|
||||||
|
ValidateSieveScript,
|
||||||
#[serde(rename = "Principal/get")]
|
#[serde(rename = "Principal/get")]
|
||||||
GetPrincipal,
|
GetPrincipal,
|
||||||
#[serde(rename = "Principal/changes")]
|
#[serde(rename = "Principal/changes")]
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright Stalwart Labs Ltd. See the COPYING
|
||||||
|
* file at the top-level directory of this distribution.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{core::get::GetObject, Get, Set};
|
||||||
|
|
||||||
|
use super::SieveScript;
|
||||||
|
|
||||||
|
impl SieveScript<Get> {
|
||||||
|
pub fn id(&self) -> Option<&str> {
|
||||||
|
self.id.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_id(&mut self) -> String {
|
||||||
|
self.id.take().unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blob_id(&self) -> Option<&str> {
|
||||||
|
self.blob_id.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_active(&self) -> bool {
|
||||||
|
self.is_active.unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetObject for SieveScript<Set> {
|
||||||
|
type GetArguments = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetObject for SieveScript<Get> {
|
||||||
|
type GetArguments = ();
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* Copyright Stalwart Labs Ltd. See the COPYING
|
||||||
|
* file at the top-level directory of this distribution.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
client::Client,
|
||||||
|
core::{
|
||||||
|
get::GetRequest,
|
||||||
|
query::{Comparator, Filter, QueryRequest, QueryResponse},
|
||||||
|
request::{Arguments, Request},
|
||||||
|
response::{SieveScriptGetResponse, SieveScriptSetResponse},
|
||||||
|
set::{SetObject, SetRequest},
|
||||||
|
},
|
||||||
|
Method, Set, URI,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
validate::{SieveScriptValidateRequest, SieveScriptValidateResponse},
|
||||||
|
Property, SieveScript,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn sieve_script_create(
|
||||||
|
&self,
|
||||||
|
name: impl Into<String>,
|
||||||
|
script: impl Into<Vec<u8>>,
|
||||||
|
activate: bool,
|
||||||
|
) -> crate::Result<SieveScript> {
|
||||||
|
let blob_id = self.upload(None, script.into(), None).await?.take_blob_id();
|
||||||
|
let mut request = self.build();
|
||||||
|
let set_request = request.set_sieve_script();
|
||||||
|
let id = set_request
|
||||||
|
.create()
|
||||||
|
.name(name)
|
||||||
|
.blob_id(blob_id)
|
||||||
|
.create_id()
|
||||||
|
.unwrap();
|
||||||
|
if activate {
|
||||||
|
set_request
|
||||||
|
.arguments()
|
||||||
|
.on_success_activate_script(id.clone());
|
||||||
|
}
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()
|
||||||
|
.await?
|
||||||
|
.created(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_replace(
|
||||||
|
&self,
|
||||||
|
id: &str,
|
||||||
|
script: impl Into<Vec<u8>>,
|
||||||
|
activate: bool,
|
||||||
|
) -> crate::Result<Option<SieveScript>> {
|
||||||
|
let blob_id = self.upload(None, script.into(), None).await?.take_blob_id();
|
||||||
|
let mut request = self.build();
|
||||||
|
let set_request = request.set_sieve_script();
|
||||||
|
set_request.update(id).blob_id(blob_id);
|
||||||
|
if activate {
|
||||||
|
set_request.arguments().on_success_activate_script_id(id);
|
||||||
|
}
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()
|
||||||
|
.await?
|
||||||
|
.updated(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_rename(
|
||||||
|
&self,
|
||||||
|
id: &str,
|
||||||
|
name: impl Into<String>,
|
||||||
|
activate: bool,
|
||||||
|
) -> crate::Result<Option<SieveScript>> {
|
||||||
|
let mut request = self.build();
|
||||||
|
let set_request = request.set_sieve_script();
|
||||||
|
set_request.update(id).name(name);
|
||||||
|
if activate {
|
||||||
|
set_request.arguments().on_success_activate_script_id(id);
|
||||||
|
}
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()
|
||||||
|
.await?
|
||||||
|
.updated(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_activate(&self, id: &str) -> crate::Result<()> {
|
||||||
|
let mut request = self.build();
|
||||||
|
request
|
||||||
|
.set_sieve_script()
|
||||||
|
.arguments()
|
||||||
|
.on_success_activate_script_id(id);
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()
|
||||||
|
.await?
|
||||||
|
.unwrap_update_errors()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_deactivate(&self) -> crate::Result<()> {
|
||||||
|
let mut request = self.build();
|
||||||
|
request
|
||||||
|
.set_sieve_script()
|
||||||
|
.arguments()
|
||||||
|
.on_success_deactivate_scripts();
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()
|
||||||
|
.await?
|
||||||
|
.unwrap_update_errors()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_destroy(&self, id: &str) -> crate::Result<()> {
|
||||||
|
let mut request = self.build();
|
||||||
|
request.set_sieve_script().destroy([id]);
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()
|
||||||
|
.await?
|
||||||
|
.destroyed(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_get(
|
||||||
|
&self,
|
||||||
|
id: &str,
|
||||||
|
properties: Option<impl IntoIterator<Item = Property>>,
|
||||||
|
) -> crate::Result<Option<SieveScript>> {
|
||||||
|
let mut request = self.build();
|
||||||
|
let get_request = request.get_sieve_script().ids([id]);
|
||||||
|
if let Some(properties) = properties {
|
||||||
|
get_request.properties(properties.into_iter());
|
||||||
|
}
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptGetResponse>()
|
||||||
|
.await
|
||||||
|
.map(|mut r| r.take_list().pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_query(
|
||||||
|
&self,
|
||||||
|
filter: Option<impl Into<Filter<super::query::Filter>>>,
|
||||||
|
sort: Option<impl IntoIterator<Item = Comparator<super::query::Comparator>>>,
|
||||||
|
) -> crate::Result<QueryResponse> {
|
||||||
|
let mut request = self.build();
|
||||||
|
let query_request = request.query_sieve_script();
|
||||||
|
if let Some(filter) = filter {
|
||||||
|
query_request.filter(filter);
|
||||||
|
}
|
||||||
|
if let Some(sort) = sort {
|
||||||
|
query_request.sort(sort.into_iter());
|
||||||
|
}
|
||||||
|
request.send_single::<QueryResponse>().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn sieve_script_validate(&self, script: impl Into<Vec<u8>>) -> crate::Result<()> {
|
||||||
|
let blob_id = self.upload(None, script.into(), None).await?.take_blob_id();
|
||||||
|
let mut request = self.build();
|
||||||
|
request.validate_sieve_script(blob_id);
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptValidateResponse>()
|
||||||
|
.await?
|
||||||
|
.unwrap_error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request<'_> {
|
||||||
|
pub fn get_sieve_script(&mut self) -> &mut GetRequest<SieveScript<Set>> {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::GetSieveScript,
|
||||||
|
Arguments::sieve_script_get(self.params(Method::GetSieveScript)),
|
||||||
|
)
|
||||||
|
.sieve_script_get_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_get_sieve_script(self) -> crate::Result<SieveScriptGetResponse> {
|
||||||
|
self.send_single().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_sieve_script(&mut self) -> &mut SetRequest<SieveScript<Set>> {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::SetSieveScript,
|
||||||
|
Arguments::sieve_script_set(self.params(Method::SetSieveScript)),
|
||||||
|
)
|
||||||
|
.sieve_script_set_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_set_sieve_script(self) -> crate::Result<SieveScriptSetResponse> {
|
||||||
|
self.send_single().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_sieve_script(
|
||||||
|
&mut self,
|
||||||
|
blob_id: impl Into<String>,
|
||||||
|
) -> &mut SieveScriptValidateRequest {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::ValidateSieveScript,
|
||||||
|
Arguments::sieve_script_validate(self.params(Method::ValidateSieveScript), blob_id),
|
||||||
|
)
|
||||||
|
.sieve_script_validate_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_validate_sieve_script(self) -> crate::Result<SieveScriptValidateResponse> {
|
||||||
|
self.send_single().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn query_sieve_script(&mut self) -> &mut QueryRequest<SieveScript<Set>> {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::QuerySieveScript,
|
||||||
|
Arguments::sieve_script_query(self.params(Method::QuerySieveScript)),
|
||||||
|
)
|
||||||
|
.sieve_script_query_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_query_sieve_script(self) -> crate::Result<QueryResponse> {
|
||||||
|
self.send_single().await
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
* Copyright Stalwart Labs Ltd. See the COPYING
|
||||||
|
* file at the top-level directory of this distribution.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
client::Client,
|
||||||
|
core::{
|
||||||
|
get::GetRequest,
|
||||||
|
query::{Comparator, Filter, QueryRequest, QueryResponse},
|
||||||
|
request::{Arguments, Request},
|
||||||
|
response::{SieveScriptGetResponse, SieveScriptSetResponse},
|
||||||
|
set::{SetObject, SetRequest},
|
||||||
|
},
|
||||||
|
Method, Set, URI,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
validate::{SieveScriptValidateRequest, SieveScriptValidateResponse},
|
||||||
|
Property, SieveScript,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn sieve_script_create(
|
||||||
|
&self,
|
||||||
|
name: impl Into<String>,
|
||||||
|
script: impl Into<Vec<u8>>,
|
||||||
|
activate: bool,
|
||||||
|
) -> crate::Result<SieveScript> {
|
||||||
|
let blob_id = self.upload(None, script.into(), None)?.take_blob_id();
|
||||||
|
let mut request = self.build();
|
||||||
|
let set_request = request.set_sieve_script();
|
||||||
|
let id = set_request
|
||||||
|
.create()
|
||||||
|
.name(name)
|
||||||
|
.blob_id(blob_id)
|
||||||
|
.create_id()
|
||||||
|
.unwrap();
|
||||||
|
if activate {
|
||||||
|
set_request
|
||||||
|
.arguments()
|
||||||
|
.on_success_activate_script(id.clone());
|
||||||
|
}
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()?
|
||||||
|
.created(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_replace(
|
||||||
|
&self,
|
||||||
|
id: &str,
|
||||||
|
script: impl Into<Vec<u8>>,
|
||||||
|
activate: bool,
|
||||||
|
) -> crate::Result<Option<SieveScript>> {
|
||||||
|
let blob_id = self.upload(None, script.into(), None)?.take_blob_id();
|
||||||
|
let mut request = self.build();
|
||||||
|
let set_request = request.set_sieve_script();
|
||||||
|
set_request.update(id).blob_id(blob_id);
|
||||||
|
if activate {
|
||||||
|
set_request.arguments().on_success_activate_script_id(id);
|
||||||
|
}
|
||||||
|
request.send_single::<SieveScriptSetResponse>()?.updated(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_rename(
|
||||||
|
&self,
|
||||||
|
id: &str,
|
||||||
|
name: impl Into<String>,
|
||||||
|
activate: bool,
|
||||||
|
) -> crate::Result<Option<SieveScript>> {
|
||||||
|
let mut request = self.build();
|
||||||
|
let set_request = request.set_sieve_script();
|
||||||
|
set_request.update(id).name(name);
|
||||||
|
if activate {
|
||||||
|
set_request.arguments().on_success_activate_script_id(id);
|
||||||
|
}
|
||||||
|
request.send_single::<SieveScriptSetResponse>()?.updated(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_activate(&self, id: &str) -> crate::Result<()> {
|
||||||
|
let mut request = self.build();
|
||||||
|
request
|
||||||
|
.set_sieve_script()
|
||||||
|
.arguments()
|
||||||
|
.on_success_activate_script_id(id);
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()?
|
||||||
|
.unwrap_update_errors()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_deactivate(&self) -> crate::Result<()> {
|
||||||
|
let mut request = self.build();
|
||||||
|
request
|
||||||
|
.set_sieve_script()
|
||||||
|
.arguments()
|
||||||
|
.on_success_deactivate_scripts();
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()?
|
||||||
|
.unwrap_update_errors()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_destroy(&self, id: &str) -> crate::Result<()> {
|
||||||
|
let mut request = self.build();
|
||||||
|
request.set_sieve_script().destroy([id]);
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptSetResponse>()?
|
||||||
|
.destroyed(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_get(
|
||||||
|
&self,
|
||||||
|
id: &str,
|
||||||
|
properties: Option<impl IntoIterator<Item = Property>>,
|
||||||
|
) -> crate::Result<Option<SieveScript>> {
|
||||||
|
let mut request = self.build();
|
||||||
|
let get_request = request.get_sieve_script().ids([id]);
|
||||||
|
if let Some(properties) = properties {
|
||||||
|
get_request.properties(properties.into_iter());
|
||||||
|
}
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptGetResponse>()
|
||||||
|
.map(|mut r| r.take_list().pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_query(
|
||||||
|
&self,
|
||||||
|
filter: Option<impl Into<Filter<super::query::Filter>>>,
|
||||||
|
sort: Option<impl IntoIterator<Item = Comparator<super::query::Comparator>>>,
|
||||||
|
) -> crate::Result<QueryResponse> {
|
||||||
|
let mut request = self.build();
|
||||||
|
let query_request = request.query_sieve_script();
|
||||||
|
if let Some(filter) = filter {
|
||||||
|
query_request.filter(filter);
|
||||||
|
}
|
||||||
|
if let Some(sort) = sort {
|
||||||
|
query_request.sort(sort.into_iter());
|
||||||
|
}
|
||||||
|
request.send_single::<QueryResponse>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sieve_script_validate(&self, script: impl Into<Vec<u8>>) -> crate::Result<()> {
|
||||||
|
let blob_id = self.upload(None, script.into(), None)?.take_blob_id();
|
||||||
|
let mut request = self.build();
|
||||||
|
request.validate_sieve_script(blob_id);
|
||||||
|
request
|
||||||
|
.send_single::<SieveScriptValidateResponse>()?
|
||||||
|
.unwrap_error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request<'_> {
|
||||||
|
pub fn get_sieve_script(&mut self) -> &mut GetRequest<SieveScript<Set>> {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::GetSieveScript,
|
||||||
|
Arguments::sieve_script_get(self.params(Method::GetSieveScript)),
|
||||||
|
)
|
||||||
|
.sieve_script_get_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_get_sieve_script(self) -> crate::Result<SieveScriptGetResponse> {
|
||||||
|
self.send_single()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_sieve_script(&mut self) -> &mut SetRequest<SieveScript<Set>> {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::SetSieveScript,
|
||||||
|
Arguments::sieve_script_set(self.params(Method::SetSieveScript)),
|
||||||
|
)
|
||||||
|
.sieve_script_set_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_set_sieve_script(self) -> crate::Result<SieveScriptSetResponse> {
|
||||||
|
self.send_single()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_sieve_script(
|
||||||
|
&mut self,
|
||||||
|
blob_id: impl Into<String>,
|
||||||
|
) -> &mut SieveScriptValidateRequest {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::ValidateSieveScript,
|
||||||
|
Arguments::sieve_script_validate(self.params(Method::ValidateSieveScript), blob_id),
|
||||||
|
)
|
||||||
|
.sieve_script_validate_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_validate_sieve_script(self) -> crate::Result<SieveScriptValidateResponse> {
|
||||||
|
self.send_single()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn query_sieve_script(&mut self) -> &mut QueryRequest<SieveScript<Set>> {
|
||||||
|
self.add_capability(URI::Sieve);
|
||||||
|
self.add_method_call(
|
||||||
|
Method::QuerySieveScript,
|
||||||
|
Arguments::sieve_script_query(self.params(Method::QuerySieveScript)),
|
||||||
|
)
|
||||||
|
.sieve_script_query_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_query_sieve_script(self) -> crate::Result<QueryResponse> {
|
||||||
|
self.send_single()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright Stalwart Labs Ltd. See the COPYING
|
||||||
|
* file at the top-level directory of this distribution.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod get;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub mod helpers;
|
||||||
|
#[cfg(feature = "blocking")]
|
||||||
|
pub mod helpers_blocking;
|
||||||
|
pub mod query;
|
||||||
|
pub mod set;
|
||||||
|
pub mod validate;
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use crate::core::changes::ChangesObject;
|
||||||
|
use crate::core::Object;
|
||||||
|
use crate::Get;
|
||||||
|
use crate::Set;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SieveScript<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
|
#[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 = "blobId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub blob_id: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "isActive")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub is_active: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Default)]
|
||||||
|
pub struct SetArguments {
|
||||||
|
#[serde(rename = "onSuccessActivateScript")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
on_success_activate_script: Option<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Copy)]
|
||||||
|
pub enum Property {
|
||||||
|
#[serde(rename = "id")]
|
||||||
|
Id,
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
Name,
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
BlobId,
|
||||||
|
#[serde(rename = "isActive")]
|
||||||
|
IsActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Property {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Property::Id => write!(f, "id"),
|
||||||
|
Property::Name => write!(f, "name"),
|
||||||
|
Property::BlobId => write!(f, "blobId"),
|
||||||
|
Property::IsActive => write!(f, "isActive"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for SieveScript<Set> {
|
||||||
|
type Property = Property;
|
||||||
|
|
||||||
|
fn requires_account_id() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for SieveScript<Get> {
|
||||||
|
type Property = Property;
|
||||||
|
|
||||||
|
fn requires_account_id() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChangesObject for SieveScript<Set> {
|
||||||
|
type ChangesResponse = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChangesObject for SieveScript<Get> {
|
||||||
|
type ChangesResponse = ();
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright Stalwart Labs Ltd. See the COPYING
|
||||||
|
* file at the top-level directory of this distribution.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
core::query::{self, QueryObject},
|
||||||
|
Set,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::SieveScript;
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone, Debug)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Filter {
|
||||||
|
Name {
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
IsActive {
|
||||||
|
#[serde(rename = "isActive")]
|
||||||
|
value: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, Clone)]
|
||||||
|
#[serde(tag = "property")]
|
||||||
|
pub enum Comparator {
|
||||||
|
#[serde(rename = "name")]
|
||||||
|
Name,
|
||||||
|
#[serde(rename = "isActive")]
|
||||||
|
IsActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Filter {
|
||||||
|
pub fn name(value: impl Into<String>) -> Self {
|
||||||
|
Filter::Name {
|
||||||
|
value: value.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_active(value: bool) -> Self {
|
||||||
|
Filter::IsActive { value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Comparator {
|
||||||
|
pub fn name() -> query::Comparator<Comparator> {
|
||||||
|
query::Comparator::new(Comparator::Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_active() -> query::Comparator<Comparator> {
|
||||||
|
query::Comparator::new(Comparator::IsActive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryObject for SieveScript<Set> {
|
||||||
|
type QueryArguments = ();
|
||||||
|
|
||||||
|
type Filter = Filter;
|
||||||
|
|
||||||
|
type Sort = Comparator;
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright Stalwart Labs Ltd. See the COPYING
|
||||||
|
* file at the top-level directory of this distribution.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
* option. This file may not be copied, modified, or distributed
|
||||||
|
* except according to those terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{core::set::SetObject, Get, Set};
|
||||||
|
|
||||||
|
use super::{SetArguments, SieveScript};
|
||||||
|
|
||||||
|
impl SieveScript<Set> {
|
||||||
|
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
|
||||||
|
self.name = Some(name.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blob_id(&mut self, blob_id: impl Into<String>) -> &mut Self {
|
||||||
|
self.blob_id = Some(blob_id.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetObject for SieveScript<Set> {
|
||||||
|
type SetArguments = SetArguments;
|
||||||
|
|
||||||
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
|
SieveScript {
|
||||||
|
_create_id,
|
||||||
|
_state: Default::default(),
|
||||||
|
id: None,
|
||||||
|
name: None,
|
||||||
|
blob_id: None,
|
||||||
|
is_active: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetArguments {
|
||||||
|
pub fn on_success_activate_script(&mut self, id: impl Into<String>) -> &mut Self {
|
||||||
|
self.on_success_activate_script = Some(Some(format!("#{}", id.into())));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_success_activate_script_id(&mut self, id: impl Into<String>) -> &mut Self {
|
||||||
|
self.on_success_activate_script = Some(Some(id.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_success_deactivate_scripts(&mut self) -> &mut Self {
|
||||||
|
self.on_success_activate_script = Some(None);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetObject for SieveScript<Get> {
|
||||||
|
type SetArguments = ();
|
||||||
|
|
||||||
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::core::{set::SetError, RequestParams};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct SieveScriptValidateRequest {
|
||||||
|
#[serde(rename = "accountId")]
|
||||||
|
account_id: String,
|
||||||
|
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
blob_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct SieveScriptValidateResponse {
|
||||||
|
#[serde(rename = "accountId")]
|
||||||
|
account_id: String,
|
||||||
|
|
||||||
|
error: Option<SetError<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SieveScriptValidateRequest {
|
||||||
|
pub fn new(params: RequestParams, blob_id: impl Into<String>) -> Self {
|
||||||
|
SieveScriptValidateRequest {
|
||||||
|
account_id: params.account_id,
|
||||||
|
blob_id: blob_id.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SieveScriptValidateResponse {
|
||||||
|
pub fn unwrap_error(self) -> crate::Result<()> {
|
||||||
|
match self.error {
|
||||||
|
Some(err) => Err(err.into()),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,7 +101,7 @@ impl Client {
|
||||||
|
|
||||||
pub async fn vacation_response_get(
|
pub async fn vacation_response_get(
|
||||||
&self,
|
&self,
|
||||||
properties: Option<Vec<Property>>,
|
properties: Option<impl IntoIterator<Item = Property>>,
|
||||||
) -> crate::Result<Option<VacationResponse>> {
|
) -> crate::Result<Option<VacationResponse>> {
|
||||||
let mut request = self.build();
|
let mut request = self.build();
|
||||||
let get_request = request.get_vacation_response().ids(["singleton"]);
|
let get_request = request.get_vacation_response().ids(["singleton"]);
|
||||||
|
|
|
@ -97,7 +97,7 @@ impl Client {
|
||||||
|
|
||||||
pub fn vacation_response_get(
|
pub fn vacation_response_get(
|
||||||
&self,
|
&self,
|
||||||
properties: Option<Vec<Property>>,
|
properties: Option<impl IntoIterator<Item = Property>>,
|
||||||
) -> crate::Result<Option<VacationResponse>> {
|
) -> crate::Result<Option<VacationResponse>> {
|
||||||
let mut request = self.build();
|
let mut request = self.build();
|
||||||
let get_request = request.get_vacation_response().ids(["singleton"]);
|
let get_request = request.get_vacation_response().ids(["singleton"]);
|
||||||
|
|
Loading…
Reference in New Issue