1use std::fmt::{Debug, Formatter};
2
3use imap_codec::{
4 imap_types::{
5 auth::AuthenticateData,
6 command::Command,
7 response::{CommandContinuationRequest, Data, Greeting, Response, Status},
8 secret::Secret,
9 },
10 AuthenticateDataCodec, CommandCodec, GreetingCodec, IdleDoneCodec, ResponseCodec,
11};
12use thiserror::Error;
13
14use crate::{
15 client_send::{ClientSendEvent, ClientSendState, ClientSendTermination},
16 handle::{Handle, HandleGenerator, HandleGeneratorGenerator, RawHandle},
17 receive::{ReceiveError, ReceiveEvent, ReceiveState},
18 types::CommandAuthenticate,
19 Interrupt, State,
20};
21
22static HANDLE_GENERATOR_GENERATOR: HandleGeneratorGenerator<CommandHandle> =
23 HandleGeneratorGenerator::new();
24
25#[derive(Clone, Debug, PartialEq)]
26#[non_exhaustive]
27pub struct Options {
28 pub crlf_relaxed: bool,
29
30 pub max_response_size: u32,
34
35 pub discard_greeting: bool,
42}
43
44#[allow(clippy::derivable_impls)]
45impl Default for Options {
46 fn default() -> Self {
47 Self {
48 crlf_relaxed: false,
50 max_response_size: 100 * 1024 * 1024,
54 discard_greeting: false,
56 }
57 }
58}
59
60pub struct Client {
61 handle_generator: HandleGenerator<CommandHandle>,
62 send_state: ClientSendState,
63 receive_state: ReceiveState,
64 next_expected_message: NextExpectedMessage,
65}
66
67impl Client {
68 pub fn new(options: Options) -> Self {
69 let send_state = ClientSendState::new(
70 CommandCodec::default(),
71 AuthenticateDataCodec::default(),
72 IdleDoneCodec::default(),
73 );
74
75 let receive_state =
76 ReceiveState::new(options.crlf_relaxed, Some(options.max_response_size));
77 let next_expected_message = if options.discard_greeting {
78 NextExpectedMessage::Response(ResponseCodec::default())
79 } else {
80 NextExpectedMessage::Greeting(GreetingCodec::default())
81 };
82
83 Self {
84 handle_generator: HANDLE_GENERATOR_GENERATOR.generate(),
85 send_state,
86 receive_state,
87 next_expected_message,
88 }
89 }
90
91 pub fn enqueue_command(&mut self, command: Command<'static>) -> CommandHandle {
97 let handle = self.handle_generator.generate();
98 self.send_state.enqueue_command(handle, command);
99 handle
100 }
101
102 fn progress_send(&mut self) -> Result<Option<Event>, Interrupt<Error>> {
103 if let NextExpectedMessage::Greeting(_) = &self.next_expected_message {
105 return Ok(None);
106 }
107
108 match self.send_state.next() {
109 Ok(Some(ClientSendEvent::Command { handle, command })) => {
110 Ok(Some(Event::CommandSent { handle, command }))
111 }
112 Ok(Some(ClientSendEvent::Authenticate { handle })) => {
113 Ok(Some(Event::AuthenticateStarted { handle }))
114 }
115 Ok(Some(ClientSendEvent::Idle { handle })) => {
116 Ok(Some(Event::IdleCommandSent { handle }))
117 }
118 Ok(Some(ClientSendEvent::IdleDone { handle })) => {
119 Ok(Some(Event::IdleDoneSent { handle }))
120 }
121 Ok(None) => Ok(None),
122 Err(Interrupt::Io(io)) => Err(Interrupt::Io(io)),
123 Err(Interrupt::Error(_)) => unreachable!(),
124 }
125 }
126
127 fn progress_receive(&mut self) -> Result<Option<Event>, Interrupt<Error>> {
128 let event = loop {
129 match &self.next_expected_message {
130 NextExpectedMessage::Greeting(codec) => {
131 match self.receive_state.next::<GreetingCodec>(codec) {
132 Ok(ReceiveEvent::DecodingSuccess(greeting)) => {
133 self.next_expected_message =
134 NextExpectedMessage::Response(ResponseCodec::default());
135 break Some(Event::GreetingReceived { greeting });
136 }
137 Ok(ReceiveEvent::LiteralAnnouncement { .. }) => {
138 continue;
140 }
141 Err(interrupt) => return Err(handle_receive_interrupt(interrupt)),
142 }
143 }
144 NextExpectedMessage::Response(codec) => {
145 let response = match self.receive_state.next::<ResponseCodec>(codec) {
146 Ok(ReceiveEvent::DecodingSuccess(response)) => response,
147 Ok(ReceiveEvent::LiteralAnnouncement { .. }) => {
148 continue;
150 }
151 Err(interrupt) => return Err(handle_receive_interrupt(interrupt)),
152 };
153
154 match response {
155 Response::Status(status) => {
156 let event = if let Some(finish_result) =
157 self.send_state.maybe_terminate(&status)
158 {
159 match finish_result {
160 ClientSendTermination::LiteralRejected { handle, command } => {
161 Event::CommandRejected {
162 handle,
163 command,
164 status,
165 }
166 }
167 ClientSendTermination::AuthenticateAccepted {
168 handle,
169 command_authenticate,
170 }
171 | ClientSendTermination::AuthenticateRejected {
172 handle,
173 command_authenticate,
174 } => Event::AuthenticateStatusReceived {
175 handle,
176 command_authenticate,
177 status,
178 },
179 ClientSendTermination::IdleRejected { handle } => {
180 Event::IdleRejected { handle, status }
181 }
182 }
183 } else {
184 Event::StatusReceived { status }
185 };
186
187 break Some(event);
188 }
189 Response::Data(data) => break Some(Event::DataReceived { data }),
190 Response::CommandContinuationRequest(continuation_request) => {
191 if self.send_state.literal_continue() {
192 break None;
196 } else if let Some(handle) = self.send_state.authenticate_continue() {
197 break Some(Event::AuthenticateContinuationRequestReceived {
198 handle,
199 continuation_request,
200 });
201 } else if let Some(handle) = self.send_state.idle_continue() {
202 break Some(Event::IdleAccepted {
203 handle,
204 continuation_request,
205 });
206 } else {
207 break Some(Event::ContinuationRequestReceived {
208 continuation_request,
209 });
210 }
211 }
212 }
213 }
214 }
215 };
216
217 Ok(event)
218 }
219
220 pub fn set_authenticate_data(
221 &mut self,
222 authenticate_data: AuthenticateData<'static>,
223 ) -> Result<CommandHandle, AuthenticateData<'static>> {
224 self.send_state.set_authenticate_data(authenticate_data)
225 }
226
227 pub fn set_idle_done(&mut self) -> Option<CommandHandle> {
228 self.send_state.set_idle_done()
229 }
230}
231
232impl Debug for Client {
233 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
234 f.debug_struct("Client")
235 .field("handle_generator", &self.handle_generator)
236 .finish_non_exhaustive()
237 }
238}
239
240impl State for Client {
241 type Event = Event;
242 type Error = Error;
243
244 fn enqueue_input(&mut self, bytes: &[u8]) {
245 self.receive_state.enqueue_input(bytes);
246 }
247
248 fn next(&mut self) -> Result<Self::Event, Interrupt<Self::Error>> {
249 loop {
250 if let Some(event) = self.progress_send()? {
251 return Ok(event);
252 }
253
254 if let Some(event) = self.progress_receive()? {
255 return Ok(event);
256 }
257 }
258 }
259}
260
261fn handle_receive_interrupt(interrupt: Interrupt<ReceiveError>) -> Interrupt<Error> {
262 match interrupt {
263 Interrupt::Io(io) => Interrupt::Io(io),
264 Interrupt::Error(ReceiveError::DecodingFailure { discarded_bytes }) => {
265 Interrupt::Error(Error::MalformedMessage { discarded_bytes })
266 }
267 Interrupt::Error(ReceiveError::ExpectedCrlfGotLf { discarded_bytes }) => {
268 Interrupt::Error(Error::ExpectedCrlfGotLf { discarded_bytes })
269 }
270 Interrupt::Error(ReceiveError::MessageIsPoisoned { .. }) => {
271 unreachable!()
273 }
274 Interrupt::Error(ReceiveError::MessageTooLong { discarded_bytes }) => {
275 Interrupt::Error(Error::ResponseTooLong { discarded_bytes })
276 }
277 }
278}
279
280#[derive(Clone, Copy, Eq, PartialEq, Hash)]
286pub struct CommandHandle(RawHandle);
287
288impl Debug for CommandHandle {
290 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
291 f.debug_tuple("CommandHandle")
292 .field(&self.0.generator_id())
293 .field(&self.0.handle_id())
294 .finish()
295 }
296}
297
298impl Handle for CommandHandle {
299 fn from_raw(handle: RawHandle) -> Self {
300 Self(handle)
301 }
302}
303
304#[derive(Debug)]
305pub enum Event {
306 GreetingReceived { greeting: Greeting<'static> },
308 CommandSent {
310 handle: CommandHandle,
312 command: Command<'static>,
314 },
315 CommandRejected {
317 handle: CommandHandle,
319 command: Command<'static>,
321 status: Status<'static>,
327 },
328 AuthenticateStarted { handle: CommandHandle },
330 AuthenticateContinuationRequestReceived {
337 handle: CommandHandle,
339 continuation_request: CommandContinuationRequest<'static>,
340 },
341 AuthenticateStatusReceived {
343 handle: CommandHandle,
344 command_authenticate: CommandAuthenticate,
345 status: Status<'static>,
346 },
347 IdleCommandSent { handle: CommandHandle },
349 IdleAccepted {
351 handle: CommandHandle,
352 continuation_request: CommandContinuationRequest<'static>,
353 },
354 IdleRejected {
356 handle: CommandHandle,
357 status: Status<'static>,
358 },
359 IdleDoneSent { handle: CommandHandle },
361 DataReceived { data: Data<'static> },
363 StatusReceived { status: Status<'static> },
365 ContinuationRequestReceived {
369 continuation_request: CommandContinuationRequest<'static>,
370 },
371}
372
373#[derive(Debug, Error)]
374pub enum Error {
375 #[error("Expected `\\r\\n`, got `\\n`")]
376 ExpectedCrlfGotLf { discarded_bytes: Secret<Box<[u8]>> },
377 #[error("Received malformed message")]
378 MalformedMessage { discarded_bytes: Secret<Box<[u8]>> },
379 #[error("Response is too long")]
380 ResponseTooLong { discarded_bytes: Secret<Box<[u8]>> },
381}
382
383#[derive(Clone, Debug)]
384enum NextExpectedMessage {
385 Greeting(GreetingCodec),
386 Response(ResponseCodec),
387}