Files
Stalwart/crates/jmap-proto/src/method/get.rs

168 lines
5.2 KiB
Rust

use crate::{
error::method::MethodError,
object::{email, Object},
parser::{json::Parser, Error, JsonObjectParser, Token},
request::{
method::MethodObject,
reference::{MaybeReference, ResultReference},
RequestProperty, RequestPropertyParser,
},
types::{id::Id, property::Property, state::State, value::Value},
};
#[derive(Debug, Clone)]
pub struct GetRequest<T> {
pub account_id: Id,
pub ids: Option<MaybeReference<Vec<Id>, ResultReference>>,
pub properties: Option<MaybeReference<Vec<Property>, ResultReference>>,
pub arguments: T,
}
#[derive(Debug, Clone)]
pub enum RequestArguments {
Email(email::GetArguments),
Mailbox,
Thread,
Identity,
EmailSubmission,
PushSubscription,
SieveScript,
VacationResponse,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct GetResponse {
#[serde(rename = "accountId")]
#[serde(skip_serializing_if = "Option::is_none")]
pub account_id: Option<Id>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<State>,
pub list: Vec<Object<Value>>,
#[serde(rename = "notFound")]
pub not_found: Vec<Id>,
}
impl JsonObjectParser for GetRequest<RequestArguments> {
fn parse(parser: &mut Parser<'_>) -> crate::parser::Result<Self>
where
Self: Sized,
{
let mut request = GetRequest {
arguments: match &parser.ctx {
MethodObject::Email => RequestArguments::Email(Default::default()),
MethodObject::Mailbox => RequestArguments::Mailbox,
MethodObject::Thread => RequestArguments::Thread,
MethodObject::Identity => RequestArguments::Identity,
MethodObject::EmailSubmission => RequestArguments::EmailSubmission,
MethodObject::PushSubscription => RequestArguments::PushSubscription,
MethodObject::SieveScript => RequestArguments::SieveScript,
MethodObject::VacationResponse => RequestArguments::VacationResponse,
_ => {
return Err(Error::Method(MethodError::UnknownMethod(format!(
"{}/get",
parser.ctx
))))
}
},
account_id: Id::default(),
ids: None,
properties: None,
};
parser
.next_token::<String>()?
.assert_jmap(Token::DictStart)?;
while let Some(key) = parser.next_dict_key::<RequestProperty>()? {
match &key.hash[0] {
0x0064_4974_6e75_6f63_6361 if !key.is_ref => {
request.account_id = parser.next_token::<Id>()?.unwrap_string("accountId")?;
}
0x0073_6469 => {
request.ids = if !key.is_ref {
<Option<Vec<Id>>>::parse(parser)?.map(MaybeReference::Value)
} else {
Some(MaybeReference::Reference(ResultReference::parse(parser)?))
};
}
0x7365_6974_7265_706f_7270 => {
request.properties = if !key.is_ref {
<Option<Vec<Property>>>::parse(parser)?.map(MaybeReference::Value)
} else {
Some(MaybeReference::Reference(ResultReference::parse(parser)?))
};
}
_ => {
if !request.arguments.parse(parser, key)? {
parser.skip_token(parser.depth_array, parser.depth_dict)?;
}
}
}
}
Ok(request)
}
}
impl RequestPropertyParser for RequestArguments {
fn parse(
&mut self,
parser: &mut Parser,
property: RequestProperty,
) -> crate::parser::Result<bool> {
if let RequestArguments::Email(arguments) = self {
arguments.parse(parser, property)
} else {
Ok(false)
}
}
}
impl GetRequest<RequestArguments> {
pub fn take_arguments(&mut self) -> RequestArguments {
std::mem::replace(&mut self.arguments, RequestArguments::VacationResponse)
}
pub fn with_arguments<T>(self, arguments: T) -> GetRequest<T> {
GetRequest {
arguments,
account_id: self.account_id,
ids: self.ids,
properties: self.properties,
}
}
}
impl<T> GetRequest<T> {
pub fn unwrap_properties(&mut self, default: &[Property]) -> Vec<Property> {
if let Some(mut properties) = self.properties.take().map(|p| p.unwrap()) {
// Add Id Property
if !properties.contains(&Property::Id) {
properties.push(Property::Id);
}
properties
} else {
default.to_vec()
}
}
pub fn unwrap_ids(
&mut self,
max_objects_in_get: usize,
) -> Result<Option<Vec<Id>>, MethodError> {
if let Some(ids) = self.ids.take() {
let ids = ids.unwrap();
if ids.len() <= max_objects_in_get {
Ok(Some(ids))
} else {
Err(MethodError::RequestTooLarge)
}
} else {
Ok(None)
}
}
}