@@ -3,10 +3,10 @@ use bufstream::BufStream;
3
3
use chrono:: { DateTime , FixedOffset } ;
4
4
use imap_proto:: Response ;
5
5
use std:: collections:: HashSet ;
6
+ use std:: collections:: VecDeque ;
6
7
use std:: io:: { Read , Write } ;
7
8
use std:: ops:: { Deref , DerefMut } ;
8
9
use std:: str;
9
- use std:: sync:: mpsc;
10
10
11
11
use super :: authenticator:: Authenticator ;
12
12
use super :: error:: { Bad , Bye , Error , No , ParseError , Result , TagMismatch , ValidateError } ;
@@ -141,11 +141,9 @@ fn validate_sequence_set(
141
141
#[ derive( Debug ) ]
142
142
pub struct Session < T : Read + Write > {
143
143
conn : Connection < T > ,
144
- pub ( crate ) unsolicited_responses_tx : mpsc:: Sender < UnsolicitedResponse > ,
145
-
146
144
/// Server responses that are not related to the current command. See also the note on
147
145
/// [unilateral server responses in RFC 3501](https://tools.ietf.org/html/rfc3501#section-7).
148
- pub unsolicited_responses : mpsc :: Receiver < UnsolicitedResponse > ,
146
+ pub ( crate ) unsolicited_responses : VecDeque < UnsolicitedResponse > ,
149
147
}
150
148
151
149
/// An (unauthenticated) handle to talk to an IMAP server. This is what you get when first
@@ -262,7 +260,7 @@ impl<'a, T: Read + Write> AppendCmd<'a, T> {
262
260
self . session . stream . flush ( ) ?;
263
261
self . session
264
262
. read_response ( )
265
- . and_then ( |( lines, _) | parse_append ( & lines, & mut self . session . unsolicited_responses_tx ) )
263
+ . and_then ( |( lines, _) | parse_append ( & lines, & mut self . session . unsolicited_responses ) )
266
264
}
267
265
}
268
266
@@ -370,10 +368,10 @@ impl<T: Read + Write> Client<T> {
370
368
///
371
369
/// This allows reading capabilities before authentication.
372
370
pub fn capabilities ( & mut self ) -> Result < Capabilities > {
373
- // Create a temporary channel as we do not care about out of band responses before login
374
- let ( mut tx , _rx ) = mpsc :: channel ( ) ;
371
+ // Create a temporary vec deque as we do not care about out of band responses before login
372
+ let mut unsolicited_responses = VecDeque :: new ( ) ;
375
373
self . run_command_and_read_response ( "CAPABILITY" )
376
- . and_then ( |lines| Capabilities :: parse ( lines, & mut tx ) )
374
+ . and_then ( |lines| Capabilities :: parse ( lines, & mut unsolicited_responses ) )
377
375
}
378
376
379
377
/// Log in to the IMAP server. Upon success a [`Session`](struct.Session.html) instance is
@@ -530,14 +528,17 @@ impl<T: Read + Write> Client<T> {
530
528
impl < T : Read + Write > Session < T > {
531
529
// not public, just to avoid duplicating the channel creation code
532
530
fn new ( conn : Connection < T > ) -> Self {
533
- let ( tx, rx) = mpsc:: channel ( ) ;
534
531
Session {
535
532
conn,
536
- unsolicited_responses : rx,
537
- unsolicited_responses_tx : tx,
533
+ unsolicited_responses : VecDeque :: new ( ) ,
538
534
}
539
535
}
540
536
537
+ /// Takes all the unsolicited responses received thus far.
538
+ pub fn take_all_unsolicited ( & mut self ) -> impl ExactSizeIterator < Item = UnsolicitedResponse > {
539
+ std:: mem:: take ( & mut self . unsolicited_responses ) . into_iter ( )
540
+ }
541
+
541
542
/// Selects a mailbox
542
543
///
543
544
/// The `SELECT` command selects a mailbox so that messages in the mailbox can be accessed.
@@ -561,7 +562,7 @@ impl<T: Read + Write> Session<T> {
561
562
"SELECT {}" ,
562
563
validate_str( "SELECT" , "mailbox" , mailbox_name. as_ref( ) ) ?
563
564
) )
564
- . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses_tx ) )
565
+ . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses ) )
565
566
}
566
567
567
568
/// The `EXAMINE` command is identical to [`Session::select`] and returns the same output;
@@ -573,7 +574,7 @@ impl<T: Read + Write> Session<T> {
573
574
"EXAMINE {}" ,
574
575
validate_str( "EXAMINE" , "mailbox" , mailbox_name. as_ref( ) ) ?
575
576
) )
576
- . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses_tx ) )
577
+ . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses ) )
577
578
}
578
579
579
580
/// Fetch retrieves data associated with a set of messages in the mailbox.
@@ -640,15 +641,15 @@ impl<T: Read + Write> Session<T> {
640
641
query : impl AsRef < str > ,
641
642
) -> Result < Fetches > {
642
643
if sequence_set. as_ref ( ) . is_empty ( ) {
643
- Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses_tx )
644
+ Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses )
644
645
} else {
645
646
let synopsis = "FETCH" ;
646
647
self . run_command_and_read_response ( & format ! (
647
648
"FETCH {} {}" ,
648
649
validate_sequence_set( synopsis, "seq" , sequence_set. as_ref( ) ) ?,
649
650
validate_str_noquote( synopsis, "query" , query. as_ref( ) ) ?
650
651
) )
651
- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
652
+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
652
653
}
653
654
}
654
655
@@ -660,22 +661,22 @@ impl<T: Read + Write> Session<T> {
660
661
query : impl AsRef < str > ,
661
662
) -> Result < Fetches > {
662
663
if uid_set. as_ref ( ) . is_empty ( ) {
663
- Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses_tx )
664
+ Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses )
664
665
} else {
665
666
let synopsis = "UID FETCH" ;
666
667
self . run_command_and_read_response ( & format ! (
667
668
"UID FETCH {} {}" ,
668
669
validate_sequence_set( synopsis, "seq" , uid_set. as_ref( ) ) ?,
669
670
validate_str_noquote( synopsis, "query" , query. as_ref( ) ) ?
670
671
) )
671
- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
672
+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
672
673
}
673
674
}
674
675
675
676
/// Noop always succeeds, and it does nothing.
676
677
pub fn noop ( & mut self ) -> Result < ( ) > {
677
678
self . run_command_and_read_response ( "NOOP" )
678
- . and_then ( |lines| parse_noop ( lines, & mut self . unsolicited_responses_tx ) )
679
+ . and_then ( |lines| parse_noop ( lines, & mut self . unsolicited_responses ) )
679
680
}
680
681
681
682
/// Logout informs the server that the client is done with the connection.
@@ -807,7 +808,7 @@ impl<T: Read + Write> Session<T> {
807
808
/// one of the listed capabilities. See [`Capabilities`] for further details.
808
809
pub fn capabilities ( & mut self ) -> Result < Capabilities > {
809
810
self . run_command_and_read_response ( "CAPABILITY" )
810
- . and_then ( |lines| Capabilities :: parse ( lines, & mut self . unsolicited_responses_tx ) )
811
+ . and_then ( |lines| Capabilities :: parse ( lines, & mut self . unsolicited_responses ) )
811
812
}
812
813
813
814
/// The [`EXPUNGE` command](https://tools.ietf.org/html/rfc3501#section-6.4.3) permanently
@@ -816,7 +817,7 @@ impl<T: Read + Write> Session<T> {
816
817
pub fn expunge ( & mut self ) -> Result < Deleted > {
817
818
self . run_command ( "EXPUNGE" ) ?;
818
819
self . read_response ( )
819
- . and_then ( |( lines, _) | parse_expunge ( lines, & mut self . unsolicited_responses_tx ) )
820
+ . and_then ( |( lines, _) | parse_expunge ( lines, & mut self . unsolicited_responses ) )
820
821
}
821
822
822
823
/// The [`UID EXPUNGE` command](https://tools.ietf.org/html/rfc4315#section-2.1) permanently
@@ -844,7 +845,7 @@ impl<T: Read + Write> Session<T> {
844
845
pub fn uid_expunge ( & mut self , uid_set : impl AsRef < str > ) -> Result < Deleted > {
845
846
self . run_command ( & format ! ( "UID EXPUNGE {}" , uid_set. as_ref( ) ) ) ?;
846
847
self . read_response ( )
847
- . and_then ( |( lines, _) | parse_expunge ( lines, & mut self . unsolicited_responses_tx ) )
848
+ . and_then ( |( lines, _) | parse_expunge ( lines, & mut self . unsolicited_responses ) )
848
849
}
849
850
850
851
/// The [`CHECK` command](https://tools.ietf.org/html/rfc3501#section-6.4.1) requests a
@@ -934,7 +935,7 @@ impl<T: Read + Write> Session<T> {
934
935
sequence_set. as_ref( ) ,
935
936
query. as_ref( )
936
937
) )
937
- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
938
+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
938
939
}
939
940
940
941
/// Equivalent to [`Session::store`], except that all identifiers in `sequence_set` are
@@ -949,7 +950,7 @@ impl<T: Read + Write> Session<T> {
949
950
uid_set. as_ref( ) ,
950
951
query. as_ref( )
951
952
) )
952
- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
953
+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
953
954
}
954
955
955
956
/// The [`COPY` command](https://tools.ietf.org/html/rfc3501#section-6.4.7) copies the
@@ -1084,7 +1085,7 @@ impl<T: Read + Write> Session<T> {
1084
1085
quote!( reference_name. unwrap_or( "" ) ) ,
1085
1086
mailbox_pattern. unwrap_or( "\" \" " )
1086
1087
) )
1087
- . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1088
+ . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses ) )
1088
1089
}
1089
1090
1090
1091
/// The [`LSUB` command](https://tools.ietf.org/html/rfc3501#section-6.3.9) returns a subset of
@@ -1112,7 +1113,7 @@ impl<T: Read + Write> Session<T> {
1112
1113
quote!( reference_name. unwrap_or( "" ) ) ,
1113
1114
mailbox_pattern. unwrap_or( "" )
1114
1115
) )
1115
- . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1116
+ . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses ) )
1116
1117
}
1117
1118
1118
1119
/// The [`STATUS` command](https://tools.ietf.org/html/rfc3501#section-6.3.10) requests the
@@ -1161,9 +1162,7 @@ impl<T: Read + Write> Session<T> {
1161
1162
validate_str( "STATUS" , "mailbox" , mailbox_name) ?,
1162
1163
data_items. as_ref( )
1163
1164
) )
1164
- . and_then ( |lines| {
1165
- parse_status ( & lines[ ..] , mailbox_name, & mut self . unsolicited_responses_tx )
1166
- } )
1165
+ . and_then ( |lines| parse_status ( & lines[ ..] , mailbox_name, & mut self . unsolicited_responses ) )
1167
1166
}
1168
1167
1169
1168
/// This method returns a handle that lets you use the [`IDLE`
@@ -1264,15 +1263,15 @@ impl<T: Read + Write> Session<T> {
1264
1263
/// - `SINCE <date>`: Messages whose internal date (disregarding time and timezone) is within or later than the specified date.
1265
1264
pub fn search ( & mut self , query : impl AsRef < str > ) -> Result < HashSet < Seq > > {
1266
1265
self . run_command_and_read_response ( & format ! ( "SEARCH {}" , query. as_ref( ) ) )
1267
- . and_then ( |lines| parse_id_set ( & lines, & mut self . unsolicited_responses_tx ) )
1266
+ . and_then ( |lines| parse_id_set ( & lines, & mut self . unsolicited_responses ) )
1268
1267
}
1269
1268
1270
1269
/// Equivalent to [`Session::search`], except that the returned identifiers
1271
1270
/// are [`Uid`] instead of [`Seq`]. See also the [`UID`
1272
1271
/// command](https://tools.ietf.org/html/rfc3501#section-6.4.8).
1273
1272
pub fn uid_search ( & mut self , query : impl AsRef < str > ) -> Result < HashSet < Uid > > {
1274
1273
self . run_command_and_read_response ( & format ! ( "UID SEARCH {}" , query. as_ref( ) ) )
1275
- . and_then ( |lines| parse_id_set ( & lines, & mut self . unsolicited_responses_tx ) )
1274
+ . and_then ( |lines| parse_id_set ( & lines, & mut self . unsolicited_responses ) )
1276
1275
}
1277
1276
1278
1277
/// This issues the [SORT command](https://tools.ietf.org/html/rfc5256#section-3),
@@ -1292,7 +1291,7 @@ impl<T: Read + Write> Session<T> {
1292
1291
charset,
1293
1292
query. as_ref( )
1294
1293
) )
1295
- . and_then ( |lines| parse_id_seq ( & lines, & mut self . unsolicited_responses_tx ) )
1294
+ . and_then ( |lines| parse_id_seq ( & lines, & mut self . unsolicited_responses ) )
1296
1295
}
1297
1296
1298
1297
/// Equivalent to [`Session::sort`], except that it returns [`Uid`]s.
@@ -1310,7 +1309,7 @@ impl<T: Read + Write> Session<T> {
1310
1309
charset,
1311
1310
query. as_ref( )
1312
1311
) )
1313
- . and_then ( |lines| parse_id_seq ( & lines, & mut self . unsolicited_responses_tx ) )
1312
+ . and_then ( |lines| parse_id_seq ( & lines, & mut self . unsolicited_responses ) )
1314
1313
}
1315
1314
1316
1315
/// The [`SETACL` command](https://datatracker.ietf.org/doc/html/rfc4314#section-3.1)
@@ -1373,7 +1372,7 @@ impl<T: Read + Write> Session<T> {
1373
1372
"GETACL {}" ,
1374
1373
validate_str( "GETACL" , "mailbox" , mailbox_name. as_ref( ) ) ?
1375
1374
) )
1376
- . and_then ( |lines| AclResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1375
+ . and_then ( |lines| AclResponse :: parse ( lines, & mut self . unsolicited_responses ) )
1377
1376
}
1378
1377
1379
1378
/// The [`LISTRIGHTS` command](https://datatracker.ietf.org/doc/html/rfc4314#section-3.4)
@@ -1394,7 +1393,7 @@ impl<T: Read + Write> Session<T> {
1394
1393
validate_str( "LISTRIGHTS" , "mailbox" , mailbox_name. as_ref( ) ) ?,
1395
1394
validate_str( "LISTRIGHTS" , "identifier" , identifier. as_ref( ) ) ?
1396
1395
) )
1397
- . and_then ( |lines| ListRightsResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1396
+ . and_then ( |lines| ListRightsResponse :: parse ( lines, & mut self . unsolicited_responses ) )
1398
1397
}
1399
1398
1400
1399
/// The [`MYRIGHTS` command](https://datatracker.ietf.org/doc/html/rfc4314#section-3.5)
@@ -1408,7 +1407,7 @@ impl<T: Read + Write> Session<T> {
1408
1407
"MYRIGHTS {}" ,
1409
1408
validate_str( "MYRIGHTS" , "mailbox" , mailbox_name. as_ref( ) ) ?,
1410
1409
) )
1411
- . and_then ( |lines| MyRightsResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1410
+ . and_then ( |lines| MyRightsResponse :: parse ( lines, & mut self . unsolicited_responses ) )
1412
1411
}
1413
1412
1414
1413
/// The [`SETQUOTA` command](https://datatracker.ietf.org/doc/html/rfc2087#section-4.1)
@@ -1428,7 +1427,7 @@ impl<T: Read + Write> Session<T> {
1428
1427
validate_str( "SETQUOTA" , "quota_root" , quota_root. as_ref( ) ) ?,
1429
1428
limits,
1430
1429
) )
1431
- . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1430
+ . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses ) )
1432
1431
}
1433
1432
1434
1433
/// The [`GETQUOTA` command](https://datatracker.ietf.org/doc/html/rfc2087#section-4.2)
@@ -1439,7 +1438,7 @@ impl<T: Read + Write> Session<T> {
1439
1438
"GETQUOTA {}" ,
1440
1439
validate_str( "GETQUOTA" , "quota_root" , quota_root. as_ref( ) ) ?
1441
1440
) )
1442
- . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1441
+ . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses ) )
1443
1442
}
1444
1443
1445
1444
/// The [`GETQUOTAROOT` command](https://datatracker.ietf.org/doc/html/rfc2087#section-4.3)
@@ -1450,7 +1449,7 @@ impl<T: Read + Write> Session<T> {
1450
1449
"GETQUOTAROOT {}" ,
1451
1450
validate_str( "GETQUOTAROOT" , "mailbox" , mailbox_name. as_ref( ) ) ?
1452
1451
) )
1453
- . and_then ( |lines| QuotaRootResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1452
+ . and_then ( |lines| QuotaRootResponse :: parse ( lines, & mut self . unsolicited_responses ) )
1454
1453
}
1455
1454
1456
1455
// these are only here because they are public interface, the rest is in `Connection`
0 commit comments