1use std::{
13 num::{ParseIntError, TryFromIntError},
14 str::Utf8Error,
15};
16
17use imap_types::{
18 IntoStatic,
19 auth::AuthenticateData,
20 command::Command,
21 core::{LiteralMode, Tag},
22 extensions::idle::IdleDone,
23 response::{Greeting, Response},
24};
25use nom::error::{ErrorKind, FromExternalError, ParseError};
26
27use crate::{
28 AuthenticateDataCodec, CommandCodec, GreetingCodec, IdleDoneCodec, ResponseCodec,
29 auth::authenticate_data,
30 command::command,
31 extensions::idle::idle_done,
32 response::{greeting, response},
33};
34
35pub(crate) type IMAPResult<'a, I, O> = Result<(I, O), nom::Err<IMAPParseError<'a, I>>>;
37
38#[derive(Debug)]
40pub(crate) struct IMAPParseError<'a, I> {
41 #[allow(unused)]
42 pub input: I,
43 pub kind: IMAPErrorKind<'a>,
44}
45
46#[derive(Debug)]
48pub(crate) enum IMAPErrorKind<'a> {
49 Literal {
50 tag: Option<Tag<'a>>,
51 length: u32,
52 mode: LiteralMode,
53 },
54 BadNumber,
55 BadBase64,
56 BadUtf8,
57 BadDateTime,
58 LiteralContainsNull,
59 RecursionLimitExceeded,
60 Nom(#[allow(dead_code)] ErrorKind),
61}
62
63impl<I> ParseError<I> for IMAPParseError<'_, I> {
64 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
65 Self {
66 input,
67 kind: IMAPErrorKind::Nom(kind),
68 }
69 }
70
71 fn append(input: I, kind: ErrorKind, _: Self) -> Self {
72 Self {
73 input,
74 kind: IMAPErrorKind::Nom(kind),
75 }
76 }
77}
78
79impl<I> FromExternalError<I, ParseIntError> for IMAPParseError<'_, I> {
80 fn from_external_error(input: I, _: ErrorKind, _: ParseIntError) -> Self {
81 Self {
82 input,
83 kind: IMAPErrorKind::BadNumber,
84 }
85 }
86}
87
88impl<I> FromExternalError<I, TryFromIntError> for IMAPParseError<'_, I> {
89 fn from_external_error(input: I, _: ErrorKind, _: TryFromIntError) -> Self {
90 Self {
91 input,
92 kind: IMAPErrorKind::BadNumber,
93 }
94 }
95}
96
97impl<I> FromExternalError<I, base64::DecodeError> for IMAPParseError<'_, I> {
98 fn from_external_error(input: I, _: ErrorKind, _: base64::DecodeError) -> Self {
99 Self {
100 input,
101 kind: IMAPErrorKind::BadBase64,
102 }
103 }
104}
105
106impl<I> FromExternalError<I, Utf8Error> for IMAPParseError<'_, I> {
107 fn from_external_error(input: I, _: ErrorKind, _: Utf8Error) -> Self {
108 Self {
109 input,
110 kind: IMAPErrorKind::BadUtf8,
111 }
112 }
113}
114
115pub trait Decoder {
119 type Message<'a>: Sized;
120 type Error<'a>;
121
122 fn decode<'a>(&self, input: &'a [u8])
123 -> Result<(&'a [u8], Self::Message<'a>), Self::Error<'a>>;
124
125 fn decode_static<'a>(
126 &self,
127 input: &'a [u8],
128 ) -> Result<(&'a [u8], Self::Message<'static>), Self::Error<'static>>
129 where
130 Self::Message<'a>: IntoStatic<Static = Self::Message<'static>>,
131 Self::Error<'a>: IntoStatic<Static = Self::Error<'static>>,
132 {
133 let (remaining, value) = self.decode(input).map_err(IntoStatic::into_static)?;
134 Ok((remaining, value.into_static()))
135 }
136}
137
138#[derive(Clone, Copy, Debug, Eq, PartialEq)]
140pub enum GreetingDecodeError {
141 Incomplete,
143
144 Failed,
146}
147
148impl IntoStatic for GreetingDecodeError {
149 type Static = Self;
150
151 fn into_static(self) -> Self::Static {
152 self
153 }
154}
155
156#[derive(Clone, Debug, Eq, PartialEq)]
158pub enum CommandDecodeError<'a> {
159 Incomplete,
161
162 LiteralFound {
199 tag: Tag<'a>,
203
204 length: u32,
206
207 mode: LiteralMode,
209 },
210
211 Failed,
213}
214
215impl IntoStatic for CommandDecodeError<'_> {
216 type Static = CommandDecodeError<'static>;
217
218 fn into_static(self) -> Self::Static {
219 match self {
220 CommandDecodeError::Incomplete => CommandDecodeError::Incomplete,
221 CommandDecodeError::LiteralFound { tag, length, mode } => {
222 CommandDecodeError::LiteralFound {
223 tag: tag.into_static(),
224 length,
225 mode,
226 }
227 }
228 CommandDecodeError::Failed => CommandDecodeError::Failed,
229 }
230 }
231}
232
233#[derive(Clone, Copy, Debug, Eq, PartialEq)]
235pub enum AuthenticateDataDecodeError {
236 Incomplete,
238
239 Failed,
241}
242
243impl IntoStatic for AuthenticateDataDecodeError {
244 type Static = Self;
245
246 fn into_static(self) -> Self::Static {
247 self
248 }
249}
250
251#[derive(Clone, Debug, Eq, PartialEq)]
253pub enum ResponseDecodeError {
254 Incomplete,
256
257 LiteralFound {
266 length: u32,
268 },
269
270 Failed,
272}
273
274impl IntoStatic for ResponseDecodeError {
275 type Static = Self;
276
277 fn into_static(self) -> Self::Static {
278 self
279 }
280}
281
282#[derive(Clone, Copy, Debug, Eq, PartialEq)]
284pub enum IdleDoneDecodeError {
285 Incomplete,
287
288 Failed,
290}
291
292impl IntoStatic for IdleDoneDecodeError {
293 type Static = Self;
294
295 fn into_static(self) -> Self::Static {
296 self
297 }
298}
299
300impl Decoder for GreetingCodec {
303 type Message<'a> = Greeting<'a>;
304 type Error<'a> = GreetingDecodeError;
305
306 fn decode<'a>(
307 &self,
308 input: &'a [u8],
309 ) -> Result<(&'a [u8], Self::Message<'a>), Self::Error<'static>> {
310 match greeting(input) {
311 Ok((rem, grt)) => Ok((rem, grt)),
312 Err(nom::Err::Incomplete(_)) => Err(GreetingDecodeError::Incomplete),
313 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => Err(GreetingDecodeError::Failed),
314 }
315 }
316}
317
318impl Decoder for CommandCodec {
319 type Message<'a> = Command<'a>;
320 type Error<'a> = CommandDecodeError<'a>;
321
322 fn decode<'a>(
323 &self,
324 input: &'a [u8],
325 ) -> Result<(&'a [u8], Self::Message<'a>), Self::Error<'a>> {
326 match command(input) {
327 Ok((rem, cmd)) => Ok((rem, cmd)),
328 Err(nom::Err::Incomplete(_)) => Err(CommandDecodeError::Incomplete),
329 Err(nom::Err::Failure(error)) => match error {
330 IMAPParseError {
331 input: _,
332 kind: IMAPErrorKind::Literal { tag, length, mode },
333 } => Err(CommandDecodeError::LiteralFound {
334 tag: tag.expect("Expected `Some(tag)` in `IMAPErrorKind::Literal`, got `None`"),
336 length,
337 mode,
338 }),
339 _ => Err(CommandDecodeError::Failed),
340 },
341 Err(nom::Err::Error(_)) => Err(CommandDecodeError::Failed),
342 }
343 }
344}
345
346impl Decoder for ResponseCodec {
347 type Message<'a> = Response<'a>;
348 type Error<'a> = ResponseDecodeError;
349
350 fn decode<'a>(
351 &self,
352 input: &'a [u8],
353 ) -> Result<(&'a [u8], Self::Message<'a>), Self::Error<'static>> {
354 match response(input) {
355 Ok((rem, rsp)) => Ok((rem, rsp)),
356 Err(nom::Err::Incomplete(_)) => Err(ResponseDecodeError::Incomplete),
357 Err(nom::Err::Error(error) | nom::Err::Failure(error)) => match error {
358 IMAPParseError {
359 kind: IMAPErrorKind::Literal { length, .. },
360 ..
361 } => Err(ResponseDecodeError::LiteralFound { length }),
362 _ => Err(ResponseDecodeError::Failed),
363 },
364 }
365 }
366}
367
368impl Decoder for AuthenticateDataCodec {
369 type Message<'a> = AuthenticateData<'a>;
370 type Error<'a> = AuthenticateDataDecodeError;
371
372 fn decode<'a>(
373 &self,
374 input: &'a [u8],
375 ) -> Result<(&'a [u8], Self::Message<'a>), Self::Error<'static>> {
376 match authenticate_data(input) {
377 Ok((rem, rsp)) => Ok((rem, rsp)),
378 Err(nom::Err::Incomplete(_)) => Err(AuthenticateDataDecodeError::Incomplete),
379 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => {
380 Err(AuthenticateDataDecodeError::Failed)
381 }
382 }
383 }
384}
385
386impl Decoder for IdleDoneCodec {
387 type Message<'a> = IdleDone;
388 type Error<'a> = IdleDoneDecodeError;
389
390 fn decode<'a>(
391 &self,
392 input: &'a [u8],
393 ) -> Result<(&'a [u8], Self::Message<'a>), Self::Error<'static>> {
394 match idle_done(input) {
395 Ok((rem, rsp)) => Ok((rem, rsp)),
396 Err(nom::Err::Incomplete(_)) => Err(IdleDoneDecodeError::Incomplete),
397 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => Err(IdleDoneDecodeError::Failed),
398 }
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use std::num::NonZeroU32;
405
406 use imap_types::{
407 command::{Command, CommandBody},
408 core::{IString, Literal, NString, Vec1},
409 extensions::idle::IdleDone,
410 fetch::MessageDataItem,
411 mailbox::Mailbox,
412 response::{Data, Greeting, GreetingKind, Response},
413 };
414
415 use super::*;
416
417 #[test]
418 fn test_decode_greeting() {
419 let tests = [
420 (
422 b"* OK ...\r\n".as_ref(),
423 Ok((
424 b"".as_ref(),
425 Greeting::new(GreetingKind::Ok, None, "...").unwrap(),
426 )),
427 ),
428 (
429 b"* ByE .\r\n???".as_ref(),
430 Ok((
431 b"???".as_ref(),
432 Greeting::new(GreetingKind::Bye, None, ".").unwrap(),
433 )),
434 ),
435 (
436 b"* preaUth x\r\n?".as_ref(),
437 Ok((
438 b"?".as_ref(),
439 Greeting::new(GreetingKind::PreAuth, None, "x").unwrap(),
440 )),
441 ),
442 (b"*".as_ref(), Err(GreetingDecodeError::Incomplete)),
444 (b"* ".as_ref(), Err(GreetingDecodeError::Incomplete)),
445 (b"* O".as_ref(), Err(GreetingDecodeError::Incomplete)),
446 (b"* OK".as_ref(), Err(GreetingDecodeError::Incomplete)),
447 (b"* OK ".as_ref(), Err(GreetingDecodeError::Incomplete)),
448 (b"* OK .".as_ref(), Err(GreetingDecodeError::Incomplete)),
449 (b"* OK .\r".as_ref(), Err(GreetingDecodeError::Incomplete)),
450 (b"**".as_ref(), Err(GreetingDecodeError::Failed)),
452 (b"* NO x\r\n".as_ref(), Err(GreetingDecodeError::Failed)),
453 ];
454
455 for (test, expected) in tests {
456 let got = GreetingCodec::default().decode(test);
457 dbg!((std::str::from_utf8(test).unwrap(), &expected, &got));
458 assert_eq!(expected, got);
459
460 {
461 let got = GreetingCodec::default().decode_static(test);
462 assert_eq!(expected, got);
463 }
464 }
465 }
466
467 #[test]
468 fn test_decode_command() {
469 let tests = [
470 (
472 b"a noop\r\n".as_ref(),
473 Ok((b"".as_ref(), Command::new("a", CommandBody::Noop).unwrap())),
474 ),
475 (
476 b"a noop\r\n???".as_ref(),
477 Ok((
478 b"???".as_ref(),
479 Command::new("a", CommandBody::Noop).unwrap(),
480 )),
481 ),
482 (
483 b"a select {5}\r\ninbox\r\n".as_ref(),
484 Ok((
485 b"".as_ref(),
486 Command::new(
487 "a",
488 CommandBody::Select {
489 mailbox: Mailbox::Inbox,
490 #[cfg(feature = "ext_condstore_qresync")]
491 parameters: Vec::default(),
492 },
493 )
494 .unwrap(),
495 )),
496 ),
497 (
498 b"a select {5}\r\ninbox\r\nxxx".as_ref(),
499 Ok((
500 b"xxx".as_ref(),
501 Command::new(
502 "a",
503 CommandBody::Select {
504 mailbox: Mailbox::Inbox,
505 #[cfg(feature = "ext_condstore_qresync")]
506 parameters: Vec::default(),
507 },
508 )
509 .unwrap(),
510 )),
511 ),
512 (b"a".as_ref(), Err(CommandDecodeError::Incomplete)),
514 (b"a ".as_ref(), Err(CommandDecodeError::Incomplete)),
515 (b"a n".as_ref(), Err(CommandDecodeError::Incomplete)),
516 (b"a no".as_ref(), Err(CommandDecodeError::Incomplete)),
517 (b"a noo".as_ref(), Err(CommandDecodeError::Incomplete)),
518 (b"a noop".as_ref(), Err(CommandDecodeError::Incomplete)),
519 (b"a noop\r".as_ref(), Err(CommandDecodeError::Incomplete)),
520 (
522 b"a select {5}\r\n".as_ref(),
523 Err(CommandDecodeError::LiteralFound {
524 tag: Tag::try_from("a").unwrap(),
525 length: 5,
526 mode: LiteralMode::Sync,
527 }),
528 ),
529 (
531 b"a select {5}\r\nxxx".as_ref(),
532 Err(CommandDecodeError::Incomplete),
533 ),
534 (b"* noop\r\n".as_ref(), Err(CommandDecodeError::Failed)),
536 (b"A noop\r\n".as_ref(), Err(CommandDecodeError::Failed)),
537 ];
538
539 for (test, expected) in tests {
540 let got = CommandCodec::default().decode(test);
541 dbg!((std::str::from_utf8(test).unwrap(), &expected, &got));
542 assert_eq!(expected, got);
543
544 {
545 let got = CommandCodec::default().decode_static(test);
546 assert_eq!(expected, got);
547 }
548 }
549 }
550
551 #[test]
552 fn test_decode_authenticate_data() {
553 let tests = [
554 (
556 b"VGVzdA==\r\n".as_ref(),
557 Ok((b"".as_ref(), AuthenticateData::r#continue(b"Test".to_vec()))),
558 ),
559 (
560 b"VGVzdA==\r\nx".as_ref(),
561 Ok((
562 b"x".as_ref(),
563 AuthenticateData::r#continue(b"Test".to_vec()),
564 )),
565 ),
566 (
567 b"*\r\n".as_ref(),
568 Ok((b"".as_ref(), AuthenticateData::Cancel)),
569 ),
570 (
571 b"*\r\nx".as_ref(),
572 Ok((b"x".as_ref(), AuthenticateData::Cancel)),
573 ),
574 (b"V".as_ref(), Err(AuthenticateDataDecodeError::Incomplete)),
576 (b"VG".as_ref(), Err(AuthenticateDataDecodeError::Incomplete)),
577 (
578 b"VGV".as_ref(),
579 Err(AuthenticateDataDecodeError::Incomplete),
580 ),
581 (
582 b"VGVz".as_ref(),
583 Err(AuthenticateDataDecodeError::Incomplete),
584 ),
585 (
586 b"VGVzd".as_ref(),
587 Err(AuthenticateDataDecodeError::Incomplete),
588 ),
589 (
590 b"VGVzdA".as_ref(),
591 Err(AuthenticateDataDecodeError::Incomplete),
592 ),
593 (
594 b"VGVzdA=".as_ref(),
595 Err(AuthenticateDataDecodeError::Incomplete),
596 ),
597 (
598 b"VGVzdA==".as_ref(),
599 Err(AuthenticateDataDecodeError::Incomplete),
600 ),
601 (
602 b"VGVzdA==\r".as_ref(),
603 Err(AuthenticateDataDecodeError::Incomplete),
604 ),
605 (
606 b"VGVzdA==\r\n".as_ref(),
607 Ok((b"".as_ref(), AuthenticateData::r#continue(b"Test".to_vec()))),
608 ),
609 (
611 b"VGVzdA== \r\n".as_ref(),
612 Err(AuthenticateDataDecodeError::Failed),
613 ),
614 (
615 b" VGVzdA== \r\n".as_ref(),
616 Err(AuthenticateDataDecodeError::Failed),
617 ),
618 (
619 b" V GVzdA== \r\n".as_ref(),
620 Err(AuthenticateDataDecodeError::Failed),
621 ),
622 (
623 b" V GVzdA= \r\n".as_ref(),
624 Err(AuthenticateDataDecodeError::Failed),
625 ),
626 ];
627
628 for (test, expected) in tests {
629 let got = AuthenticateDataCodec::default().decode(test);
630 dbg!((std::str::from_utf8(test).unwrap(), &expected, &got));
631 assert_eq!(expected, got);
632
633 {
634 let got = AuthenticateDataCodec::default().decode_static(test);
635 assert_eq!(expected, got);
636 }
637 }
638 }
639
640 #[test]
641 fn test_decode_idle_done() {
642 let tests = [
643 (b"done\r\n".as_ref(), Ok((b"".as_ref(), IdleDone))),
645 (b"done\r\n?".as_ref(), Ok((b"?".as_ref(), IdleDone))),
646 (b"d".as_ref(), Err(IdleDoneDecodeError::Incomplete)),
648 (b"do".as_ref(), Err(IdleDoneDecodeError::Incomplete)),
649 (b"don".as_ref(), Err(IdleDoneDecodeError::Incomplete)),
650 (b"done".as_ref(), Err(IdleDoneDecodeError::Incomplete)),
651 (b"done\r".as_ref(), Err(IdleDoneDecodeError::Incomplete)),
652 (b"donee\r\n".as_ref(), Err(IdleDoneDecodeError::Failed)),
654 (b" done\r\n".as_ref(), Err(IdleDoneDecodeError::Failed)),
655 (b"done \r\n".as_ref(), Err(IdleDoneDecodeError::Failed)),
656 (b" done \r\n".as_ref(), Err(IdleDoneDecodeError::Failed)),
657 ];
658
659 for (test, expected) in tests {
660 let got = IdleDoneCodec::default().decode(test);
661 dbg!((std::str::from_utf8(test).unwrap(), &expected, &got));
662 assert_eq!(expected, got);
663
664 {
665 let got = IdleDoneCodec::default().decode_static(test);
666 assert_eq!(expected, got);
667 }
668 }
669 }
670
671 #[test]
672 fn test_decode_response() {
673 let tests = [
674 (b"".as_ref(), Err(ResponseDecodeError::Incomplete)),
676 (b"*".as_ref(), Err(ResponseDecodeError::Incomplete)),
677 (b"* ".as_ref(), Err(ResponseDecodeError::Incomplete)),
678 (b"* S".as_ref(), Err(ResponseDecodeError::Incomplete)),
679 (b"* SE".as_ref(), Err(ResponseDecodeError::Incomplete)),
680 (b"* SEA".as_ref(), Err(ResponseDecodeError::Incomplete)),
681 (b"* SEAR".as_ref(), Err(ResponseDecodeError::Incomplete)),
682 (b"* SEARC".as_ref(), Err(ResponseDecodeError::Incomplete)),
683 (b"* SEARCH".as_ref(), Err(ResponseDecodeError::Incomplete)),
684 (b"* SEARCH ".as_ref(), Err(ResponseDecodeError::Incomplete)),
685 (b"* SEARCH 1".as_ref(), Err(ResponseDecodeError::Incomplete)),
686 (
687 b"* SEARCH 1\r".as_ref(),
688 Err(ResponseDecodeError::Incomplete),
689 ),
690 (
692 b"* SEARCH 1\r\n".as_ref(),
693 Ok((
694 b"".as_ref(),
695 Response::Data(Data::Search(
696 vec![NonZeroU32::new(1).unwrap()],
697 #[cfg(feature = "ext_condstore_qresync")]
698 None,
699 )),
700 )),
701 ),
702 #[cfg(feature = "quirk_trailing_space_search")]
703 (
704 b"* SEARCH \r\n".as_ref(),
705 Ok((
706 b"".as_ref(),
707 Response::Data(Data::Search(
708 vec![],
709 #[cfg(feature = "ext_condstore_qresync")]
710 None,
711 )),
712 )),
713 ),
714 (
715 b"* SEARCH 1\r\n???".as_ref(),
716 Ok((
717 b"???".as_ref(),
718 Response::Data(Data::Search(
719 vec![NonZeroU32::new(1).unwrap()],
720 #[cfg(feature = "ext_condstore_qresync")]
721 None,
722 )),
723 )),
724 ),
725 (
726 b"* 1 FETCH (RFC822 {5}\r\nhello)\r\n".as_ref(),
727 Ok((
728 b"".as_ref(),
729 Response::Data(Data::Fetch {
730 seq: NonZeroU32::new(1).unwrap(),
731 items: Vec1::from(MessageDataItem::Rfc822(NString(Some(
732 IString::Literal(Literal::try_from(b"hello".as_ref()).unwrap()),
733 )))),
734 }),
735 )),
736 ),
737 (
738 b"* 1 FETCH (RFC822 {5}\r\n".as_ref(),
739 Err(ResponseDecodeError::LiteralFound { length: 5 }),
740 ),
741 (
743 b"* search 1 2 3\r\n".as_ref(),
744 Err(ResponseDecodeError::Failed),
745 ),
746 #[cfg(not(feature = "quirk_trailing_space_search"))]
747 (b"* search \r\n".as_ref(), Err(ResponseDecodeError::Failed)),
748 (b"A search\r\n".as_ref(), Err(ResponseDecodeError::Failed)),
749 ];
750
751 for (test, expected) in tests {
752 let got = ResponseCodec::default().decode(test);
753 dbg!((std::str::from_utf8(test).unwrap(), &expected, &got));
754 assert_eq!(expected, got);
755
756 {
757 let got = ResponseCodec::default().decode_static(test);
758 assert_eq!(expected, got);
759 }
760 }
761 }
762}