Merge pull request #140 from brycefisher/feat/cargo-feature-nativetls
(feature) Allow opt-out from `native_tls` crate
This commit is contained in:
commit
7aa5aa7edb
6 changed files with 62 additions and 52 deletions
18
Cargo.toml
18
Cargo.toml
|
|
@ -21,8 +21,12 @@ maintenance = { status = "actively-developed" }
|
||||||
is-it-maintained-issue-resolution = { repository = "jonhoo/rust-imap" }
|
is-it-maintained-issue-resolution = { repository = "jonhoo/rust-imap" }
|
||||||
is-it-maintained-open-issues = { repository = "jonhoo/rust-imap" }
|
is-it-maintained-open-issues = { repository = "jonhoo/rust-imap" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
tls = ["native-tls"]
|
||||||
|
default = ["tls"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
native-tls = "0.2.2"
|
native-tls = { version = "0.2.2", optional = true }
|
||||||
regex = "1.0"
|
regex = "1.0"
|
||||||
bufstream = "0.1"
|
bufstream = "0.1"
|
||||||
imap-proto = "0.9.0"
|
imap-proto = "0.9.0"
|
||||||
|
|
@ -35,3 +39,15 @@ lazy_static = "1.4"
|
||||||
lettre = "0.9"
|
lettre = "0.9"
|
||||||
lettre_email = "0.9"
|
lettre_email = "0.9"
|
||||||
rustls-connector = "0.8.0"
|
rustls-connector = "0.8.0"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "basic"
|
||||||
|
required-features = ["default"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "gmail_oauth2"
|
||||||
|
required-features = ["default"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "imap_integration"
|
||||||
|
required-features = ["default"]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use base64;
|
use base64;
|
||||||
use bufstream::BufStream;
|
use bufstream::BufStream;
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
use native_tls::{TlsConnector, TlsStream};
|
use native_tls::{TlsConnector, TlsStream};
|
||||||
use nom;
|
use nom;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
@ -109,39 +110,6 @@ impl<T: Read + Write> DerefMut for Session<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to a server using an insecure TCP connection.
|
|
||||||
///
|
|
||||||
/// The returned [`Client`] is unauthenticated; to access session-related methods (through
|
|
||||||
/// [`Session`]), use [`Client::login`] or [`Client::authenticate`].
|
|
||||||
///
|
|
||||||
/// Consider using [`connect`] for a secured connection where possible.
|
|
||||||
/// You can upgrade an insecure client to a secure one using [`Client::secure`].
|
|
||||||
/// ```rust,no_run
|
|
||||||
/// # extern crate native_tls;
|
|
||||||
/// # extern crate imap;
|
|
||||||
/// # use std::io;
|
|
||||||
/// # use native_tls::TlsConnector;
|
|
||||||
/// # fn main() {
|
|
||||||
/// // a plain, unencrypted TCP connection
|
|
||||||
/// let client = imap::connect_insecure(("imap.example.org", 143)).unwrap();
|
|
||||||
///
|
|
||||||
/// // upgrade to SSL
|
|
||||||
/// let tls = TlsConnector::builder().build().unwrap();
|
|
||||||
/// let tls_client = client.secure("imap.example.org", &tls);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn connect_insecure<A: ToSocketAddrs>(addr: A) -> Result<Client<TcpStream>> {
|
|
||||||
match TcpStream::connect(addr) {
|
|
||||||
Ok(stream) => {
|
|
||||||
let mut socket = Client::new(stream);
|
|
||||||
|
|
||||||
socket.read_greeting()?;
|
|
||||||
Ok(socket)
|
|
||||||
}
|
|
||||||
Err(e) => Err(Error::Io(e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Connect to a server using a TLS-encrypted connection.
|
/// Connect to a server using a TLS-encrypted connection.
|
||||||
///
|
///
|
||||||
/// The returned [`Client`] is unauthenticated; to access session-related methods (through
|
/// 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>>
|
||||||
/// let client = imap::connect(("imap.example.org", 993), "imap.example.org", &tls).unwrap();
|
/// let client = imap::connect(("imap.example.org", 993), "imap.example.org", &tls).unwrap();
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
pub fn connect<A: ToSocketAddrs, S: AsRef<str>>(
|
pub fn connect<A: ToSocketAddrs, S: AsRef<str>>(
|
||||||
addr: A,
|
addr: A,
|
||||||
domain: S,
|
domain: S,
|
||||||
|
|
@ -186,6 +155,7 @@ impl Client<TcpStream> {
|
||||||
/// This will upgrade an IMAP client from using a regular TCP connection to use TLS.
|
/// This will upgrade an IMAP client from using a regular TCP connection to use TLS.
|
||||||
///
|
///
|
||||||
/// The domain parameter is required to perform hostname verification.
|
/// The domain parameter is required to perform hostname verification.
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
pub fn secure<S: AsRef<str>>(
|
pub fn secure<S: AsRef<str>>(
|
||||||
mut self,
|
mut self,
|
||||||
domain: S,
|
domain: S,
|
||||||
|
|
|
||||||
16
src/error.rs
16
src/error.rs
|
|
@ -3,6 +3,7 @@
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
|
|
@ -10,7 +11,9 @@ use std::str::Utf8Error;
|
||||||
use base64::DecodeError;
|
use base64::DecodeError;
|
||||||
use bufstream::IntoInnerError as BufError;
|
use bufstream::IntoInnerError as BufError;
|
||||||
use imap_proto::Response;
|
use imap_proto::Response;
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
use native_tls::Error as TlsError;
|
use native_tls::Error as TlsError;
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
use native_tls::HandshakeError as TlsHandshakeError;
|
use native_tls::HandshakeError as TlsHandshakeError;
|
||||||
|
|
||||||
/// A convenience wrapper around `Result` for `imap::Error`.
|
/// A convenience wrapper around `Result` for `imap::Error`.
|
||||||
|
|
@ -22,8 +25,10 @@ pub enum Error {
|
||||||
/// An `io::Error` that occurred while trying to read or write to a network stream.
|
/// An `io::Error` that occurred while trying to read or write to a network stream.
|
||||||
Io(IoError),
|
Io(IoError),
|
||||||
/// An error from the `native_tls` library during the TLS handshake.
|
/// An error from the `native_tls` library during the TLS handshake.
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
TlsHandshake(TlsHandshakeError<TcpStream>),
|
TlsHandshake(TlsHandshakeError<TcpStream>),
|
||||||
/// An error from the `native_tls` library while managing the socket.
|
/// An error from the `native_tls` library while managing the socket.
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Tls(TlsError),
|
Tls(TlsError),
|
||||||
/// A BAD response from the IMAP server.
|
/// A BAD response from the IMAP server.
|
||||||
Bad(String),
|
Bad(String),
|
||||||
|
|
@ -38,6 +43,8 @@ pub enum Error {
|
||||||
Validate(ValidateError),
|
Validate(ValidateError),
|
||||||
/// Error appending an e-mail.
|
/// Error appending an e-mail.
|
||||||
Append,
|
Append,
|
||||||
|
#[doc(hidden)]
|
||||||
|
__Nonexhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IoError> for Error {
|
impl From<IoError> for Error {
|
||||||
|
|
@ -58,12 +65,14 @@ impl<T> From<BufError<T>> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
impl From<TlsHandshakeError<TcpStream>> for Error {
|
impl From<TlsHandshakeError<TcpStream>> for Error {
|
||||||
fn from(err: TlsHandshakeError<TcpStream>) -> Error {
|
fn from(err: TlsHandshakeError<TcpStream>) -> Error {
|
||||||
Error::TlsHandshake(err)
|
Error::TlsHandshake(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
impl From<TlsError> for Error {
|
impl From<TlsError> for Error {
|
||||||
fn from(err: TlsError) -> Error {
|
fn from(err: TlsError) -> Error {
|
||||||
Error::Tls(err)
|
Error::Tls(err)
|
||||||
|
|
@ -80,7 +89,9 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Io(ref e) => fmt::Display::fmt(e, f),
|
Error::Io(ref e) => fmt::Display::fmt(e, f),
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Error::Tls(ref e) => fmt::Display::fmt(e, f),
|
Error::Tls(ref e) => fmt::Display::fmt(e, f),
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Error::TlsHandshake(ref e) => fmt::Display::fmt(e, f),
|
Error::TlsHandshake(ref e) => fmt::Display::fmt(e, f),
|
||||||
Error::Validate(ref e) => fmt::Display::fmt(e, f),
|
Error::Validate(ref e) => fmt::Display::fmt(e, f),
|
||||||
Error::No(ref data) | Error::Bad(ref data) => {
|
Error::No(ref data) | Error::Bad(ref data) => {
|
||||||
|
|
@ -95,7 +106,9 @@ impl StdError for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Io(ref e) => e.description(),
|
Error::Io(ref e) => e.description(),
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Error::Tls(ref e) => e.description(),
|
Error::Tls(ref e) => e.description(),
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Error::TlsHandshake(ref e) => e.description(),
|
Error::TlsHandshake(ref e) => e.description(),
|
||||||
Error::Parse(ref e) => e.description(),
|
Error::Parse(ref e) => e.description(),
|
||||||
Error::Validate(ref e) => e.description(),
|
Error::Validate(ref e) => e.description(),
|
||||||
|
|
@ -103,13 +116,16 @@ impl StdError for Error {
|
||||||
Error::No(_) => "No Response",
|
Error::No(_) => "No Response",
|
||||||
Error::ConnectionLost => "Connection lost",
|
Error::ConnectionLost => "Connection lost",
|
||||||
Error::Append => "Could not append mail to mailbox",
|
Error::Append => "Could not append mail to mailbox",
|
||||||
|
Error::__Nonexhaustive => "Unknown",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self) -> Option<&dyn StdError> {
|
fn cause(&self) -> Option<&dyn StdError> {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Io(ref e) => Some(e),
|
Error::Io(ref e) => Some(e),
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Error::Tls(ref e) => Some(e),
|
Error::Tls(ref e) => Some(e),
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
Error::TlsHandshake(ref e) => Some(e),
|
Error::TlsHandshake(ref e) => Some(e),
|
||||||
Error::Parse(ParseError::DataNotUtf8(_, ref e)) => Some(e),
|
Error::Parse(ParseError::DataNotUtf8(_, ref e)) => Some(e),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use crate::client::Session;
|
use crate::client::Session;
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
use native_tls::TlsStream;
|
use native_tls::TlsStream;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
|
@ -164,6 +165,7 @@ impl<'a> SetReadTimeout for TcpStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
impl<'a> SetReadTimeout for TlsStream<TcpStream> {
|
impl<'a> SetReadTimeout for TlsStream<TcpStream> {
|
||||||
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
fn set_read_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
|
||||||
self.get_ref().set_read_timeout(timeout).map_err(Error::Io)
|
self.get_ref().set_read_timeout(timeout).map_err(Error::Io)
|
||||||
|
|
|
||||||
20
src/lib.rs
20
src/lib.rs
|
|
@ -50,13 +50,29 @@
|
||||||
//! let body = std::str::from_utf8(body)
|
//! let body = std::str::from_utf8(body)
|
||||||
//! .expect("message was not valid utf-8")
|
//! .expect("message was not valid utf-8")
|
||||||
//! .to_string();
|
//! .to_string();
|
||||||
//!
|
//!
|
||||||
//! // be nice to the server and log out
|
//! // be nice to the server and log out
|
||||||
//! imap_session.logout()?;
|
//! imap_session.logout()?;
|
||||||
//!
|
//!
|
||||||
//! Ok(Some(body))
|
//! Ok(Some(body))
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Opting out of `native_tls`
|
||||||
|
//!
|
||||||
|
//! For situations where using openssl becomes problematic, you can disable the
|
||||||
|
//! default feature which provides integration with the `native_tls` crate. One major
|
||||||
|
//! reason you might want to do this is cross-compiling. To opt out of native_tls, add
|
||||||
|
//! this to your Cargo.toml file:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [dependencies.imap]
|
||||||
|
//! version = "<some version>"
|
||||||
|
//! default-features = false
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Even without `native_tls`, you can still use TLS by leveraging the pure Rust `rustls`
|
||||||
|
//! crate. See the example/rustls.rs file for a working example.
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,26 +47,16 @@ fn smtp(user: &str) -> lettre::SmtpTransport {
|
||||||
.transport()
|
.transport()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn connect_insecure() {
|
|
||||||
imap::connect_insecure(&format!(
|
|
||||||
"{}:3143",
|
|
||||||
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn connect_insecure_then_secure() {
|
fn connect_insecure_then_secure() {
|
||||||
|
let host = std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string());
|
||||||
|
let stream = TcpStream::connect((host.as_ref(), 3143)).unwrap();
|
||||||
|
|
||||||
// ignored because of https://github.com/greenmail-mail-test/greenmail/issues/135
|
// ignored because of https://github.com/greenmail-mail-test/greenmail/issues/135
|
||||||
imap::connect_insecure(&format!(
|
imap::Client::new(stream)
|
||||||
"{}:3143",
|
.secure("imap.example.com", &tls())
|
||||||
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
|
.unwrap();
|
||||||
))
|
|
||||||
.unwrap()
|
|
||||||
.secure("imap.example.com", &tls())
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue