@@ -64,10 +64,6 @@ pub struct Client<T: Read + Write + Unpin + fmt::Debug> {
64
64
pub struct Connection < T : Read + Write + Unpin + fmt:: Debug > {
65
65
pub ( crate ) stream : ImapStream < T > ,
66
66
67
- /// Enable debug mode for this connection so that all client-server interactions are printed to
68
- /// `STDERR`.
69
- pub debug : bool ,
70
-
71
67
/// Manages the request ids.
72
68
pub ( crate ) request_ids : IdGenerator ,
73
69
}
@@ -192,7 +188,6 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Client<T> {
192
188
Client {
193
189
conn : Connection {
194
190
stream,
195
- debug : false ,
196
191
request_ids : IdGenerator :: new ( ) ,
197
192
} ,
198
193
}
@@ -260,9 +255,9 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Client<T> {
260
255
/// access_token: String,
261
256
/// }
262
257
///
263
- /// impl async_imap::Authenticator for OAuth2 {
258
+ /// impl async_imap::Authenticator for & OAuth2 {
264
259
/// type Response = String;
265
- /// fn process(&self, _: &[u8]) -> Self::Response {
260
+ /// fn process(&mut self, _: &[u8]) -> Self::Response {
266
261
/// format!(
267
262
/// "user={}\x01auth=Bearer {}\x01\x01",
268
263
/// self.user, self.access_token
@@ -297,60 +292,59 @@ impl<T: Read + Write + Unpin + fmt::Debug + Send> Client<T> {
297
292
pub async fn authenticate < A : Authenticator , S : AsRef < str > > (
298
293
mut self ,
299
294
auth_type : S ,
300
- authenticator : & A ,
295
+ authenticator : A ,
301
296
) -> :: std:: result:: Result < Session < T > , ( Error , Client < T > ) > {
302
- ok_or_unauth_client_err ! (
297
+ let id = ok_or_unauth_client_err ! (
303
298
self . run_command( & format!( "AUTHENTICATE {}" , auth_type. as_ref( ) ) )
304
299
. await ,
305
300
self
306
301
) ;
307
- let session = self . do_auth_handshake ( authenticator) . await ?;
308
-
302
+ let session = self . do_auth_handshake ( id, authenticator) . await ?;
309
303
Ok ( session)
310
304
}
311
305
312
306
/// This func does the handshake process once the authenticate command is made.
313
307
async fn do_auth_handshake < A : Authenticator > (
314
308
mut self ,
315
- authenticator : & A ,
309
+ id : RequestId ,
310
+ mut authenticator : A ,
316
311
) -> :: std:: result:: Result < Session < T > , ( Error , Client < T > ) > {
317
312
// explicit match blocks neccessary to convert error to tuple and not bind self too
318
313
// early (see also comment on `login`)
319
- if let Some ( res) = self . read_response ( ) . await {
320
- // FIXME: Some servers will only send `+\r\n` need to handle that in imap_proto.
321
- // https://github.com/djc/tokio-imap/issues/67
322
- let res = ok_or_unauth_client_err ! ( res. map_err( Into :: into) , self ) ;
323
- match res. parsed ( ) {
324
- Response :: Continue { information, .. } => {
325
- let challenge = if let Some ( text) = information {
314
+ loop {
315
+ if let Some ( res) = self . read_response ( ) . await {
316
+ let res = ok_or_unauth_client_err ! ( res. map_err( Into :: into) , self ) ;
317
+ match res. parsed ( ) {
318
+ Response :: Continue { information, .. } => {
319
+ let challenge = if let Some ( text) = information {
320
+ ok_or_unauth_client_err ! (
321
+ base64:: decode( text) . map_err( |e| Error :: Parse (
322
+ ParseError :: Authentication ( ( * text) . to_string( ) , Some ( e) )
323
+ ) ) ,
324
+ self
325
+ )
326
+ } else {
327
+ Vec :: new ( )
328
+ } ;
329
+ let raw_response = & mut authenticator. process ( & challenge) ;
330
+ let auth_response = base64:: encode ( raw_response) ;
331
+
326
332
ok_or_unauth_client_err ! (
327
- base64:: decode( text) . map_err( |e| Error :: Parse (
328
- ParseError :: Authentication ( ( * text) . to_string( ) , Some ( e) )
329
- ) ) ,
333
+ self . conn. run_command_untagged( & auth_response) . await ,
330
334
self
331
- )
332
- } else {
333
- Vec :: new ( )
334
- } ;
335
- let raw_response = & authenticator. process ( & challenge) ;
336
- let auth_response = base64:: encode ( raw_response) ;
337
-
338
- ok_or_unauth_client_err ! (
339
- self . conn. run_command_untagged( & auth_response) . await ,
340
- self
341
- ) ;
342
- Ok ( Session :: new ( self . conn ) )
343
- }
344
- _ => {
345
- if self . read_response ( ) . await . is_some ( ) {
346
- Ok ( Session :: new ( self . conn ) )
347
- } else {
348
- Err ( ( Error :: ConnectionLost , self ) )
335
+ ) ;
336
+ }
337
+ _ => {
338
+ ok_or_unauth_client_err ! (
339
+ self . check_done_ok_from( & id, None , res) . await ,
340
+ self
341
+ ) ;
342
+ return Ok ( Session :: new ( self . conn ) ) ;
349
343
}
350
344
}
345
+ } else {
346
+ return Err ( ( Error :: ConnectionLost , self ) ) ;
351
347
}
352
- } else {
353
- Err ( ( Error :: ConnectionLost , self ) )
354
348
}
355
349
}
356
350
}
@@ -1322,63 +1316,81 @@ impl<T: Read + Write + Unpin + fmt::Debug> Connection<T> {
1322
1316
unsolicited : Option < sync:: Sender < UnsolicitedResponse > > ,
1323
1317
) -> Result < ( ) > {
1324
1318
let id = self . run_command ( command) . await ?;
1325
- self . check_ok ( id, unsolicited) . await ?;
1319
+ self . check_done_ok ( & id, unsolicited) . await ?;
1326
1320
1327
1321
Ok ( ( ) )
1328
1322
}
1329
1323
1330
- pub ( crate ) async fn check_ok (
1324
+ pub ( crate ) async fn check_done_ok (
1331
1325
& mut self ,
1332
- id : RequestId ,
1326
+ id : & RequestId ,
1327
+ unsolicited : Option < sync:: Sender < UnsolicitedResponse > > ,
1328
+ ) -> Result < ( ) > {
1329
+ if let Some ( first_res) = self . stream . next ( ) . await {
1330
+ self . check_done_ok_from ( id, unsolicited, first_res?) . await
1331
+ } else {
1332
+ Err ( Error :: ConnectionLost )
1333
+ }
1334
+ }
1335
+
1336
+ pub ( crate ) async fn check_done_ok_from (
1337
+ & mut self ,
1338
+ id : & RequestId ,
1333
1339
unsolicited : Option < sync:: Sender < UnsolicitedResponse > > ,
1340
+ mut response : ResponseData ,
1334
1341
) -> Result < ( ) > {
1335
- while let Some ( res) = self . stream . next ( ) . await {
1336
- let res = res?;
1342
+ loop {
1337
1343
if let Response :: Done {
1338
1344
status,
1339
1345
code,
1340
1346
information,
1341
1347
tag,
1342
- } = res . parsed ( )
1348
+ } = response . parsed ( )
1343
1349
{
1344
- use imap_proto:: Status ;
1345
- match status {
1346
- Status :: Ok => {
1347
- if tag != & id {
1348
- if let Some ( unsolicited) = unsolicited. clone ( ) {
1349
- handle_unilateral ( res, unsolicited) . await ;
1350
- }
1351
- continue ;
1352
- }
1353
-
1354
- return Ok ( ( ) ) ;
1355
- }
1356
- Status :: Bad => {
1357
- return Err ( Error :: Bad ( format ! (
1358
- "code: {:?}, info: {:?}" ,
1359
- code, information
1360
- ) ) )
1361
- }
1362
- Status :: No => {
1363
- return Err ( Error :: No ( format ! (
1364
- "code: {:?}, info: {:?}" ,
1365
- code, information
1366
- ) ) )
1367
- }
1368
- _ => {
1369
- return Err ( Error :: Io ( io:: Error :: new (
1370
- io:: ErrorKind :: Other ,
1371
- format ! (
1372
- "status: {:?}, code: {:?}, information: {:?}" ,
1373
- status, code, information
1374
- ) ,
1375
- ) ) ) ;
1376
- }
1350
+ self . check_status_ok ( status, code. as_ref ( ) , * information) ?;
1351
+
1352
+ if tag == id {
1353
+ return Ok ( ( ) ) ;
1377
1354
}
1378
1355
}
1356
+
1357
+ if let Some ( unsolicited) = unsolicited. clone ( ) {
1358
+ handle_unilateral ( response, unsolicited) . await ;
1359
+ }
1360
+
1361
+ if let Some ( res) = self . stream . next ( ) . await {
1362
+ response = res?;
1363
+ } else {
1364
+ return Err ( Error :: ConnectionLost ) ;
1365
+ }
1379
1366
}
1367
+ }
1380
1368
1381
- Err ( Error :: ConnectionLost )
1369
+ pub ( crate ) fn check_status_ok (
1370
+ & self ,
1371
+ status : & imap_proto:: Status ,
1372
+ code : Option < & imap_proto:: ResponseCode < ' _ > > ,
1373
+ information : Option < & str > ,
1374
+ ) -> Result < ( ) > {
1375
+ use imap_proto:: Status ;
1376
+ match status {
1377
+ Status :: Ok => Ok ( ( ) ) ,
1378
+ Status :: Bad => Err ( Error :: Bad ( format ! (
1379
+ "code: {:?}, info: {:?}" ,
1380
+ code, information
1381
+ ) ) ) ,
1382
+ Status :: No => Err ( Error :: No ( format ! (
1383
+ "code: {:?}, info: {:?}" ,
1384
+ code, information
1385
+ ) ) ) ,
1386
+ _ => Err ( Error :: Io ( io:: Error :: new (
1387
+ io:: ErrorKind :: Other ,
1388
+ format ! (
1389
+ "status: {:?}, code: {:?}, information: {:?}" ,
1390
+ status, code, information
1391
+ ) ,
1392
+ ) ) ) ,
1393
+ }
1382
1394
}
1383
1395
}
1384
1396
@@ -1484,9 +1496,9 @@ mod tests {
1484
1496
enum Authenticate {
1485
1497
Auth ,
1486
1498
} ;
1487
- impl Authenticator for Authenticate {
1499
+ impl Authenticator for & Authenticate {
1488
1500
type Response = Vec < u8 > ;
1489
- fn process ( & self , challenge : & [ u8 ] ) -> Self :: Response {
1501
+ fn process ( & mut self , challenge : & [ u8 ] ) -> Self :: Response {
1490
1502
assert ! ( challenge == b"bar" , "Invalid authenticate challenge" ) ;
1491
1503
b"foo" . to_vec ( )
1492
1504
}
@@ -1525,7 +1537,7 @@ mod tests {
1525
1537
#[ async_std:: test]
1526
1538
async fn logout ( ) {
1527
1539
let response = b"A0001 OK Logout completed.\r \n " . to_vec ( ) ;
1528
- let command = format ! ( "A0001 LOGOUT\r \n " ) ;
1540
+ let command = "A0001 LOGOUT\r \n " ;
1529
1541
let mock_stream = MockStream :: new ( response) ;
1530
1542
let mut session = mock_session ! ( mock_stream) ;
1531
1543
session. logout ( ) . await . unwrap ( ) ;
@@ -2027,7 +2039,7 @@ mod tests {
2027
2039
#[ test]
2028
2040
fn validate_newline ( ) {
2029
2041
if let Err ( ref e) = validate_str ( "test\n string" ) {
2030
- if let & Error :: Validate ( ref ve) = e {
2042
+ if let Error :: Validate ( ref ve) = e {
2031
2043
if ve. 0 == '\n' {
2032
2044
return ;
2033
2045
}
@@ -2041,7 +2053,7 @@ mod tests {
2041
2053
#[ allow( unreachable_patterns) ]
2042
2054
fn validate_carriage_return ( ) {
2043
2055
if let Err ( ref e) = validate_str ( "test\r string" ) {
2044
- if let & Error :: Validate ( ref ve) = e {
2056
+ if let Error :: Validate ( ref ve) = e {
2045
2057
if ve. 0 == '\r' {
2046
2058
return ;
2047
2059
}
0 commit comments