jmap_client/email/
parse.rs

1/*
2 * Copyright Stalwart Labs LLC 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 serde::{Deserialize, Serialize};
13
14use super::{BodyProperty, Email, Property};
15use crate::{core::RequestParams, Error};
16use ahash::AHashMap;
17
18#[derive(Debug, Clone, Serialize)]
19pub struct EmailParseRequest {
20    #[serde(rename = "accountId")]
21    account_id: String,
22
23    #[serde(rename = "blobIds")]
24    blob_ids: Vec<String>,
25
26    #[serde(rename = "properties")]
27    #[serde(skip_serializing_if = "Option::is_none")]
28    properties: Option<Vec<Property>>,
29
30    #[serde(rename = "bodyProperties")]
31    #[serde(skip_serializing_if = "Option::is_none")]
32    body_properties: Option<Vec<BodyProperty>>,
33
34    #[serde(rename = "fetchTextBodyValues")]
35    #[serde(skip_serializing_if = "Option::is_none")]
36    fetch_text_body_values: Option<bool>,
37
38    #[serde(rename = "fetchHTMLBodyValues")]
39    #[serde(skip_serializing_if = "Option::is_none")]
40    fetch_html_body_values: Option<bool>,
41
42    #[serde(rename = "fetchAllBodyValues")]
43    #[serde(skip_serializing_if = "Option::is_none")]
44    fetch_all_body_values: Option<bool>,
45
46    #[serde(rename = "maxBodyValueBytes")]
47    #[serde(skip_serializing_if = "Option::is_none")]
48    max_body_value_bytes: Option<usize>,
49}
50
51#[derive(Debug, Clone, Deserialize)]
52pub struct EmailParseResponse {
53    #[serde(rename = "accountId")]
54    account_id: String,
55
56    #[serde(rename = "parsed")]
57    parsed: Option<AHashMap<String, Email>>,
58
59    #[serde(rename = "notParsable")]
60    not_parsable: Option<Vec<String>>,
61
62    #[serde(rename = "notFound")]
63    not_found: Option<Vec<String>>,
64}
65
66impl EmailParseRequest {
67    pub fn new(params: RequestParams) -> Self {
68        EmailParseRequest {
69            account_id: params.account_id,
70            blob_ids: Vec::new(),
71            properties: None,
72            body_properties: None,
73            fetch_text_body_values: None,
74            fetch_html_body_values: None,
75            fetch_all_body_values: None,
76            max_body_value_bytes: None,
77        }
78    }
79
80    pub fn blob_ids<U, V>(&mut self, blob_ids: U) -> &mut Self
81    where
82        U: IntoIterator<Item = V>,
83        V: Into<String>,
84    {
85        self.blob_ids = blob_ids.into_iter().map(|v| v.into()).collect();
86        self
87    }
88
89    pub fn properties(&mut self, properties: impl IntoIterator<Item = Property>) -> &mut Self {
90        self.properties = Some(properties.into_iter().collect());
91        self
92    }
93
94    pub fn body_properties(
95        &mut self,
96        body_properties: impl IntoIterator<Item = BodyProperty>,
97    ) -> &mut Self {
98        self.body_properties = Some(body_properties.into_iter().collect());
99        self
100    }
101
102    pub fn fetch_text_body_values(&mut self, fetch_text_body_values: bool) -> &mut Self {
103        self.fetch_text_body_values = fetch_text_body_values.into();
104        self
105    }
106
107    pub fn fetch_html_body_values(&mut self, fetch_html_body_values: bool) -> &mut Self {
108        self.fetch_html_body_values = fetch_html_body_values.into();
109        self
110    }
111
112    pub fn fetch_all_body_values(&mut self, fetch_all_body_values: bool) -> &mut Self {
113        self.fetch_all_body_values = fetch_all_body_values.into();
114        self
115    }
116
117    pub fn max_body_value_bytes(&mut self, max_body_value_bytes: usize) -> &mut Self {
118        self.max_body_value_bytes = max_body_value_bytes.into();
119        self
120    }
121}
122
123impl EmailParseResponse {
124    pub fn account_id(&self) -> &str {
125        &self.account_id
126    }
127
128    pub fn parsed(&mut self, blob_id: &str) -> crate::Result<Email> {
129        if let Some(result) = self.parsed.as_mut().and_then(|r| r.remove(blob_id)) {
130            Ok(result)
131        } else if self
132            .not_parsable
133            .as_ref()
134            .map(|np| np.iter().any(|id| id == blob_id))
135            .unwrap_or(false)
136        {
137            Err(Error::Internal(format!(
138                "blobId {} is not parsable.",
139                blob_id
140            )))
141        } else {
142            Err(Error::Internal(format!("blobId {} not found.", blob_id)))
143        }
144    }
145
146    pub fn parsed_list(&self) -> Option<impl Iterator<Item = (&String, &Email)>> {
147        self.parsed.as_ref().map(|map| map.iter())
148    }
149
150    pub fn not_parsable(&self) -> Option<&[String]> {
151        self.not_parsable.as_deref()
152    }
153
154    pub fn not_found(&self) -> Option<&[String]> {
155        self.not_found.as_deref()
156    }
157}