From a4b03568be4326c6a0f9564b3c002af60b37424b Mon Sep 17 00:00:00 2001 From: Celti Burroughs Date: Sat, 30 Nov 2019 04:58:24 -0700 Subject: [PATCH] Add `imap::connect_starttls` convenience function Add a `imap::connect_starttls` convenience function, with the same syntax as `imap::connect`, to make STARTTLS connections as easily as IMAPS. PR#140 removed `imap::connect_insecure` with the stated goal of encouraging users to connect securely. With that change, users are forced to construct their own `TcpStream`s when interacting with non-IMAPS servers. This change may perversely incentivise the use of insecure connections, instead of discouraging them, as users may blindly copy-paste code involving `Client::new` and `TcpStream`s so things "just work", without the visual indicator of `_insecure` suggesting something is wrong. Tangentially, [RFC 2595] encourages using STARTTLS instead of raw SSL sockets. Ideally, we should support both options equally well. [RFC 2595]: https://tools.ietf.org/html/rfc2595#section-7 --- src/client.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/client.rs b/src/client.rs index 8dd68a0..b663fd2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -154,6 +154,46 @@ pub fn connect>( } } +/// Connect to a server and upgrade to a TLS-encrypted connection. +/// +/// This is the [STARTTLS](https://tools.ietf.org/html/rfc2595) equivalent to [`connect`]. All +/// notes there also apply here. +/// +/// # Examples +/// +/// ```no_run +/// # extern crate native_tls; +/// # extern crate imap; +/// # use std::io; +/// # use native_tls::TlsConnector; +/// # fn main() { +/// let tls = TlsConnector::builder().build().unwrap(); +/// let client = imap::connect_starttls(("imap.example.org", 143), "imap.example.org", &tls).unwrap(); +/// # } +/// ``` +#[cfg(feature = "tls")] +pub fn connect_starttls>( + addr: A, + domain: S, + ssl_connector: &TlsConnector, +) -> Result>> { + match TcpStream::connect(addr) { + Ok(stream) => { + let mut socket = Client::new(stream); + socket.read_greeting()?; + socket.run_command_and_check_ok("STARTTLS")?; + TlsConnector::connect( + ssl_connector, + domain.as_ref(), + socket.conn.stream.into_inner()?, + ) + .map(Client::new) + .map_err(Error::TlsHandshake) + } + Err(e) => Err(Error::Io(e)), + } +} + impl Client { /// This will upgrade an IMAP client from using a regular TCP connection to use TLS. ///