1pub mod get;
13pub mod helpers;
14pub mod query;
15pub mod set;
16
17use crate::core::changes::ChangesObject;
18use crate::core::set::{map_not_set, string_not_set};
19use crate::core::Object;
20use crate::mailbox::set::role_not_set;
21use crate::principal::ACL;
22use crate::{Get, Set};
23use ahash::AHashMap;
24use serde::{Deserialize, Serialize};
25use std::fmt::Display;
26
27#[derive(Debug, Clone, Serialize, Default)]
28pub struct SetArguments {
29 #[serde(rename = "onDestroyRemoveEmails")]
30 #[serde(skip_serializing_if = "Option::is_none")]
31 on_destroy_remove_emails: Option<bool>,
32}
33
34#[derive(Debug, Clone, Serialize, Default)]
35pub struct QueryArguments {
36 #[serde(rename = "sortAsTree")]
37 sort_as_tree: bool,
38 #[serde(rename = "filterAsTree")]
39 filter_as_tree: bool,
40}
41
42#[derive(Debug, Deserialize, Default)]
43pub struct ChangesResponse {
44 #[serde(rename = "updatedProperties")]
45 updated_properties: Option<Vec<Property>>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct Mailbox<State = Get> {
50 #[serde(skip)]
51 _create_id: Option<usize>,
52
53 #[serde(skip)]
54 _state: std::marker::PhantomData<State>,
55
56 #[serde(rename = "id")]
57 #[serde(skip_serializing_if = "Option::is_none")]
58 id: Option<String>,
59
60 #[serde(rename = "name")]
61 #[serde(skip_serializing_if = "Option::is_none")]
62 name: Option<String>,
63
64 #[serde(rename = "parentId")]
65 #[serde(skip_serializing_if = "string_not_set")]
66 parent_id: Option<String>,
67
68 #[serde(rename = "role")]
69 #[serde(skip_serializing_if = "role_not_set")]
70 role: Option<Role>,
71
72 #[serde(rename = "sortOrder")]
73 #[serde(skip_serializing_if = "Option::is_none")]
74 sort_order: Option<u32>,
75
76 #[serde(rename = "totalEmails")]
77 #[serde(skip_serializing_if = "Option::is_none")]
78 total_emails: Option<usize>,
79
80 #[serde(rename = "unreadEmails")]
81 #[serde(skip_serializing_if = "Option::is_none")]
82 unread_emails: Option<usize>,
83
84 #[serde(rename = "totalThreads")]
85 #[serde(skip_serializing_if = "Option::is_none")]
86 total_threads: Option<usize>,
87
88 #[serde(rename = "unreadThreads")]
89 #[serde(skip_serializing_if = "Option::is_none")]
90 unread_threads: Option<usize>,
91
92 #[serde(rename = "myRights")]
93 #[serde(skip_serializing_if = "Option::is_none")]
94 my_rights: Option<MailboxRights>,
95
96 #[serde(rename = "isSubscribed")]
97 #[serde(skip_serializing_if = "Option::is_none")]
98 is_subscribed: Option<bool>,
99
100 #[serde(rename = "shareWith")]
101 #[serde(skip_serializing_if = "map_not_set")]
102 share_with: Option<AHashMap<String, AHashMap<ACL, bool>>>,
103
104 #[serde(flatten)]
105 #[serde(skip_deserializing)]
106 #[serde(skip_serializing_if = "Option::is_none")]
107 acl_patch: Option<AHashMap<String, ACLPatch>>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(untagged)]
112pub(crate) enum ACLPatch {
113 Replace(AHashMap<ACL, bool>),
114 Set(bool),
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Default)]
118pub enum Role {
119 Archive,
120 Drafts,
121 Important,
122 Inbox,
123 Junk,
124 Sent,
125 Trash,
126 Other(String),
127 #[default]
128 None,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
132pub struct MailboxRights {
133 #[serde(rename = "mayReadItems")]
134 #[serde(default)]
135 may_read_items: bool,
136
137 #[serde(rename = "mayAddItems")]
138 #[serde(default)]
139 may_add_items: bool,
140
141 #[serde(rename = "mayRemoveItems")]
142 #[serde(default)]
143 may_remove_items: bool,
144
145 #[serde(rename = "maySetSeen")]
146 #[serde(default)]
147 may_set_seen: bool,
148
149 #[serde(rename = "maySetKeywords")]
150 #[serde(default)]
151 may_set_keywords: bool,
152
153 #[serde(rename = "mayCreateChild")]
154 #[serde(default)]
155 may_create_child: bool,
156
157 #[serde(rename = "mayRename")]
158 #[serde(default)]
159 may_rename: bool,
160
161 #[serde(rename = "mayDelete")]
162 #[serde(default)]
163 may_delete: bool,
164
165 #[serde(rename = "maySubmit")]
166 #[serde(default)]
167 may_submit: bool,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Copy)]
171pub enum Property {
172 #[serde(rename = "id")]
173 Id,
174 #[serde(rename = "name")]
175 Name,
176 #[serde(rename = "parentId")]
177 ParentId,
178 #[serde(rename = "role")]
179 Role,
180 #[serde(rename = "sortOrder")]
181 SortOrder,
182 #[serde(rename = "totalEmails")]
183 TotalEmails,
184 #[serde(rename = "unreadEmails")]
185 UnreadEmails,
186 #[serde(rename = "totalThreads")]
187 TotalThreads,
188 #[serde(rename = "unreadThreads")]
189 UnreadThreads,
190 #[serde(rename = "myRights")]
191 MyRights,
192 #[serde(rename = "isSubscribed")]
193 IsSubscribed,
194 #[serde(rename = "shareWith")]
195 ShareWith,
196}
197
198impl Property {
199 pub fn is_count(&self) -> bool {
200 matches!(
201 self,
202 Property::TotalEmails
203 | Property::UnreadEmails
204 | Property::TotalThreads
205 | Property::UnreadThreads
206 )
207 }
208}
209
210impl Display for Property {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 match self {
213 Property::Id => write!(f, "id"),
214 Property::Name => write!(f, "name"),
215 Property::ParentId => write!(f, "parentId"),
216 Property::Role => write!(f, "role"),
217 Property::SortOrder => write!(f, "sortOrder"),
218 Property::TotalEmails => write!(f, "totalEmails"),
219 Property::UnreadEmails => write!(f, "unreadEmails"),
220 Property::TotalThreads => write!(f, "totalThreads"),
221 Property::UnreadThreads => write!(f, "unreadThreads"),
222 Property::MyRights => write!(f, "myRights"),
223 Property::IsSubscribed => write!(f, "isSubscribed"),
224 Property::ShareWith => write!(f, "shareWith"),
225 }
226 }
227}
228
229impl ChangesResponse {
230 pub fn updated_properties(&self) -> Option<&[Property]> {
231 self.updated_properties.as_deref()
232 }
233}
234
235impl Object for Mailbox<Set> {
236 type Property = Property;
237
238 fn requires_account_id() -> bool {
239 true
240 }
241}
242
243impl Object for Mailbox<Get> {
244 type Property = Property;
245
246 fn requires_account_id() -> bool {
247 true
248 }
249}
250
251impl ChangesObject for Mailbox<Set> {
252 type ChangesResponse = ChangesResponse;
253}
254
255impl ChangesObject for Mailbox<Get> {
256 type ChangesResponse = ChangesResponse;
257}
258
259impl<'de> Deserialize<'de> for Role {
260 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
261 where
262 D: serde::Deserializer<'de>,
263 {
264 match <&str>::deserialize(deserializer)?
265 .to_ascii_lowercase()
266 .as_str()
267 {
268 "inbox" => Ok(Role::Inbox),
269 "sent" => Ok(Role::Sent),
270 "trash" => Ok(Role::Trash),
271 "drafts" => Ok(Role::Drafts),
272 "junk" => Ok(Role::Junk),
273 "archive" => Ok(Role::Archive),
274 "important" => Ok(Role::Important),
275 other => Ok(Role::Other(other.to_string())),
276 }
277 }
278}
279
280impl Serialize for Role {
281 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
282 where
283 S: serde::Serializer,
284 {
285 serializer.serialize_str(match self {
286 Role::Inbox => "inbox",
287 Role::Sent => "sent",
288 Role::Trash => "trash",
289 Role::Drafts => "drafts",
290 Role::Junk => "junk",
291 Role::Archive => "archive",
292 Role::Important => "important",
293 Role::Other(other) => other,
294 Role::None => "",
295 })
296 }
297}