Skip to content

Commit 7aa5aa7

Browse files
authored
Merge pull request #140 from brycefisher/feat/cargo-feature-nativetls
(feature) Allow opt-out from `native_tls` crate
2 parents c8288ea + 6fcc189 commit 7aa5aa7

File tree

6 files changed

+62
-52
lines changed

6 files changed

+62
-52
lines changed

Cargo.toml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ maintenance = { status = "actively-developed" }
2121
is-it-maintained-issue-resolution = { repository = "jonhoo/rust-imap" }
2222
is-it-maintained-open-issues = { repository = "jonhoo/rust-imap" }
2323

24+
[features]
25+
tls = ["native-tls"]
26+
default = ["tls"]
27+
2428
[dependencies]
25-
native-tls = "0.2.2"
29+
native-tls = { version = "0.2.2", optional = true }
2630
regex = "1.0"
2731
bufstream = "0.1"
2832
imap-proto = "0.9.0"
@@ -35,3 +39,15 @@ lazy_static = "1.4"
3539
lettre = "0.9"
3640
lettre_email = "0.9"
3741
rustls-connector = "0.8.0"
42+
43+
[[example]]
44+
name = "basic"
45+
required-features = ["default"]
46+
47+
[[example]]
48+
name = "gmail_oauth2"
49+
required-features = ["default"]
50+
51+
[[test]]
52+
name = "imap_integration"
53+
required-features = ["default"]

src/client.rs

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use base64;
22
use bufstream::BufStream;
3+
#[cfg(feature = "tls")]
34
use native_tls::{TlsConnector, TlsStream};
45
use nom;
56
use std::collections::HashSet;
@@ -109,39 +110,6 @@ impl<T: Read + Write> DerefMut for Session<T> {
109110
}
110111
}
111112

