@@ -10,7 +10,7 @@ use async_std::io::{Read, Write, WriteExt};
1010use base64:: Engine as _;
1111use extensions:: id:: { format_identification, parse_id} ;
1212use extensions:: quota:: parse_get_quota_root;
13- use futures:: { io, Stream , StreamExt } ;
13+ use futures:: { io, Stream , TryStreamExt } ;
1414use imap_proto:: { Metadata , RequestId , Response } ;
1515#[ cfg( feature = "runtime-tokio" ) ]
1616use tokio:: io:: { AsyncRead as Read , AsyncWrite as Write , AsyncWriteExt } ;
@@ -122,7 +122,7 @@ macro_rules! ok_or_unauth_client_err {
122122 ( $r: expr, $self: expr) => {
123123 match $r {
124124 Ok ( o) => o,
125- Err ( e) => return Err ( ( e, $self) ) ,
125+ Err ( e) => return Err ( ( e. into ( ) , $self) ) ,
126126 }
127127 } ;
128128}
@@ -262,42 +262,37 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Client<T> {
262262 // explicit match blocks neccessary to convert error to tuple and not bind self too
263263 // early (see also comment on `login`)
264264 loop {
265- if let Some ( res) = self . read_response ( ) . await {
266- let res = ok_or_unauth_client_err ! ( res. map_err( Into :: into) , self ) ;
267- match res. parsed ( ) {
268- Response :: Continue { information, .. } => {
269- let challenge = if let Some ( text) = information {
270- ok_or_unauth_client_err ! (
271- base64:: engine:: general_purpose:: STANDARD
272- . decode( text. as_ref( ) )
273- . map_err( |e| Error :: Parse ( ParseError :: Authentication (
274- ( * text) . to_string( ) ,
275- Some ( e)
276- ) ) ) ,
277- self
278- )
279- } else {
280- Vec :: new ( )
281- } ;
282- let raw_response = & mut authenticator. process ( & challenge) ;
283- let auth_response =
284- base64:: engine:: general_purpose:: STANDARD . encode ( raw_response) ;
285-
286- ok_or_unauth_client_err ! (
287- self . conn. run_command_untagged( & auth_response) . await ,
288- self
289- ) ;
290- }
291- _ => {
265+ let Some ( res) = ok_or_unauth_client_err ! ( self . read_response( ) . await , self ) else {
266+ return Err ( ( Error :: ConnectionLost , self ) ) ;
267+ } ;
268+ match res. parsed ( ) {
269+ Response :: Continue { information, .. } => {
270+ let challenge = if let Some ( text) = information {
292271 ok_or_unauth_client_err ! (
293- self . check_done_ok_from( & id, None , res) . await ,
272+ base64:: engine:: general_purpose:: STANDARD
273+ . decode( text. as_ref( ) )
274+ . map_err( |e| Error :: Parse ( ParseError :: Authentication (
275+ ( * text) . to_string( ) ,
276+ Some ( e)
277+ ) ) ) ,
294278 self
295- ) ;
296- return Ok ( Session :: new ( self . conn ) ) ;
297- }
279+ )
280+ } else {
281+ Vec :: new ( )
282+ } ;
283+ let raw_response = & mut authenticator. process ( & challenge) ;
284+ let auth_response =
285+ base64:: engine:: general_purpose:: STANDARD . encode ( raw_response) ;
286+
287+ ok_or_unauth_client_err ! (
288+ self . conn. run_command_untagged( & auth_response) . await ,
289+ self
290+ ) ;
291+ }
292+ _ => {
293+ ok_or_unauth_client_err ! ( self . check_done_ok_from( & id, None , res) . await , self ) ;
294+ return Ok ( Session :: new ( self . conn ) ) ;
298295 }
299- } else {
300- return Err ( ( Error :: ConnectionLost , self ) ) ;
301296 }
302297 }
303298 }
@@ -975,12 +970,13 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
975970 mailbox_pattern. unwrap_or( "\" \" " )
976971 ) )
977972 . await ?;
978-
979- Ok ( parse_names (
973+ let names = parse_names (
980974 & mut self . conn . stream ,
981975 self . unsolicited_responses_tx . clone ( ) ,
982976 id,
983- ) )
977+ ) ;
978+
979+ Ok ( names)
984980 }
985981
986982 /// The [`LSUB` command](https://tools.ietf.org/html/rfc3501#section-6.3.9) returns a subset of
@@ -1136,23 +1132,20 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
11361132 ) )
11371133 . await ?;
11381134
1139- match self . read_response ( ) . await {
1140- Some ( Ok ( res) ) => {
1141- if let Response :: Continue { .. } = res. parsed ( ) {
1142- self . stream . as_mut ( ) . write_all ( content) . await ?;
1143- self . stream . as_mut ( ) . write_all ( b"\r \n " ) . await ?;
1144- self . stream . flush ( ) . await ?;
1145- self . conn
1146- . check_done_ok ( & id, Some ( self . unsolicited_responses_tx . clone ( ) ) )
1147- . await ?;
1148- Ok ( ( ) )
1149- } else {
1150- Err ( Error :: Append )
1151- }
1152- }
1153- Some ( Err ( err) ) => Err ( err. into ( ) ) ,
1154- _ => Err ( Error :: Append ) ,
1155- }
1135+ let Some ( res) = self . read_response ( ) . await ? else {
1136+ return Err ( Error :: Append ) ;
1137+ } ;
1138+ let Response :: Continue { .. } = res. parsed ( ) else {
1139+ return Err ( Error :: Append ) ;
1140+ } ;
1141+
1142+ self . stream . as_mut ( ) . write_all ( content) . await ?;
1143+ self . stream . as_mut ( ) . write_all ( b"\r \n " ) . await ?;
1144+ self . stream . flush ( ) . await ?;
1145+ self . conn
1146+ . check_done_ok ( & id, Some ( self . unsolicited_responses_tx . clone ( ) ) )
1147+ . await ?;
1148+ Ok ( ( ) )
11561149 }
11571150
11581151 /// The [`SEARCH` command](https://tools.ietf.org/html/rfc3501#section-6.4.4) searches the
@@ -1352,7 +1345,7 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Session<T> {
13521345 }
13531346
13541347 /// Read the next response on the connection.
1355- pub async fn read_response ( & mut self ) -> Option < io:: Result < ResponseData > > {
1348+ pub async fn read_response ( & mut self ) -> io:: Result < Option < ResponseData > > {
13561349 self . conn . read_response ( ) . await
13571350 }
13581351}
@@ -1377,8 +1370,8 @@ impl<T: Read + Write + Unpin + fmt::Debug> Connection<T> {
13771370 }
13781371
13791372 /// Read the next response on the connection.
1380- pub async fn read_response ( & mut self ) -> Option < io:: Result < ResponseData > > {
1381- self . stream . next ( ) . await
1373+ pub async fn read_response ( & mut self ) -> io:: Result < Option < ResponseData > > {
1374+ self . stream . try_next ( ) . await
13821375 }
13831376
13841377 pub ( crate ) async fn run_command_untagged ( & mut self , command : & str ) -> Result < ( ) > {
@@ -1415,8 +1408,8 @@ impl<T: Read + Write + Unpin + fmt::Debug> Connection<T> {
14151408 id : & RequestId ,
14161409 unsolicited : Option < channel:: Sender < UnsolicitedResponse > > ,
14171410 ) -> Result < ( ) > {
1418- if let Some ( first_res) = self . stream . next ( ) . await {
1419- self . check_done_ok_from ( id, unsolicited, first_res? ) . await
1411+ if let Some ( first_res) = self . stream . try_next ( ) . await ? {
1412+ self . check_done_ok_from ( id, unsolicited, first_res) . await
14201413 } else {
14211414 Err ( Error :: ConnectionLost )
14221415 }
@@ -1447,11 +1440,10 @@ impl<T: Read + Write + Unpin + fmt::Debug> Connection<T> {
14471440 handle_unilateral ( response, unsolicited) ;
14481441 }
14491442
1450- if let Some ( res) = self . stream . next ( ) . await {
1451- response = res?;
1452- } else {
1443+ let Some ( res) = self . stream . try_next ( ) . await ? else {
14531444 return Err ( Error :: ConnectionLost ) ;
1454- }
1445+ } ;
1446+ response = res;
14551447 }
14561448 }
14571449
@@ -1495,6 +1487,7 @@ mod tests {
14951487 use std:: future:: Future ;
14961488
14971489 use async_std:: sync:: { Arc , Mutex } ;
1490+ use futures:: StreamExt ;
14981491 use imap_proto:: Status ;
14991492
15001493 macro_rules! mock_client {
@@ -1555,7 +1548,7 @@ mod tests {
15551548 async fn readline_eof ( ) {
15561549 let mock_stream = MockStream :: default ( ) . with_eof ( ) ;
15571550 let mut client = mock_client ! ( mock_stream) ;
1558- let res = client. read_response ( ) . await ;
1551+ let res = client. read_response ( ) . await . unwrap ( ) ;
15591552 assert ! ( res. is_none( ) ) ;
15601553 }
15611554
@@ -2117,7 +2110,7 @@ mod tests {
21172110 . unwrap ( ) ;
21182111
21192112 // Unexpected EOF.
2120- let err = fetch_result. next ( ) . await . unwrap ( ) . unwrap_err ( ) ;
2113+ let err = fetch_result. try_next ( ) . await . unwrap_err ( ) ;
21212114 let Error :: Io ( io_err) = err else {
21222115 panic ! ( "Unexpected error type: {err}" )
21232116 } ;
0 commit comments