@@ -8,7 +8,7 @@ use std::str;
88use std:: sync:: mpsc;
99
1010use super :: authenticator:: Authenticator ;
11- use super :: error:: { Bad , Error , No , ParseError , Result , ValidateError } ;
11+ use super :: error:: { Bad , Bye , Error , No , ParseError , Result , ValidateError } ;
1212use super :: extensions;
1313use super :: parse:: * ;
1414use super :: types:: * ;
@@ -609,7 +609,18 @@ impl<T: Read + Write> Session<T> {
609609
610610 /// Logout informs the server that the client is done with the connection.
611611 pub fn logout ( & mut self ) -> Result < ( ) > {
612- self . run_command_and_check_ok ( "LOGOUT" )
612+ // Check for OK or BYE.
613+ // According to the RFC:
614+ // https://datatracker.ietf.org/doc/html/rfc3501#section-6.1.3
615+ // We should get an untagged BYE and a tagged OK.
616+ // Apparently some servers send a tagged BYE (imap.wp.pl #210)
617+ // instead, so we just treat it like OK since we are logging out
618+ // anyway and this avoids returning an error on logout.
619+ match self . run_command_and_check_ok ( "LOGOUT" ) {
620+ Ok ( _) => Ok ( ( ) ) ,
621+ Err ( Error :: Bye ( _) ) => Ok ( ( ) ) ,
622+ resp => resp,
623+ }
613624 }
614625
615626 /// The [`CREATE` command](https://tools.ietf.org/html/rfc3501#section-6.3.3) creates a mailbox
@@ -1337,7 +1348,7 @@ impl<T: Read + Write> Connection<T> {
13371348 ) ) => {
13381349 assert_eq ! ( tag. as_bytes( ) , match_tag. as_bytes( ) ) ;
13391350 Some ( match status {
1340- Status :: Bad | Status :: No => Err ( (
1351+ Status :: Bad | Status :: No | Status :: Bye => Err ( (
13411352 status,
13421353 information. map ( |v| v. into_owned ( ) ) ,
13431354 code. map ( |v| v. into_owned ( ) ) ,
@@ -1376,6 +1387,13 @@ impl<T: Read + Write> Connection<T> {
13761387 . unwrap_or_else ( || "no explanation given" . to_string ( ) ) ,
13771388 } ) ) ;
13781389 }
1390+ Status :: Bye => {
1391+ break Err ( Error :: Bye ( Bye {
1392+ code,
1393+ information : expl
1394+ . unwrap_or_else ( || "no explanation given" . to_string ( ) ) ,
1395+ } ) ) ;
1396+ }
13791397 _ => break Err ( Error :: Parse ( ParseError :: Invalid ( data. split_off ( 0 ) ) ) ) ,
13801398 }
13811399 }
@@ -1570,6 +1588,32 @@ mod tests {
15701588 ) ;
15711589 }
15721590
1591+ #[ test]
1592+ fn logout_with_untagged_bye ( ) {
1593+ let response = b"* BYE Logging out\r \n a1 OK Logout completed.\r \n " . to_vec ( ) ;
1594+ let command = format ! ( "a1 LOGOUT\r \n " ) ;
1595+ let mock_stream = MockStream :: new ( response) ;
1596+ let mut session = mock_session ! ( mock_stream) ;
1597+ session. logout ( ) . unwrap ( ) ;
1598+ assert ! (
1599+ session. stream. get_ref( ) . written_buf == command. as_bytes( ) . to_vec( ) ,
1600+ "Invalid logout command"
1601+ ) ;
1602+ }
1603+
1604+ #[ test]
1605+ fn logout_with_tagged_bye ( ) {
1606+ let response = b"a1 BYE IMAP4rev1 Server logging out\r \n " . to_vec ( ) ;
1607+ let command = format ! ( "a1 LOGOUT\r \n " ) ;
1608+ let mock_stream = MockStream :: new ( response) ;
1609+ let mut session = mock_session ! ( mock_stream) ;
1610+ session. logout ( ) . unwrap ( ) ;
1611+ assert ! (
1612+ session. stream. get_ref( ) . written_buf == command. as_bytes( ) . to_vec( ) ,
1613+ "Invalid logout command"
1614+ ) ;
1615+ }
1616+
15731617 #[ test]
15741618 fn rename ( ) {
15751619 let response = b"a1 OK RENAME completed\r \n " . to_vec ( ) ;
0 commit comments