112-
/// Connect to a server using an insecure TCP connection.
113-
///
114-
/// The returned [`Client`] is unauthenticated; to access session-related methods (through
115-
/// [`Session`]), use [`Client::login`] or [`Client::authenticate`].
116-
///
117-
/// Consider using [`connect`] for a secured connection where possible.
118-
/// You can upgrade an insecure client to a secure one using [`Client::secure`].
119-
/// ```rust,no_run
120-
/// # extern crate native_tls;
121-
/// # extern crate imap;
122-
/// # use std::io;
123-
/// # use native_tls::TlsConnector;
124-
/// # fn main() {
125-
/// // a plain, unencrypted TCP connection
126-
/// let client = imap::connect_insecure(("imap.example.org", 143)).unwrap();
127-
///
128-
/// // upgrade to SSL
129-
/// let tls = TlsConnector::builder().build().unwrap();
130-
/// let tls_client = client.secure("imap.example.org", &tls);
131-
/// # }
132-
/// ```
133-
pub fn connect_insecure<A: ToSocketAddrs>(addr: A) -> Result<Client<TcpStream>> {
134-
match TcpStream::connect(addr) {
135-
Ok(stream) => {
136-
let mut socket = Client::new(stream);
137-
138-
socket.read_greeting()?;
139-
Ok(socket)
140-
}
141-
Err(e) => Err(Error::Io(e)),
142-
}
143-
}
144-
145113
/// Connect to a server using a TLS-encrypted connection.
146114
///
147115
/// The returned [`Client`] is unauthenticated; to access session-related methods (through
@@ -162,6 +130,7 @@ pub fn connect_insecure<A: ToSocketAddrs>(addr: A) -> Result<Client<TcpStream>>
162130
/// let client = imap::connect(("imap.example.org", 993), "imap.example.org", &tls).unwrap();
163131
/// # }
164132
/// ```
133+
#[cfg(feature = "tls")]
165134
pub fn connect<A: ToSocketAddrs, S: AsRef<str>>(
166135
addr: A,
167136
domain: S,
@@ -186,6 +155,7 @@ impl Client<TcpStream> {
186155
/// This will upgrade an IMAP client from using a regular TCP connection to use TLS.
187156
///
188157
/// The domain parameter is required to perform hostname verification.
158+
#[cfg(feature = "tls")]
189159
pub fn secure<S: AsRef<str>>(
190160
mut self,
191161
domain: S,

src/error.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
use std::error::Error as StdError;
44
use std::fmt;
55
use std::io::Error as IoError;
6+
#[cfg(feature = "tls")]
67
use std::net::TcpStream;
78
use std::result;
89
use std::str::Utf8Error;
910

1011
use base64::DecodeError;
1112
use bufstream::IntoInnerError as BufError;
1213
use imap_proto::Response;
14+
#[cfg(feature = "tls")]
1315
use native_tls::Error as TlsError;
16+
#[cfg(feature = "tls")]
1417
use native_tls::HandshakeError as TlsHandshakeError;
1518

1619
/// A convenience wrapper around `Result` for `imap::Error`.
@@ -22,8 +25,10 @@ pub enum Error {
2225
/// An `io::Error` that occurred while trying to read or write to a network stream.
2326
Io(IoError),
2427
/// An error from the `native_tls` library during the TLS handshake.
28+
#[cfg(feature = "tls")]
2529
TlsHandshake(TlsHandshakeError<TcpStream>),
2630
/// An error from the `native_tls` library while managing the socket.
31+
#[cfg(feature = "tls")]
2732
Tls(TlsError),
2833
/// A BAD response from the IMAP server.
2934
Bad(String),
@@ -38,6 +43,8 @@ pub enum Error {
3843
Validate(ValidateError),
3944
/// Error appending an e-mail.
4045
Append,
46+
#[doc(hidden)]
47+
__Nonexhaustive,
4148
}
4249

4350
impl From<IoError> for Error {
@@ -58,12 +65,14 @@ impl<T> From<BufError<T>> for Error {
5865
}
5966
}
6067

68+
#[cfg(feature = "tls")]
6169
impl From<TlsHandshakeError<TcpStream>> for Error {
6270
fn from(err: TlsHandshakeError<TcpStream>) -> Error {
6371
Error::TlsHandshake(err)
6472
}
6573
}
6674

75+
#[cfg(feature = "tls")]
6776
impl From<TlsError> for Error {
6877
fn from(err: TlsError) -> Error {
6978
Error::Tls(err)
@@ -80,7 +89,9 @@ impl fmt::Display for Error {
8089
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8190
match *self {
8291
Error::Io(ref e) => fmt::Display::fmt(e, f),
92+
#[cfg(feature = "tls")]
8393
Error::Tls(ref e) => fmt::Display::fmt(e, f),
94+
#[cfg(feature = "tls")]
8495
Error::TlsHandshake(ref e) => fmt::Display::fmt(e, f),
8596
Error::Validate(ref e) => fmt::Display::fmt(e, f),
8697
Error::No(ref data) | Error::Bad(ref data) => {
@@ -95,21 +106,26 @@ impl StdError for Error {
95106
fn description(&self) -> &str {
96107
match *self {
97108
Error::Io(ref e) => e.description(),
109+
#[cfg(feature = "tls")]
98110
Error::Tls(ref e) => e.description(),
111+
#[cfg(feature = "tls")]
99112
Error::TlsHandshake(ref e) => e.description(),
100113
Error::Parse(ref e) => e.description(),
101114
Error::Validate(ref e) => e.description(),
102115
Error::Bad(_) => "Bad Response",
103116
Error::No(_) => "No Response",
104117
Error::ConnectionLost => "Connection lost",
105118
Error::Append => "Could not append mail to mailbox",
119+
Error::__Nonexhaustive => "Unknown",
106120
}
107121
}
108122

109123
fn cause(&self) -> Option<&dyn StdError> {
110124
match *self {
111125
Error::Io(ref e) => Some(e),
126+
#[cfg(feature = "tls")]
112127
Error::Tls(ref e) => Some(e),
128+
#[cfg(feature = "tls")]
113129
Error::TlsHandshake(ref e) => Some(e),
114130
Error::Parse(ParseError::DataNotUtf8(_, ref e)) => Some(e),
115131
_ => None,

src/extensions/idle.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use crate::client::Session;
55
use crate::error::{Error, Result};
6+
#[cfg(feature = "tls")]
67
use native_tls::TlsStream;
78
use std::io::{self, Read, Write};
89
use std::net::TcpStream;
@@ -164,6 +165,7 @@ impl<'a> SetReadTimeout for TcpStream {
164165
}
165166
}
166167

168+
#[cfg(feature = "tls")]
167169
impl<'a> SetReadTimeout for TlsStream<TcpStream> {
168170
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
169171
self.get_ref().set_read_timeout(timeout).map_err(Error::Io)

src/lib.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,29 @@
5050
//! let body = std::str::from_utf8(body)
5151
//! .expect("message was not valid utf-8")
5252
//! .to_string();
53-
//!
53+
//!
5454
//! // be nice to the server and log out
5555
//! imap_session.logout()?;
56-
//!
56+
//!
5757
//! Ok(Some(body))
5858
//! }
5959
//! ```
60+
//!
61+
//! ## Opting out of `native_tls`
62+
//!
63+
//! For situations where using openssl becomes problematic, you can disable the
64+
//! default feature which provides integration with the `native_tls` crate. One major
65+
//! reason you might want to do this is cross-compiling. To opt out of native_tls, add
66+
//! this to your Cargo.toml file:
67+
//!
68+
//! ```toml
69+
//! [dependencies.imap]
70+
//! version = "<some version>"
71+
//! default-features = false
72+
//! ```
73+
//!
74+
//! Even without `native_tls`, you can still use TLS by leveraging the pure Rust `rustls`
75+
//! crate. See the example/rustls.rs file for a working example.
6076
#![deny(missing_docs)]
6177
#![warn(rust_2018_idioms)]
6278

tests/imap_integration.rs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,16 @@ fn smtp(user: &str) -> lettre::SmtpTransport {
4747
.transport()
4848
}
4949

50-
#[test]
51-
fn connect_insecure() {
52-
imap::connect_insecure(&format!(
53-
"{}:3143",
54-
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
55-
))
56-
.unwrap();
57-
}
58-
5950
#[test]
6051
#[ignore]
6152
fn connect_insecure_then_secure() {
53+
let host = std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string());
54+
let stream = TcpStream::connect((host.as_ref(), 3143)).unwrap();
55+
6256
// ignored because of https://github.com/greenmail-mail-test/greenmail/issues/135
63-
imap::connect_insecure(&format!(
64-
"{}:3143",
65-
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
66-
))
67-
.unwrap()
68-
.secure("imap.example.com", &tls())
69-
.unwrap();
57+
imap::Client::new(stream)
58+
.secure("imap.example.com", &tls())
59+
.unwrap();
7060
}
7161

7262
#[test]

0 commit comments

Comments
 (0)