/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use super::{ Call, Request, RequestMethod, method::{MethodFunction, MethodName, MethodObject}, }; use crate::request::{ CopyRequestMethod, GetRequestMethod, ParseRequestMethod, QueryChangesRequestMethod, QueryRequestMethod, SetRequestMethod, deserialize::{DeserializeArguments, deserialize_request}, }; use serde::{ Deserialize, Deserializer, de::{self, SeqAccess, Visitor}, }; use std::fmt::{self, Display}; impl<'x> Request<'x> { pub fn parse(json: &'x [u8], max_calls: usize, max_size: usize) -> trc::Result { if json.len() <= max_size { match serde_json::from_slice::(json) { Ok(request) => { if request.method_calls.len() <= max_calls { Ok(request) } else { Err(trc::LimitEvent::CallsIn.into_err()) } } Err(err) => Err(trc::JmapEvent::NotRequest .into_err() .reason(err.to_string()) .details(String::from_utf8_lossy(json).into_owned())), } } else { Err(trc::LimitEvent::SizeRequest.into_err()) } } } impl<'de> DeserializeArguments<'de> for Request<'de> { fn deserialize_argument(&mut self, key: &str, map: &mut A) -> Result<(), A::Error> where A: serde::de::MapAccess<'de>, { hashify::fnc_map!(key.as_bytes(), b"using" => { self.using = map.next_value()?; }, b"methodCalls" => { self.method_calls = map.next_value()?; }, b"createdIds" => { self.created_ids = map.next_value()?; }, _ => { let _ = map.next_value::()?; } ); Ok(()) } } struct CallVisitor; impl<'de> Visitor<'de> for CallVisitor { type Value = Call>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("an array with 3 elements") } fn visit_seq(self, mut seq: V) -> Result>, V::Error> where V: SeqAccess<'de>, { let method_name = seq .next_element::<&str>()? .ok_or_else(|| de::Error::invalid_length(0, &self))?; let name = match MethodName::parse(method_name) { Some(name) => name, None => { // Ignore the rest of the call let _ = seq .next_element::()? .ok_or_else(|| de::Error::invalid_length(1, &self))?; let id = seq .next_element::()? .ok_or_else(|| de::Error::invalid_length(2, &self))?; return Ok(Call { id, method: RequestMethod::Error( trc::JmapEvent::UnknownMethod .into_err() .details(method_name.to_string()), ), name: MethodName::error(), }); } }; let method = match (&name.fnc, &name.obj) { (MethodFunction::Get, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Email(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Mailbox) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Mailbox(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Thread) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Thread(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Identity) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Identity(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::EmailSubmission) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::EmailSubmission(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::PushSubscription) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::PushSubscription(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::VacationResponse) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::VacationResponse(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::SieveScript) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Sieve(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Principal) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Principal(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Quota) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Quota(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Blob) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Blob(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Calendar) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Calendar(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::CalendarEvent) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::CalendarEvent(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::CalendarEventNotification) => { match seq.next_element() { Ok(Some(value)) => { RequestMethod::Get(GetRequestMethod::CalendarEventNotification(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::Get, MethodObject::ParticipantIdentity) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::ParticipantIdentity(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::AddressBook) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::AddressBook(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::ContactCard) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::ContactCard(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::FileNode) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::FileNode(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::ShareNotification) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::ShareNotification(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::SearchSnippet) => match seq.next_element() { Ok(Some(value)) => RequestMethod::SearchSnippet(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Get, MethodObject::Registry(_)) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Registry(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Email(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::Mailbox) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Mailbox(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::Identity) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Identity(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::EmailSubmission) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::EmailSubmission(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::PushSubscription) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::PushSubscription(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::VacationResponse) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::VacationResponse(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::SieveScript) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Sieve(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::Calendar) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Calendar(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::CalendarEvent) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::CalendarEvent(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::CalendarEventNotification) => { match seq.next_element() { Ok(Some(value)) => { RequestMethod::Set(SetRequestMethod::CalendarEventNotification(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::Set, MethodObject::ParticipantIdentity) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::ParticipantIdentity(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::AddressBook) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::AddressBook(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::ContactCard) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::ContactCard(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::FileNode) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::FileNode(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::ShareNotification) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::ShareNotification(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Set, MethodObject::Registry(_)) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Registry(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Email(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::Mailbox) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Mailbox(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::EmailSubmission) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::EmailSubmission(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::SieveScript) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Sieve(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::Principal) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Principal(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::Quota) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Quota(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::Calendar) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Calendar(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::CalendarEvent) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::CalendarEvent(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::CalendarEventNotification) => { match seq.next_element() { Ok(Some(value)) => { RequestMethod::Query(QueryRequestMethod::CalendarEventNotification(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::Query, MethodObject::AddressBook) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::AddressBook(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::ContactCard) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::ContactCard(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::FileNode) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::FileNode(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::ShareNotification) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::Query(QueryRequestMethod::ShareNotification(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Query, MethodObject::Registry(_)) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Registry(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::Email(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::Mailbox) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::Mailbox(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::EmailSubmission) => { match seq.next_element() { Ok(Some(value)) => RequestMethod::QueryChanges( QueryChangesRequestMethod::EmailSubmission(value), ), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::QueryChanges, MethodObject::Principal) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::Principal(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::Quota) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::Quota(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::CalendarEvent) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::CalendarEvent(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::CalendarEventNotification) => { match seq.next_element() { Ok(Some(value)) => RequestMethod::QueryChanges( QueryChangesRequestMethod::CalendarEventNotification(value), ), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::QueryChanges, MethodObject::ContactCard) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::ContactCard(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::FileNode) => match seq.next_element() { Ok(Some(value)) => { RequestMethod::QueryChanges(QueryChangesRequestMethod::FileNode(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::QueryChanges, MethodObject::ShareNotification) => { match seq.next_element() { Ok(Some(value)) => RequestMethod::QueryChanges( QueryChangesRequestMethod::ShareNotification(value), ), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::Changes, _) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Changes(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Copy, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::Email(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Copy, MethodObject::Blob) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::Blob(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Copy, MethodObject::CalendarEvent) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::CalendarEvent(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Copy, MethodObject::ContactCard) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::ContactCard(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Lookup, MethodObject::Blob) => match seq.next_element() { Ok(Some(value)) => RequestMethod::LookupBlob(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Upload, MethodObject::Blob) => match seq.next_element() { Ok(Some(value)) => RequestMethod::UploadBlob(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Import, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => RequestMethod::ImportEmail(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Parse, MethodObject::Email) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Parse(ParseRequestMethod::Email(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Parse, MethodObject::CalendarEvent) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Parse(ParseRequestMethod::CalendarEvent(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Parse, MethodObject::ContactCard) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Parse(ParseRequestMethod::ContactCard(value)), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::GetAvailability, MethodObject::Principal) => { match seq.next_element() { Ok(Some(value)) => { RequestMethod::Get(GetRequestMethod::PrincipalAvailability(value)) } Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } } } (MethodFunction::Validate, MethodObject::SieveScript) => match seq.next_element() { Ok(Some(value)) => RequestMethod::ValidateScript(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, (MethodFunction::Echo, MethodObject::Core) => match seq.next_element() { Ok(Some(value)) => RequestMethod::Echo(value), Err(err) => RequestMethod::invalid(err), Ok(None) => { return Err(de::Error::invalid_length(1, &self)); } }, _ => { return Err(de::Error::custom(format!( "Invalid method function/object combination: {}", method_name ))); } }; let id = seq .next_element::()? .ok_or_else(|| de::Error::invalid_length(2, &self))?; Ok(Call { id, method, name }) } } impl RequestMethod<'_> { fn invalid(err: impl Display) -> Self { RequestMethod::Error( trc::JmapEvent::InvalidArguments .into_err() .details(err.to_string()), ) } } impl<'de> Deserialize<'de> for Request<'de> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserialize_request(deserializer) } } impl<'de> Deserialize<'de> for Call> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(CallVisitor) } } #[cfg(test)] mod tests { use crate::request::Request; const TEST: &str = r#" { "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ], "methodCalls": [ [ "method1", { "arg1": "arg1data", "arg2": "arg2data" }, "c1" ], [ "Core/echo", { "hello": true, "high": 5 }, "c2" ], [ "method3", {"hello": [{"a": {"b": true}}]}, "c3" ] ], "createdIds": { "c1": "m1", "c2": "m2" } } "#; const TEST1: &str = r#" { "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ], "methodCalls": [ [ "Email/query", { "accountId": "0", "filter": { "conditions": [ { "hasKeyword": "music", "maxSize": 455 }, { "hasKeyword": "video" }, { "operator": "AND", "conditions": [ { "subject": "test" }, { "minSize": 100 } ] } ], "operator": "OR" }, "sort": [ { "property": "subject", "isAscending": true }, { "property": "allInThreadHaveKeyword", "isAscending": false, "keyword": "$seen" }, { "keyword": "$junk", "property": "someInThreadHaveKeyword", "collation": "i;octet", "isAscending": false } ], "position": 0, "limit": 10 }, "c1" ] ], "createdIds": {} } "#; const TEST2: &str = r##" { "using": [ "urn:ietf:params:jmap:submission", "urn:ietf:params:jmap:mail", "urn:ietf:params:jmap:core" ], "methodCalls": [ [ "Email/set", { "accountId": "c", "create": { "c37ee58b-e224-4799-88e6-1d7484e3b782": { "mailboxIds": { "9": true }, "subject": "test", "from": [ { "name": "Foo", "email": "foo@bar.com" } ], "to": [ { "name": null, "email": "bar@foo.com" } ], "cc": [], "bcc": [], "replyTo": [ { "name": null, "email": "foo@bar.com" } ], "htmlBody": [ { "partId": "c37ee58b-e224-4799-88e6-1d7484e3b782", "type": "text/html" } ], "bodyValues": { "c37ee58b-e224-4799-88e6-1d7484e3b782": { "value": "

test email

", "isEncodingProblem": false, "isTruncated": false } }, "header:User-Agent:asText": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0" } } }, "c0" ], [ "EmailSubmission/set", { "accountId": "c", "create": { "c37ee58b-e224-4799-88e6-1d7484e3b782": { "identityId": "a", "emailId": "#c37ee58b-e224-4799-88e6-1d7484e3b782", "envelope": { "mailFrom": { "email": "foo@bar.com" }, "rcptTo": [ { "email": "bar@foo.com" } ] } } }, "onSuccessUpdateEmail": { "#c37ee58b-e224-4799-88e6-1d7484e3b782": { "mailboxIds/d": true, "mailboxIds/9": null, "keywords/$seen": true, "keywords/$draft": null } } }, "c1" ] ] } "##; #[test] fn parse_request() { println!("{:#?}", Request::parse(TEST.as_bytes(), 10, 10240)); println!("{:#?}", Request::parse(TEST1.as_bytes(), 10, 10240)); println!("{:#?}", Request::parse(TEST2.as_bytes(), 10, 10240)); } }