jmap_client/core/
request.rs

1/*
2 * Copyright Stalwart Labs Ltd. See the COPYING
3 * file at the top-level directory of this distribution.
4 *
5 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8 * option. This file may not be copied, modified, or distributed
9 * except according to those terms.
10 */
11
12use crate::{
13    blob::copy::CopyBlobRequest,
14    client::Client,
15    email::{
16        import::EmailImportRequest, parse::EmailParseRequest,
17        search_snippet::SearchSnippetGetRequest, Email,
18    },
19    email_submission::EmailSubmission,
20    identity::Identity,
21    mailbox::Mailbox,
22    principal::Principal,
23    push_subscription::PushSubscription,
24    sieve::{validate::SieveScriptValidateRequest, SieveScript},
25    thread::Thread,
26    vacation_response::VacationResponse,
27    Error, Method, Set, URI,
28};
29use ahash::AHashMap;
30use serde::{de::DeserializeOwned, Serialize};
31
32use super::{
33    changes::ChangesRequest,
34    copy::CopyRequest,
35    get::GetRequest,
36    query::QueryRequest,
37    query_changes::QueryChangesRequest,
38    response::{Response, SingleMethodResponse, TaggedMethodResponse},
39    set::SetRequest,
40    RequestParams,
41};
42
43#[derive(Serialize)]
44pub struct Request<'x> {
45    #[serde(skip)]
46    client: &'x Client,
47    #[serde(skip)]
48    account_id: String,
49
50    pub using: Vec<URI>,
51
52    #[serde(rename = "methodCalls")]
53    pub method_calls: Vec<(Method, Arguments, String)>,
54
55    #[serde(rename = "createdIds")]
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub created_ids: Option<AHashMap<String, String>>,
58}
59
60#[derive(Debug, Clone, Serialize)]
61pub struct ResultReference {
62    #[serde(rename = "resultOf")]
63    result_of: String,
64    name: Method,
65    path: String,
66}
67
68#[derive(Debug, Clone, Serialize)]
69#[serde(untagged)]
70pub enum Arguments {
71    Changes(ChangesRequest),
72    PushGet(GetRequest<PushSubscription<Set>>),
73    PushSet(SetRequest<PushSubscription<Set>>),
74    BlobCopy(CopyBlobRequest),
75    MailboxGet(GetRequest<Mailbox<Set>>),
76    MailboxQuery(QueryRequest<Mailbox<Set>>),
77    MailboxQueryChanges(QueryChangesRequest<Mailbox<Set>>),
78    MailboxSet(SetRequest<Mailbox<Set>>),
79    ThreadGet(GetRequest<Thread>),
80    EmailGet(GetRequest<Email<Set>>),
81    EmailQuery(QueryRequest<Email<Set>>),
82    EmailQueryChanges(QueryChangesRequest<Email<Set>>),
83    EmailSet(SetRequest<Email<Set>>),
84    EmailCopy(CopyRequest<Email<Set>>),
85    EmailImport(EmailImportRequest),
86    EmailParse(EmailParseRequest),
87    SearchSnippetGet(SearchSnippetGetRequest),
88    IdentityGet(GetRequest<Identity<Set>>),
89    IdentitySet(SetRequest<Identity<Set>>),
90    EmailSubmissionGet(GetRequest<EmailSubmission<Set>>),
91    EmailSubmissionQuery(QueryRequest<EmailSubmission<Set>>),
92    EmailSubmissionQueryChanges(QueryChangesRequest<EmailSubmission<Set>>),
93    EmailSubmissionSet(SetRequest<EmailSubmission<Set>>),
94    VacationResponseGet(GetRequest<VacationResponse<Set>>),
95    VacationResponseSet(SetRequest<VacationResponse<Set>>),
96    SieveScriptGet(GetRequest<SieveScript<Set>>),
97    SieveScriptQuery(QueryRequest<SieveScript<Set>>),
98    SieveScriptValidate(SieveScriptValidateRequest),
99    SieveScriptSet(SetRequest<SieveScript<Set>>),
100    PrincipalGet(GetRequest<Principal<Set>>),
101    PrincipalQuery(QueryRequest<Principal<Set>>),
102    PrincipalQueryChanges(QueryChangesRequest<Principal<Set>>),
103    PrincipalSet(SetRequest<Principal<Set>>),
104}
105
106impl Arguments {
107    pub fn changes(params: RequestParams, since_state: String) -> Self {
108        Arguments::Changes(ChangesRequest::new(params, since_state))
109    }
110
111    pub fn push_get(params: RequestParams) -> Self {
112        Arguments::PushGet(GetRequest::new(params))
113    }
114
115    pub fn push_set(params: RequestParams) -> Self {
116        Arguments::PushSet(SetRequest::new(params))
117    }
118
119    pub fn blob_copy(params: RequestParams, from_account_id: String) -> Self {
120        Arguments::BlobCopy(CopyBlobRequest::new(params, from_account_id))
121    }
122
123    pub fn mailbox_get(params: RequestParams) -> Self {
124        Arguments::MailboxGet(GetRequest::new(params))
125    }
126
127    pub fn mailbox_query(params: RequestParams) -> Self {
128        Arguments::MailboxQuery(QueryRequest::new(params))
129    }
130
131    pub fn mailbox_query_changes(params: RequestParams, since_query_state: String) -> Self {
132        Arguments::MailboxQueryChanges(QueryChangesRequest::new(params, since_query_state))
133    }
134
135    pub fn mailbox_set(params: RequestParams) -> Self {
136        Arguments::MailboxSet(SetRequest::new(params))
137    }
138
139    pub fn thread_get(params: RequestParams) -> Self {
140        Arguments::ThreadGet(GetRequest::new(params))
141    }
142
143    pub fn email_get(params: RequestParams) -> Self {
144        Arguments::EmailGet(GetRequest::new(params))
145    }
146
147    pub fn email_query(params: RequestParams) -> Self {
148        Arguments::EmailQuery(QueryRequest::new(params))
149    }
150
151    pub fn email_query_changes(params: RequestParams, since_query_state: String) -> Self {
152        Arguments::EmailQueryChanges(QueryChangesRequest::new(params, since_query_state))
153    }
154
155    pub fn email_set(params: RequestParams) -> Self {
156        Arguments::EmailSet(SetRequest::new(params))
157    }
158
159    pub fn email_copy(params: RequestParams, from_account_id: String) -> Self {
160        Arguments::EmailCopy(CopyRequest::new(params, from_account_id))
161    }
162
163    pub fn email_import(params: RequestParams) -> Self {
164        Arguments::EmailImport(EmailImportRequest::new(params))
165    }
166
167    pub fn email_parse(params: RequestParams) -> Self {
168        Arguments::EmailParse(EmailParseRequest::new(params))
169    }
170
171    pub fn search_snippet_get(params: RequestParams) -> Self {
172        Arguments::SearchSnippetGet(SearchSnippetGetRequest::new(params))
173    }
174
175    pub fn identity_get(params: RequestParams) -> Self {
176        Arguments::IdentityGet(GetRequest::new(params))
177    }
178
179    pub fn identity_set(params: RequestParams) -> Self {
180        Arguments::IdentitySet(SetRequest::new(params))
181    }
182
183    pub fn email_submission_get(params: RequestParams) -> Self {
184        Arguments::EmailSubmissionGet(GetRequest::new(params))
185    }
186
187    pub fn email_submission_query(params: RequestParams) -> Self {
188        Arguments::EmailSubmissionQuery(QueryRequest::new(params))
189    }
190
191    pub fn email_submission_query_changes(
192        params: RequestParams,
193        since_query_state: String,
194    ) -> Self {
195        Arguments::EmailSubmissionQueryChanges(QueryChangesRequest::new(params, since_query_state))
196    }
197
198    pub fn email_submission_set(params: RequestParams) -> Self {
199        Arguments::EmailSubmissionSet(SetRequest::new(params))
200    }
201
202    pub fn vacation_response_get(params: RequestParams) -> Self {
203        Arguments::VacationResponseGet(GetRequest::new(params))
204    }
205
206    pub fn vacation_response_set(params: RequestParams) -> Self {
207        Arguments::VacationResponseSet(SetRequest::new(params))
208    }
209
210    pub fn sieve_script_get(params: RequestParams) -> Self {
211        Arguments::SieveScriptGet(GetRequest::new(params))
212    }
213
214    pub fn sieve_script_query(params: RequestParams) -> Self {
215        Arguments::SieveScriptQuery(QueryRequest::new(params))
216    }
217
218    pub fn sieve_script_validate(params: RequestParams, blob_id: impl Into<String>) -> Self {
219        Arguments::SieveScriptValidate(SieveScriptValidateRequest::new(params, blob_id))
220    }
221
222    pub fn sieve_script_set(params: RequestParams) -> Self {
223        Arguments::SieveScriptSet(SetRequest::new(params))
224    }
225
226    pub fn principal_get(params: RequestParams) -> Self {
227        Arguments::PrincipalGet(GetRequest::new(params))
228    }
229
230    pub fn principal_query(params: RequestParams) -> Self {
231        Arguments::PrincipalQuery(QueryRequest::new(params))
232    }
233
234    pub fn principal_query_changes(params: RequestParams, since_query_state: String) -> Self {
235        Arguments::PrincipalQueryChanges(QueryChangesRequest::new(params, since_query_state))
236    }
237
238    pub fn principal_set(params: RequestParams) -> Self {
239        Arguments::PrincipalSet(SetRequest::new(params))
240    }
241
242    pub fn changes_mut(&mut self) -> &mut ChangesRequest {
243        match self {
244            Arguments::Changes(ref mut r) => r,
245            _ => unreachable!(),
246        }
247    }
248
249    pub fn push_get_mut(&mut self) -> &mut GetRequest<PushSubscription<Set>> {
250        match self {
251            Arguments::PushGet(ref mut r) => r,
252            _ => unreachable!(),
253        }
254    }
255
256    pub fn push_set_mut(&mut self) -> &mut SetRequest<PushSubscription<Set>> {
257        match self {
258            Arguments::PushSet(ref mut r) => r,
259            _ => unreachable!(),
260        }
261    }
262
263    pub fn blob_copy_mut(&mut self) -> &mut CopyBlobRequest {
264        match self {
265            Arguments::BlobCopy(ref mut r) => r,
266            _ => unreachable!(),
267        }
268    }
269
270    pub fn mailbox_get_mut(&mut self) -> &mut GetRequest<Mailbox<Set>> {
271        match self {
272            Arguments::MailboxGet(ref mut r) => r,
273            _ => unreachable!(),
274        }
275    }
276
277    pub fn mailbox_query_mut(&mut self) -> &mut QueryRequest<Mailbox<Set>> {
278        match self {
279            Arguments::MailboxQuery(ref mut r) => r,
280            _ => unreachable!(),
281        }
282    }
283
284    pub fn mailbox_query_changes_mut(&mut self) -> &mut QueryChangesRequest<Mailbox<Set>> {
285        match self {
286            Arguments::MailboxQueryChanges(ref mut r) => r,
287            _ => unreachable!(),
288        }
289    }
290
291    pub fn mailbox_set_mut(&mut self) -> &mut SetRequest<Mailbox<Set>> {
292        match self {
293            Arguments::MailboxSet(ref mut r) => r,
294            _ => unreachable!(),
295        }
296    }
297
298    pub fn thread_get_mut(&mut self) -> &mut GetRequest<Thread> {
299        match self {
300            Arguments::ThreadGet(ref mut r) => r,
301            _ => unreachable!(),
302        }
303    }
304
305    pub fn email_get_mut(&mut self) -> &mut GetRequest<Email<Set>> {
306        match self {
307            Arguments::EmailGet(ref mut r) => r,
308            _ => unreachable!(),
309        }
310    }
311
312    pub fn email_query_mut(&mut self) -> &mut QueryRequest<Email<Set>> {
313        match self {
314            Arguments::EmailQuery(ref mut r) => r,
315            _ => unreachable!(),
316        }
317    }
318
319    pub fn email_query_changes_mut(&mut self) -> &mut QueryChangesRequest<Email<Set>> {
320        match self {
321            Arguments::EmailQueryChanges(ref mut r) => r,
322            _ => unreachable!(),
323        }
324    }
325
326    pub fn email_set_mut(&mut self) -> &mut SetRequest<Email<Set>> {
327        match self {
328            Arguments::EmailSet(ref mut r) => r,
329            _ => unreachable!(),
330        }
331    }
332
333    pub fn email_copy_mut(&mut self) -> &mut CopyRequest<Email<Set>> {
334        match self {
335            Arguments::EmailCopy(ref mut r) => r,
336            _ => unreachable!(),
337        }
338    }
339
340    pub fn email_import_mut(&mut self) -> &mut EmailImportRequest {
341        match self {
342            Arguments::EmailImport(ref mut r) => r,
343            _ => unreachable!(),
344        }
345    }
346
347    pub fn email_parse_mut(&mut self) -> &mut EmailParseRequest {
348        match self {
349            Arguments::EmailParse(ref mut r) => r,
350            _ => unreachable!(),
351        }
352    }
353
354    pub fn search_snippet_get_mut(&mut self) -> &mut SearchSnippetGetRequest {
355        match self {
356            Arguments::SearchSnippetGet(ref mut r) => r,
357            _ => unreachable!(),
358        }
359    }
360
361    pub fn identity_get_mut(&mut self) -> &mut GetRequest<Identity<Set>> {
362        match self {
363            Arguments::IdentityGet(ref mut r) => r,
364            _ => unreachable!(),
365        }
366    }
367
368    pub fn identity_set_mut(&mut self) -> &mut SetRequest<Identity<Set>> {
369        match self {
370            Arguments::IdentitySet(ref mut r) => r,
371            _ => unreachable!(),
372        }
373    }
374
375    pub fn email_submission_get_mut(&mut self) -> &mut GetRequest<EmailSubmission<Set>> {
376        match self {
377            Arguments::EmailSubmissionGet(ref mut r) => r,
378            _ => unreachable!(),
379        }
380    }
381
382    pub fn email_submission_query_mut(&mut self) -> &mut QueryRequest<EmailSubmission<Set>> {
383        match self {
384            Arguments::EmailSubmissionQuery(ref mut r) => r,
385            _ => unreachable!(),
386        }
387    }
388
389    pub fn email_submission_query_changes_mut(
390        &mut self,
391    ) -> &mut QueryChangesRequest<EmailSubmission<Set>> {
392        match self {
393            Arguments::EmailSubmissionQueryChanges(ref mut r) => r,
394            _ => unreachable!(),
395        }
396    }
397
398    pub fn email_submission_set_mut(&mut self) -> &mut SetRequest<EmailSubmission<Set>> {
399        match self {
400            Arguments::EmailSubmissionSet(ref mut r) => r,
401            _ => unreachable!(),
402        }
403    }
404
405    pub fn vacation_response_get_mut(&mut self) -> &mut GetRequest<VacationResponse<Set>> {
406        match self {
407            Arguments::VacationResponseGet(ref mut r) => r,
408            _ => unreachable!(),
409        }
410    }
411
412    pub fn vacation_response_set_mut(&mut self) -> &mut SetRequest<VacationResponse<Set>> {
413        match self {
414            Arguments::VacationResponseSet(ref mut r) => r,
415            _ => unreachable!(),
416        }
417    }
418
419    pub fn sieve_script_get_mut(&mut self) -> &mut GetRequest<SieveScript<Set>> {
420        match self {
421            Arguments::SieveScriptGet(ref mut r) => r,
422            _ => unreachable!(),
423        }
424    }
425
426    pub fn sieve_script_query_mut(&mut self) -> &mut QueryRequest<SieveScript<Set>> {
427        match self {
428            Arguments::SieveScriptQuery(ref mut r) => r,
429            _ => unreachable!(),
430        }
431    }
432
433    pub fn sieve_script_validate_mut(&mut self) -> &mut SieveScriptValidateRequest {
434        match self {
435            Arguments::SieveScriptValidate(ref mut r) => r,
436            _ => unreachable!(),
437        }
438    }
439
440    pub fn sieve_script_set_mut(&mut self) -> &mut SetRequest<SieveScript<Set>> {
441        match self {
442            Arguments::SieveScriptSet(ref mut r) => r,
443            _ => unreachable!(),
444        }
445    }
446
447    pub fn principal_get_mut(&mut self) -> &mut GetRequest<Principal<Set>> {
448        match self {
449            Arguments::PrincipalGet(ref mut r) => r,
450            _ => unreachable!(),
451        }
452    }
453
454    pub fn principal_query_mut(&mut self) -> &mut QueryRequest<Principal<Set>> {
455        match self {
456            Arguments::PrincipalQuery(ref mut r) => r,
457            _ => unreachable!(),
458        }
459    }
460
461    pub fn principal_query_changes_mut(&mut self) -> &mut QueryChangesRequest<Principal<Set>> {
462        match self {
463            Arguments::PrincipalQueryChanges(ref mut r) => r,
464            _ => unreachable!(),
465        }
466    }
467
468    pub fn principal_set_mut(&mut self) -> &mut SetRequest<Principal<Set>> {
469        match self {
470            Arguments::PrincipalSet(ref mut r) => r,
471            _ => unreachable!(),
472        }
473    }
474}
475
476impl<'x> Request<'x> {
477    pub fn new(client: &'x Client) -> Self {
478        Request {
479            using: vec![URI::Core, URI::Mail],
480            method_calls: vec![],
481            created_ids: None,
482            account_id: client.default_account_id().to_string(),
483            client,
484        }
485    }
486
487    pub fn account_id(mut self, account_id: impl Into<String>) -> Self {
488        self.account_id = account_id.into();
489        self
490    }
491
492    #[maybe_async::maybe_async]
493    pub async fn send(self) -> crate::Result<Response<TaggedMethodResponse>> {
494        self.client.send(&self).await
495    }
496
497    #[cfg(feature = "websockets")]
498    pub async fn send_ws(self) -> crate::Result<String> {
499        self.client.send_ws(self).await
500    }
501
502    #[maybe_async::maybe_async]
503    pub async fn send_single<T>(self) -> crate::Result<T>
504    where
505        T: DeserializeOwned,
506    {
507        let response: Response<SingleMethodResponse<T>> = self.client.send(&self).await?;
508        match response
509            .unwrap_method_responses()
510            .pop()
511            .ok_or_else(|| Error::Internal("Server returned no results".to_string()))?
512        {
513            SingleMethodResponse::Ok((_, response, _)) => Ok(response),
514            SingleMethodResponse::Error((_, err, _)) => Err(err.into()),
515        }
516    }
517
518    pub fn params(&self, method: Method) -> RequestParams {
519        RequestParams {
520            account_id: self.account_id.clone(),
521            method,
522            call_id: self.method_calls.len(),
523        }
524    }
525
526    pub fn add_method_call(&mut self, method: Method, arguments: Arguments) -> &mut Arguments {
527        let call_id = format!("s{}", self.method_calls.len());
528        self.method_calls.push((method, arguments, call_id));
529        &mut self.method_calls.last_mut().unwrap().1
530    }
531
532    pub fn add_capability(&mut self, uri: URI) {
533        if !self.using.contains(&uri) {
534            self.using.push(uri);
535        }
536    }
537
538    pub fn last_result_reference(&self, path: impl Into<String>) -> ResultReference {
539        let last_method = self.method_calls.last().unwrap();
540        ResultReference {
541            result_of: last_method.2.clone(),
542            name: last_method.0,
543            path: path.into(),
544        }
545    }
546}
547
548impl ResultReference {
549    pub fn new(method: Method, call_id: usize, path: impl Into<String>) -> Self {
550        ResultReference {
551            result_of: format!("s{}", call_id),
552            name: method,
553            path: path.into(),
554        }
555    }
556}