Repository: duesee/imap-codec (language: python)

Issue:
docs: `AuthMechanism::Plain` has wrong order of authzid/authcid
```
base64(b"<authenticate-id>\x00<authorize-id>\x00<password>")
```

-> 

```
base64(b"<authorization identity>\x00<authentication identity>\x00<password>")
```

```abnf
message   = [authzid] UTF8NUL authcid UTF8NUL passwd
authcid   = 1*SAFE ; MUST accept up to 255 octets
authzid   = 1*SAFE ; MUST accept up to 255 octets
passwd    = 1*SAFE ; MUST accept up to 255 octets
UTF8NUL   = %x00 ; [UTF-8](https://datatracker.ietf.org/doc/html/rfc4616#ref-UTF-8) encoded NUL character

SAFE      = UTF1 / UTF2 / UTF3 / UTF4
               ;; any UTF-8 encoded [Unicode](https://datatracker.ietf.org/doc/html/rfc4616#ref-Unicode) character except NUL

UTF1      = %x01-7F ;; except NUL
UTF2      = %xC2-DF UTF0
UTF3      = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) / %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
UTF4      = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) / %xF4 %x80-8F 2(UTF0)
UTF0      = %x80-BF
```

> The authorization identity (authzid), authentication identity
> (authcid), password (passwd), and NUL character deliminators SHALL be
> transferred as [UTF-8] encoded strings of [Unicode] characters.


Discussion / hints:

Fix patch:
diff --git a/imap-codec/src/codec.rs b/imap-codec/src/codec.rs
index 9b169a9d..427d76ff 100644
--- a/imap-codec/src/codec.rs
+++ b/imap-codec/src/codec.rs
@@ -55,6 +55,7 @@ mod tests {
         auth::AuthenticateData,
         command::{Command, CommandBody},
         core::{IString, Literal, LiteralMode, NString, NonEmptyVec, Tag},
+        extensions::idle::IdleDone,
         fetch::MessageDataItem,
         mailbox::Mailbox,
         response::{Data, Greeting, GreetingKind, Response},
@@ -65,8 +66,8 @@ mod tests {
     use crate::{
         decode::{CommandDecodeError, Decoder, GreetingDecodeError, ResponseDecodeError},
         testing::{
-            kat_inverse_authenticate_data, kat_inverse_command, kat_inverse_greeting,
-            kat_inverse_response,
+            kat_inverse_authenticate_data, kat_inverse_command, kat_inverse_done,
+            kat_inverse_greeting, kat_inverse_response,
         },
     };
 
@@ -164,6 +165,14 @@ mod tests {
         )]);
     }
 
+    #[test]
+    fn test_kat_inverse_done() {
+        kat_inverse_done(&[
+            (b"done\r\n".as_ref(), b"".as_ref(), IdleDone),
+            (b"DONE\r\n".as_ref(), b"".as_ref(), IdleDone),
+        ]);
+    }
+
     #[test]
     fn test_greeting_incomplete_failed() {
         let tests = [
diff --git a/imap-types/src/auth.rs b/imap-types/src/auth.rs
index 618f98eb..ba42a916 100644
--- a/imap-types/src/auth.rs
+++ b/imap-types/src/auth.rs
@@ -30,7 +30,7 @@ pub enum AuthMechanism<'a> {
     /// ```
     ///
     /// ```text
-    /// base64(b"<authenticate-id>\x00<authorize-id>\x00<password>")
+    /// base64(b"<authorization identity>\x00<authentication identity>\x00<password>")
     /// ```
     ///
     /// # Reference(s):
@@ -92,12 +92,18 @@ impl<'a> From<Atom<'a>> for AuthMechanism<'a> {
 
 impl<'a> Display for AuthMechanism<'a> {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        f.write_str(match self {
+        f.write_str(self.as_ref())
+    }
+}
+
+impl<'a> AsRef<str> for AuthMechanism<'a> {
+    fn as_ref(&self) -> &str {
+        match self {
             Self::Plain => "PLAIN",
             Self::Login => "LOGIN",
             Self::XOAuth2 => "XOAUTH2",
             Self::Other(other) => other.0.as_ref(),
-        })
+        }
     }
 }
 


Test patch:
diff --git a/imap-codec/src/testing.rs b/imap-codec/src/testing.rs
index d9e3d07a..1c9bf543 100644
--- a/imap-codec/src/testing.rs
+++ b/imap-codec/src/testing.rs
@@ -3,6 +3,7 @@ use std::fmt::Debug;
 use imap_types::{
     auth::AuthenticateData,
     command::Command,
+    extensions::idle::IdleDone,
     response::{Greeting, Response},
     utils::escape_byte_string,
 };
@@ -10,7 +11,7 @@ use imap_types::{
 use crate::{
     decode::{Decoder, IMAPResult},
     encode::{EncodeContext, EncodeIntoContext},
-    AuthenticateDataCodec, CommandCodec, GreetingCodec, ResponseCodec,
+    AuthenticateDataCodec, CommandCodec, GreetingCodec, IdleDoneCodec, ResponseCodec,
 };
 
 pub(crate) fn known_answer_test_encode(
@@ -81,6 +82,7 @@ impl_kat_inverse! {kat_inverse_command, CommandCodec, Command}
 impl_kat_inverse! {kat_inverse_response, ResponseCodec, Response}
 //impl_kat_inverse! {kat_inverse_continue, ContinueCodec, Continue}
 impl_kat_inverse! {kat_inverse_authenticate_data, AuthenticateDataCodec, AuthenticateData}
+impl_kat_inverse! {kat_inverse_done, IdleDoneCodec, IdleDone}
 
 #[cfg(test)]
 mod tests {