diff --git a/melib/src/imap/connection.rs b/melib/src/imap/connection.rs index 7e48706a..690338a8 100644 --- a/melib/src/imap/connection.rs +++ b/melib/src/imap/connection.rs @@ -19,11 +19,15 @@ * along with meli. If not, see . */ -use super::protocol_parser::{ImapLineSplit, ImapResponse, RequiredResponses, SelectResponse}; use crate::{ backends::{BackendEvent, MailboxHash, RefreshEvent}, email::parser::BytesExt, error::*, + imap::{ + protocol_parser::{self, ImapLineSplit, ImapResponse, RequiredResponses, SelectResponse}, + Capabilities, ImapServerConf, UIDStore, + }, + text::Truncate, utils::{ connections::{std_net::connect as tcp_stream_connect, Connection}, futures::timeout, @@ -72,8 +76,6 @@ macro_rules! imap_log { }; } -use super::{protocol_parser, Capabilities, ImapServerConf, UIDStore}; - #[derive(Clone, Copy, Debug)] pub enum SyncPolicy { None, @@ -170,10 +172,12 @@ impl ImapStream { .build() .chain_err_kind(ErrorKind::Network(NetworkErrorKind::InvalidTLSConnection))?; - let addr = (path.as_str(), server_conf.server_port); - let mut socket = AsyncWrapper::new({ - let conn = Connection::new_tcp(tcp_stream_connect(addr, server_conf.timeout)?); + let addr = (path.clone(), server_conf.server_port); + let timeout = server_conf.timeout; + let conn = Connection::new_tcp( + smol::unblock(move || tcp_stream_connect(addr, timeout)).await?, + ); #[cfg(feature = "imap-trace")] { conn.trace(true).with_id("imap") @@ -244,39 +248,50 @@ impl ImapStream { } { - // [ref:FIXME]: This is blocking - let socket = socket.into_inner()?; - let mut conn_result = connector.connect(path, socket); - if let Err(native_tls::HandshakeError::WouldBlock(midhandshake_stream)) = - conn_result - { - let mut midhandshake_stream = Some(midhandshake_stream); - loop { - match midhandshake_stream.take().unwrap().handshake() { - Ok(r) => { - conn_result = Ok(r); - break; - } - Err(native_tls::HandshakeError::WouldBlock(stream)) => { - midhandshake_stream = Some(stream); - } - p => { - p.chain_err_kind(ErrorKind::Network( - NetworkErrorKind::InvalidTLSConnection, - ))?; + let path = Arc::new(path.to_string()); + let conn = smol::unblock({ + let socket = socket.into_inner()?; + let path = Arc::clone(&path); + move || { + let conn_result = connector.connect(&path, socket); + if let Err(native_tls::HandshakeError::WouldBlock(midhandshake_stream)) = + conn_result + { + let mut midhandshake_stream = Some(midhandshake_stream); + loop { + match midhandshake_stream.take().unwrap().handshake() { + Ok(r) => { + return Ok(r); + } + Err(native_tls::HandshakeError::WouldBlock(stream)) => { + midhandshake_stream = Some(stream); + } + Err(err) => { + return Err(Error::from(err).set_kind(ErrorKind::Network( + NetworkErrorKind::InvalidTLSConnection, + ))); + } + } } } + conn_result.chain_err_kind(ErrorKind::Network( + NetworkErrorKind::InvalidTLSConnection, + )) } - } - AsyncWrapper::new(Connection::new_tls(conn_result.chain_err_summary( - || format!("Could not initiate TLS negotiation to {}.", path), - )?)) - .chain_err_summary(|| format!("Could not initiate TLS negotiation to {}.", path))? + }) + .await + .chain_err_summary(|| format!("Could not initiate TLS negotiation to {}.", path))?; + AsyncWrapper::new(Connection::new_tls(conn)) + .chain_err_summary(|| format!("{} connection failed.", path)) + .chain_err_kind(ErrorKind::OSError)? } } else { - let addr = (path.as_str(), server_conf.server_port); AsyncWrapper::new({ - let conn = Connection::new_tcp(tcp_stream_connect(addr, server_conf.timeout)?); + let addr = (path.clone(), server_conf.server_port); + let timeout = server_conf.timeout; + let conn = Connection::new_tcp( + smol::unblock(move || tcp_stream_connect(addr, timeout)).await?, + ); #[cfg(feature = "imap-trace")] { conn.trace(true).with_id("imap") @@ -335,16 +350,24 @@ impl ImapStream { .map(|(_, v)| v) }); - if capabilities.is_err() { - return Err(Error::new(format!( - "Could not connect to {}: expected CAPABILITY response but got:{}", - &server_conf.server_hostname, - String::from_utf8_lossy(&res) - )) - .set_kind(ErrorKind::ProtocolError)); - } + let capabilities = match capabilities { + Err(_err) => { + log::debug!( + "Could not connect to {}: expected CAPABILITY response but got: {} `{}`", + &server_conf.server_hostname, + _err, + String::from_utf8_lossy(&res) + ); + return Err(Error::new(format!( + "Could not connect to {}: expected CAPABILITY response but got: `{}`", + &server_conf.server_hostname, + String::from_utf8_lossy(&res).as_ref().trim_at_boundary(40) + )) + .set_kind(ErrorKind::ProtocolError)); + } + Ok(v) => v, + }; - let capabilities = capabilities.unwrap(); if !capabilities .iter() .any(|cap| cap.eq_ignore_ascii_case(b"IMAP4rev1")) @@ -533,9 +556,9 @@ impl ImapStream { match self.protocol { ImapProtocol::IMAP { .. } => { if matches!(command.body, CommandBody::Login { .. }) { - imap_log!(trace, self, "sent: M{} LOGIN ..", self.cmd_id - 1); + imap_log!(trace, self, "sent: M{} LOGIN ..", self.cmd_id); } else { - imap_log!(trace, self, "sent: M{} {:?}", self.cmd_id - 1, command.body); + imap_log!(trace, self, "sent: M{} {:?}", self.cmd_id, command.body); } } ImapProtocol::ManageSieve => {}