1pub mod email;
4pub mod email_advanced;
5pub mod identity;
6pub mod mailbox;
7pub mod search_snippet;
8pub mod submission;
9pub mod thread;
10pub mod vacation;
11
12use crate::types::{JmapError, JmapErrorType, JmapMethodCall, JmapMethodResponse};
13use rusmes_storage::backends::filesystem::FilesystemBackend;
14use rusmes_storage::StorageBackend;
15use std::path::PathBuf;
16use std::sync::Arc;
17
18#[allow(clippy::too_many_arguments)]
20pub async fn dispatch_method(
21 call: JmapMethodCall,
22 capabilities: &[String],
23) -> anyhow::Result<JmapMethodResponse> {
24 let method_name = &call.0;
25 let call_id = &call.2;
26
27 if let Err(error) = validate_method_capability(method_name, capabilities) {
29 return Ok(JmapMethodResponse(
30 "error".to_string(),
31 serde_json::to_value(error)?,
32 call_id.clone(),
33 ));
34 }
35
36 let backend = Arc::new(FilesystemBackend::new(PathBuf::from("/tmp/rusmes/mail")));
38 let message_store = backend.message_store();
39
40 match method_name.as_str() {
42 "Email/get" => {
44 let request = serde_json::from_value(call.1)?;
45 let response = email::email_get(request, message_store.as_ref()).await?;
46 Ok(JmapMethodResponse(
47 "Email/get".to_string(),
48 serde_json::to_value(response)?,
49 call_id.clone(),
50 ))
51 }
52 "Email/set" => {
53 let request = serde_json::from_value(call.1)?;
54 let response = email::email_set(request, message_store.as_ref()).await?;
55 Ok(JmapMethodResponse(
56 "Email/set".to_string(),
57 serde_json::to_value(response)?,
58 call_id.clone(),
59 ))
60 }
61 "Email/query" => {
62 let request = serde_json::from_value(call.1)?;
63 let response = email::email_query(request, message_store.as_ref()).await?;
64 Ok(JmapMethodResponse(
65 "Email/query".to_string(),
66 serde_json::to_value(response)?,
67 call_id.clone(),
68 ))
69 }
70 "Email/changes" => {
71 let request = serde_json::from_value(call.1)?;
72 let response = email_advanced::email_changes(request, message_store.as_ref()).await?;
73 Ok(JmapMethodResponse(
74 "Email/changes".to_string(),
75 serde_json::to_value(response)?,
76 call_id.clone(),
77 ))
78 }
79 "Email/queryChanges" => {
80 let request = serde_json::from_value(call.1)?;
81 let response =
82 email_advanced::email_query_changes(request, message_store.as_ref()).await?;
83 Ok(JmapMethodResponse(
84 "Email/queryChanges".to_string(),
85 serde_json::to_value(response)?,
86 call_id.clone(),
87 ))
88 }
89 "Email/copy" => {
90 let request = serde_json::from_value(call.1)?;
91 let response = email_advanced::email_copy(request, message_store.as_ref()).await?;
92 Ok(JmapMethodResponse(
93 "Email/copy".to_string(),
94 serde_json::to_value(response)?,
95 call_id.clone(),
96 ))
97 }
98 "Email/import" => {
99 let request = serde_json::from_value(call.1)?;
100 let response = email_advanced::email_import(request, message_store.as_ref()).await?;
101 Ok(JmapMethodResponse(
102 "Email/import".to_string(),
103 serde_json::to_value(response)?,
104 call_id.clone(),
105 ))
106 }
107 "Email/parse" => {
108 let request = serde_json::from_value(call.1)?;
109 let response = email_advanced::email_parse(request, message_store.as_ref()).await?;
110 Ok(JmapMethodResponse(
111 "Email/parse".to_string(),
112 serde_json::to_value(response)?,
113 call_id.clone(),
114 ))
115 }
116
117 "EmailSubmission/get" => {
119 let request = serde_json::from_value(call.1)?;
120 let response =
121 submission::email_submission_get(request, message_store.as_ref()).await?;
122 Ok(JmapMethodResponse(
123 "EmailSubmission/get".to_string(),
124 serde_json::to_value(response)?,
125 call_id.clone(),
126 ))
127 }
128 "EmailSubmission/set" => {
129 let request = serde_json::from_value(call.1)?;
130 let response =
131 submission::email_submission_set(request, message_store.as_ref()).await?;
132 Ok(JmapMethodResponse(
133 "EmailSubmission/set".to_string(),
134 serde_json::to_value(response)?,
135 call_id.clone(),
136 ))
137 }
138 "EmailSubmission/query" => {
139 let request = serde_json::from_value(call.1)?;
140 let response =
141 submission::email_submission_query(request, message_store.as_ref()).await?;
142 Ok(JmapMethodResponse(
143 "EmailSubmission/query".to_string(),
144 serde_json::to_value(response)?,
145 call_id.clone(),
146 ))
147 }
148 "EmailSubmission/changes" => {
149 let request = serde_json::from_value(call.1)?;
150 let response =
151 submission::email_submission_changes(request, message_store.as_ref()).await?;
152 Ok(JmapMethodResponse(
153 "EmailSubmission/changes".to_string(),
154 serde_json::to_value(response)?,
155 call_id.clone(),
156 ))
157 }
158
159 "Mailbox/get" => {
161 let request = serde_json::from_value(call.1)?;
162 let response = mailbox::mailbox_get(request, message_store.as_ref()).await?;
163 Ok(JmapMethodResponse(
164 "Mailbox/get".to_string(),
165 serde_json::to_value(response)?,
166 call_id.clone(),
167 ))
168 }
169 "Mailbox/set" => {
170 let request = serde_json::from_value(call.1)?;
171 let response = mailbox::mailbox_set(request, message_store.as_ref()).await?;
172 Ok(JmapMethodResponse(
173 "Mailbox/set".to_string(),
174 serde_json::to_value(response)?,
175 call_id.clone(),
176 ))
177 }
178 "Mailbox/query" => {
179 let request = serde_json::from_value(call.1)?;
180 let response = mailbox::mailbox_query(request, message_store.as_ref()).await?;
181 Ok(JmapMethodResponse(
182 "Mailbox/query".to_string(),
183 serde_json::to_value(response)?,
184 call_id.clone(),
185 ))
186 }
187 "Mailbox/changes" => {
188 let request = serde_json::from_value(call.1)?;
189 let response = mailbox::mailbox_changes(request, message_store.as_ref()).await?;
190 Ok(JmapMethodResponse(
191 "Mailbox/changes".to_string(),
192 serde_json::to_value(response)?,
193 call_id.clone(),
194 ))
195 }
196 "Mailbox/queryChanges" => {
197 let request = serde_json::from_value(call.1)?;
198 let response = mailbox::mailbox_query_changes(request, message_store.as_ref()).await?;
199 Ok(JmapMethodResponse(
200 "Mailbox/queryChanges".to_string(),
201 serde_json::to_value(response)?,
202 call_id.clone(),
203 ))
204 }
205
206 "Thread/get" => {
208 let request = serde_json::from_value(call.1)?;
209 let response = thread::thread_get(request, message_store.as_ref()).await?;
210 Ok(JmapMethodResponse(
211 "Thread/get".to_string(),
212 serde_json::to_value(response)?,
213 call_id.clone(),
214 ))
215 }
216 "Thread/changes" => {
217 let request = serde_json::from_value(call.1)?;
218 let response = thread::thread_changes(request, message_store.as_ref()).await?;
219 Ok(JmapMethodResponse(
220 "Thread/changes".to_string(),
221 serde_json::to_value(response)?,
222 call_id.clone(),
223 ))
224 }
225
226 "SearchSnippet/get" => {
228 let request = serde_json::from_value(call.1)?;
229 let response =
230 search_snippet::search_snippet_get(request, message_store.as_ref()).await?;
231 Ok(JmapMethodResponse(
232 "SearchSnippet/get".to_string(),
233 serde_json::to_value(response)?,
234 call_id.clone(),
235 ))
236 }
237
238 "Identity/get" => {
240 let request = serde_json::from_value(call.1)?;
241 let response = identity::identity_get(request, message_store.as_ref()).await?;
242 Ok(JmapMethodResponse(
243 "Identity/get".to_string(),
244 serde_json::to_value(response)?,
245 call_id.clone(),
246 ))
247 }
248 "Identity/set" => {
249 let request = serde_json::from_value(call.1)?;
250 let response = identity::identity_set(request, message_store.as_ref()).await?;
251 Ok(JmapMethodResponse(
252 "Identity/set".to_string(),
253 serde_json::to_value(response)?,
254 call_id.clone(),
255 ))
256 }
257 "Identity/changes" => {
258 let request = serde_json::from_value(call.1)?;
259 let response = identity::identity_changes(request, message_store.as_ref()).await?;
260 Ok(JmapMethodResponse(
261 "Identity/changes".to_string(),
262 serde_json::to_value(response)?,
263 call_id.clone(),
264 ))
265 }
266
267 "VacationResponse/get" => {
269 let request = serde_json::from_value(call.1)?;
270 let response = vacation::vacation_response_get(request, message_store.as_ref()).await?;
271 Ok(JmapMethodResponse(
272 "VacationResponse/get".to_string(),
273 serde_json::to_value(response)?,
274 call_id.clone(),
275 ))
276 }
277 "VacationResponse/set" => {
278 let request = serde_json::from_value(call.1)?;
279 let response = vacation::vacation_response_set(request, message_store.as_ref()).await?;
280 Ok(JmapMethodResponse(
281 "VacationResponse/set".to_string(),
282 serde_json::to_value(response)?,
283 call_id.clone(),
284 ))
285 }
286
287 _ => {
288 Ok(JmapMethodResponse(
290 "error".to_string(),
291 serde_json::to_value(
292 JmapError::new(JmapErrorType::UnknownMethod)
293 .with_detail(format!("Unknown method: {}", method_name)),
294 )?,
295 call_id.clone(),
296 ))
297 }
298 }
299}
300
301fn validate_method_capability(method_name: &str, capabilities: &[String]) -> Result<(), JmapError> {
303 let required_capability = match method_name {
304 m if m.starts_with("Email/") => "urn:ietf:params:jmap:mail",
305 m if m.starts_with("Mailbox/") => "urn:ietf:params:jmap:mail",
306 m if m.starts_with("Thread/") => "urn:ietf:params:jmap:mail",
307 m if m.starts_with("SearchSnippet/") => "urn:ietf:params:jmap:mail",
308 m if m.starts_with("EmailSubmission/") => "urn:ietf:params:jmap:submission",
309 m if m.starts_with("Identity/") => "urn:ietf:params:jmap:submission",
310 m if m.starts_with("VacationResponse/") => "urn:ietf:params:jmap:vacationresponse",
311 _ => {
312 return Ok(());
314 }
315 };
316
317 if !capabilities.iter().any(|cap| cap == required_capability) {
318 return Err(
319 JmapError::new(JmapErrorType::UnknownMethod).with_detail(format!(
320 "Method '{}' requires capability '{}' which was not declared in 'using'",
321 method_name, required_capability
322 )),
323 );
324 }
325
326 Ok(())
327}