io_jmap/rfc8621/email_submission/
cancel.rs1use alloc::{collections::BTreeMap, string::String, vec, vec::Vec};
58
59use secrecy::SecretString;
60use serde::{Deserialize, Serialize};
61use thiserror::Error;
62
63use crate::{
64 coroutine::*,
65 jmap_try,
66 rfc8620::{
67 JMAP_CORE_CAPABILITY, error::JmapMethodError, request::JmapBatch, send::*,
68 session::JmapSession,
69 },
70 rfc8621::{
71 JMAP_MAIL_CAPABILITY,
72 email_submission::{
73 JMAP_SUBMISSION_CAPABILITY, JmapEmailSubmission, JmapEmailSubmissionSetItemError,
74 JmapUndoStatus,
75 },
76 },
77};
78
79#[derive(Clone, Debug, Default, Serialize)]
83#[serde(rename_all = "camelCase")]
84pub struct JmapEmailSubmissionUpdate {
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub undo_status: Option<JmapUndoStatus>,
88}
89
90#[derive(Debug, Error)]
92pub enum JmapEmailSubmissionCancelError {
93 #[error("JMAP EmailSubmission/set (cancel) failed: missing response in method_responses")]
95 MissingResponse,
96 #[error("JMAP EmailSubmission/set (cancel) failed: {0}")]
98 Send(#[from] JmapSendError),
99 #[error("JMAP EmailSubmission/set (cancel) failed: serialize args: {0}")]
101 SerializeArgs(#[source] serde_json::Error),
102 #[error("JMAP EmailSubmission/set (cancel) failed: parse response: {0}")]
104 ParseResponse(#[source] serde_json::Error),
105 #[error("JMAP EmailSubmission/set (cancel) failed: {0}")]
107 Method(#[from] JmapMethodError),
108}
109
110#[derive(Clone, Debug)]
112pub struct JmapEmailSubmissionCancelOutput {
113 pub new_state: String,
115 pub updated: BTreeMap<String, Option<JmapEmailSubmission>>,
117 pub not_updated: BTreeMap<String, JmapEmailSubmissionSetItemError>,
119 pub keep_alive: bool,
121}
122
123pub struct JmapEmailSubmissionCancel {
125 state: State,
126}
127
128impl JmapEmailSubmissionCancel {
129 pub fn new(
131 session: &JmapSession,
132 http_auth: &SecretString,
133 ids: Vec<String>,
134 ) -> Result<Self, JmapEmailSubmissionCancelError> {
135 let account_id = session
136 .primary_accounts
137 .get(JMAP_MAIL_CAPABILITY)
138 .cloned()
139 .unwrap_or_default();
140 let api_url = &session.api_url;
141
142 let update = ids
143 .into_iter()
144 .map(|id| {
145 (
146 id,
147 JmapEmailSubmissionUpdate {
148 undo_status: Some(JmapUndoStatus::Canceled),
149 },
150 )
151 })
152 .collect();
153
154 let args = serde_json::to_value(CancelEmailSubmissionsArgs { account_id, update })
155 .map_err(JmapEmailSubmissionCancelError::SerializeArgs)?;
156
157 let mut batch = JmapBatch::new();
158 batch.add("EmailSubmission/set", args);
159 let request = batch.into_request(vec![
160 JMAP_CORE_CAPABILITY.into(),
161 JMAP_MAIL_CAPABILITY.into(),
162 JMAP_SUBMISSION_CAPABILITY.into(),
163 ]);
164
165 Ok(Self {
166 state: State::Send(JmapSend::new(http_auth, api_url, request)?),
167 })
168 }
169}
170
171impl JmapCoroutine for JmapEmailSubmissionCancel {
172 type Yield = JmapYield;
173 type Return = Result<JmapEmailSubmissionCancelOutput, JmapEmailSubmissionCancelError>;
174
175 fn resume(&mut self, arg: Option<&[u8]>) -> JmapCoroutineState<Self::Yield, Self::Return> {
176 match &mut self.state {
177 State::Send(send) => {
178 let JmapSendOutput {
179 response,
180 keep_alive,
181 } = jmap_try!(send, arg);
182
183 let Some((name, args, _)) = response.method_responses.into_iter().next() else {
184 return JmapCoroutineState::Complete(Err(
185 JmapEmailSubmissionCancelError::MissingResponse,
186 ));
187 };
188
189 if name == "error" {
190 let err = serde_json::from_value::<JmapMethodError>(args)
191 .unwrap_or(JmapMethodError::Unknown);
192 return JmapCoroutineState::Complete(Err(err.into()));
193 }
194
195 match serde_json::from_value::<EmailSubmissionCancelResponse>(args) {
196 Ok(r) => JmapCoroutineState::Complete(Ok(JmapEmailSubmissionCancelOutput {
197 new_state: r.new_state,
198 updated: r.updated.unwrap_or_default(),
199 not_updated: r.not_updated.unwrap_or_default(),
200 keep_alive,
201 })),
202 Err(err) => JmapCoroutineState::Complete(Err(
203 JmapEmailSubmissionCancelError::ParseResponse(err),
204 )),
205 }
206 }
207 }
208 }
209}
210
211enum State {
212 Send(JmapSend),
213}
214
215#[derive(Serialize)]
216#[serde(rename_all = "camelCase")]
217struct CancelEmailSubmissionsArgs {
218 account_id: String,
219 update: BTreeMap<String, JmapEmailSubmissionUpdate>,
220}
221
222#[derive(Deserialize)]
223#[serde(rename_all = "camelCase")]
224struct EmailSubmissionCancelResponse {
225 new_state: String,
226 #[serde(default)]
227 updated: Option<BTreeMap<String, Option<JmapEmailSubmission>>>,
228 #[serde(default)]
229 not_updated: Option<BTreeMap<String, JmapEmailSubmissionSetItemError>>,
230}