@@ -3,10 +3,10 @@ use bufstream::BufStream;
33use chrono:: { DateTime , FixedOffset } ;
44use imap_proto:: Response ;
55use std:: collections:: HashSet ;
6+ use std:: collections:: VecDeque ;
67use std:: io:: { Read , Write } ;
78use std:: ops:: { Deref , DerefMut } ;
89use std:: str;
9- use std:: sync:: mpsc;
1010
1111use super :: authenticator:: Authenticator ;
1212use super :: error:: { Bad , Bye , Error , No , ParseError , Result , TagMismatch , ValidateError } ;
@@ -141,11 +141,9 @@ fn validate_sequence_set(
141141#[ derive( Debug ) ]
142142pub struct Session < T : Read + Write > {
143143 conn : Connection < T > ,
144- pub ( crate ) unsolicited_responses_tx : mpsc:: Sender < UnsolicitedResponse > ,
145-
146144 /// Server responses that are not related to the current command. See also the note on
147145 /// [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 > ,
149147}
150148
151149/// 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> {
262260 self . session . stream . flush ( ) ?;
263261 self . session
264262 . 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 ) )
266264 }
267265}
268266
@@ -370,10 +368,10 @@ impl<T: Read + Write> Client<T> {
370368 ///
371369 /// This allows reading capabilities before authentication.
372370 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 ( ) ;
375373 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 ) )
377375 }
378376
379377 /// 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> {
530528impl < T : Read + Write > Session < T > {
531529 // not public, just to avoid duplicating the channel creation code
532530 fn new ( conn : Connection < T > ) -> Self {
533- let ( tx, rx) = mpsc:: channel ( ) ;
534531 Session {
535532 conn,
536- unsolicited_responses : rx,
537- unsolicited_responses_tx : tx,
533+ unsolicited_responses : VecDeque :: new ( ) ,
538534 }
539535 }
540536
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+
541542 /// Selects a mailbox
542543 ///
543544 /// 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> {
561562 "SELECT {}" ,
562563 validate_str( "SELECT" , "mailbox" , mailbox_name. as_ref( ) ) ?
563564 ) )
564- . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses_tx ) )
565+ . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses ) )
565566 }
566567
567568 /// The `EXAMINE` command is identical to [`Session::select`] and returns the same output;
@@ -573,7 +574,7 @@ impl<T: Read + Write> Session<T> {
573574 "EXAMINE {}" ,
574575 validate_str( "EXAMINE" , "mailbox" , mailbox_name. as_ref( ) ) ?
575576 ) )
576- . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses_tx ) )
577+ . and_then ( |( lines, _) | parse_mailbox ( & lines[ ..] , & mut self . unsolicited_responses ) )
577578 }
578579
579580 /// Fetch retrieves data associated with a set of messages in the mailbox.
@@ -640,15 +641,15 @@ impl<T: Read + Write> Session<T> {
640641 query : impl AsRef < str > ,
641642 ) -> Result < Fetches > {
642643 if sequence_set. as_ref ( ) . is_empty ( ) {
643- Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses_tx )
644+ Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses )
644645 } else {
645646 let synopsis = "FETCH" ;
646647 self . run_command_and_read_response ( & format ! (
647648 "FETCH {} {}" ,
648649 validate_sequence_set( synopsis, "seq" , sequence_set. as_ref( ) ) ?,
649650 validate_str_noquote( synopsis, "query" , query. as_ref( ) ) ?
650651 ) )
651- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
652+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
652653 }
653654 }
654655
@@ -660,22 +661,22 @@ impl<T: Read + Write> Session<T> {
660661 query : impl AsRef < str > ,
661662 ) -> Result < Fetches > {
662663 if uid_set. as_ref ( ) . is_empty ( ) {
663- Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses_tx )
664+ Fetches :: parse ( vec ! [ ] , & mut self . unsolicited_responses )
664665 } else {
665666 let synopsis = "UID FETCH" ;
666667 self . run_command_and_read_response ( & format ! (
667668 "UID FETCH {} {}" ,
668669 validate_sequence_set( synopsis, "seq" , uid_set. as_ref( ) ) ?,
669670 validate_str_noquote( synopsis, "query" , query. as_ref( ) ) ?
670671 ) )
671- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
672+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
672673 }
673674 }
674675
675676 /// Noop always succeeds, and it does nothing.
676677 pub fn noop ( & mut self ) -> Result < ( ) > {
677678 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 ) )
679680 }
680681
681682 /// Logout informs the server that the client is done with the connection.
@@ -807,7 +808,7 @@ impl<T: Read + Write> Session<T> {
807808 /// one of the listed capabilities. See [`Capabilities`] for further details.
808809 pub fn capabilities ( & mut self ) -> Result < Capabilities > {
809810 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 ) )
811812 }
812813
813814 /// The [`EXPUNGE` command](https://tools.ietf.org/html/rfc3501#section-6.4.3) permanently
@@ -816,7 +817,7 @@ impl<T: Read + Write> Session<T> {
816817 pub fn expunge ( & mut self ) -> Result < Deleted > {
817818 self . run_command ( "EXPUNGE" ) ?;
818819 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 ) )
820821 }
821822
822823 /// The [`UID EXPUNGE` command](https://tools.ietf.org/html/rfc4315#section-2.1) permanently
@@ -844,7 +845,7 @@ impl<T: Read + Write> Session<T> {
844845 pub fn uid_expunge ( & mut self , uid_set : impl AsRef < str > ) -> Result < Deleted > {
845846 self . run_command ( & format ! ( "UID EXPUNGE {}" , uid_set. as_ref( ) ) ) ?;
846847 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 ) )
848849 }
849850
850851 /// 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> {
934935 sequence_set. as_ref( ) ,
935936 query. as_ref( )
936937 ) )
937- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
938+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
938939 }
939940
940941 /// Equivalent to [`Session::store`], except that all identifiers in `sequence_set` are
@@ -949,7 +950,7 @@ impl<T: Read + Write> Session<T> {
949950 uid_set. as_ref( ) ,
950951 query. as_ref( )
951952 ) )
952- . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses_tx ) )
953+ . and_then ( |lines| Fetches :: parse ( lines, & mut self . unsolicited_responses ) )
953954 }
954955
955956 /// 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> {
10841085 quote!( reference_name. unwrap_or( "" ) ) ,
10851086 mailbox_pattern. unwrap_or( "\" \" " )
10861087 ) )
1087- . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1088+ . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses ) )
10881089 }
10891090
10901091 /// 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> {
11121113 quote!( reference_name. unwrap_or( "" ) ) ,
11131114 mailbox_pattern. unwrap_or( "" )
11141115 ) )
1115- . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1116+ . and_then ( |lines| Names :: parse ( lines, & mut self . unsolicited_responses ) )
11161117 }
11171118
11181119 /// 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> {
11611162 validate_str( "STATUS" , "mailbox" , mailbox_name) ?,
11621163 data_items. as_ref( )
11631164 ) )
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 ) )
11671166 }
11681167
11691168 /// This method returns a handle that lets you use the [`IDLE`
@@ -1264,15 +1263,15 @@ impl<T: Read + Write> Session<T> {
12641263 /// - `SINCE <date>`: Messages whose internal date (disregarding time and timezone) is within or later than the specified date.
12651264 pub fn search ( & mut self , query : impl AsRef < str > ) -> Result < HashSet < Seq > > {
12661265 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 ) )
12681267 }
12691268
12701269 /// Equivalent to [`Session::search`], except that the returned identifiers
12711270 /// are [`Uid`] instead of [`Seq`]. See also the [`UID`
12721271 /// command](https://tools.ietf.org/html/rfc3501#section-6.4.8).
12731272 pub fn uid_search ( & mut self , query : impl AsRef < str > ) -> Result < HashSet < Uid > > {
12741273 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 ) )
12761275 }
12771276
12781277 /// This issues the [SORT command](https://tools.ietf.org/html/rfc5256#section-3),
@@ -1292,7 +1291,7 @@ impl<T: Read + Write> Session<T> {
12921291 charset,
12931292 query. as_ref( )
12941293 ) )
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 ) )
12961295 }
12971296
12981297 /// Equivalent to [`Session::sort`], except that it returns [`Uid`]s.
@@ -1310,7 +1309,7 @@ impl<T: Read + Write> Session<T> {
13101309 charset,
13111310 query. as_ref( )
13121311 ) )
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 ) )
13141313 }
13151314
13161315 /// The [`SETACL` command](https://datatracker.ietf.org/doc/html/rfc4314#section-3.1)
@@ -1373,7 +1372,7 @@ impl<T: Read + Write> Session<T> {
13731372 "GETACL {}" ,
13741373 validate_str( "GETACL" , "mailbox" , mailbox_name. as_ref( ) ) ?
13751374 ) )
1376- . and_then ( |lines| AclResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1375+ . and_then ( |lines| AclResponse :: parse ( lines, & mut self . unsolicited_responses ) )
13771376 }
13781377
13791378 /// The [`LISTRIGHTS` command](https://datatracker.ietf.org/doc/html/rfc4314#section-3.4)
@@ -1394,7 +1393,7 @@ impl<T: Read + Write> Session<T> {
13941393 validate_str( "LISTRIGHTS" , "mailbox" , mailbox_name. as_ref( ) ) ?,
13951394 validate_str( "LISTRIGHTS" , "identifier" , identifier. as_ref( ) ) ?
13961395 ) )
1397- . and_then ( |lines| ListRightsResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1396+ . and_then ( |lines| ListRightsResponse :: parse ( lines, & mut self . unsolicited_responses ) )
13981397 }
13991398
14001399 /// The [`MYRIGHTS` command](https://datatracker.ietf.org/doc/html/rfc4314#section-3.5)
@@ -1408,7 +1407,7 @@ impl<T: Read + Write> Session<T> {
14081407 "MYRIGHTS {}" ,
14091408 validate_str( "MYRIGHTS" , "mailbox" , mailbox_name. as_ref( ) ) ?,
14101409 ) )
1411- . and_then ( |lines| MyRightsResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1410+ . and_then ( |lines| MyRightsResponse :: parse ( lines, & mut self . unsolicited_responses ) )
14121411 }
14131412
14141413 /// The [`SETQUOTA` command](https://datatracker.ietf.org/doc/html/rfc2087#section-4.1)
@@ -1428,7 +1427,7 @@ impl<T: Read + Write> Session<T> {
14281427 validate_str( "SETQUOTA" , "quota_root" , quota_root. as_ref( ) ) ?,
14291428 limits,
14301429 ) )
1431- . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1430+ . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses ) )
14321431 }
14331432
14341433 /// The [`GETQUOTA` command](https://datatracker.ietf.org/doc/html/rfc2087#section-4.2)
@@ -1439,7 +1438,7 @@ impl<T: Read + Write> Session<T> {
14391438 "GETQUOTA {}" ,
14401439 validate_str( "GETQUOTA" , "quota_root" , quota_root. as_ref( ) ) ?
14411440 ) )
1442- . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1441+ . and_then ( |lines| QuotaResponse :: parse ( lines, & mut self . unsolicited_responses ) )
14431442 }
14441443
14451444 /// The [`GETQUOTAROOT` command](https://datatracker.ietf.org/doc/html/rfc2087#section-4.3)
@@ -1450,7 +1449,7 @@ impl<T: Read + Write> Session<T> {
14501449 "GETQUOTAROOT {}" ,
14511450 validate_str( "GETQUOTAROOT" , "mailbox" , mailbox_name. as_ref( ) ) ?
14521451 ) )
1453- . and_then ( |lines| QuotaRootResponse :: parse ( lines, & mut self . unsolicited_responses_tx ) )
1452+ . and_then ( |lines| QuotaRootResponse :: parse ( lines, & mut self . unsolicited_responses ) )
14541453 }
14551454
14561455 // these are only here because they are public interface, the rest is in `Connection`
0 commit comments