From 00314ffbe04ab2c39286aaa034fef3864e5d4e6d Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Fri, 10 May 2019 19:13:38 +0100 Subject: [PATCH] feat: add proper shutdown logic for imap --- Cargo.toml | 1 - src/dc_imap.rs | 206 +++++++++++++++++++++++++++---------------------- src/lib.rs | 2 - 3 files changed, 114 insertions(+), 95 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 18b502809..ba8d3499e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ num-traits = "0.2.6" native-tls = "0.2.3" lettre = "0.9.0" imap = "1.0.1" -# rental = "0.5.3" mmime = { git = "https://github.com/dignifiedquire/mmime" } base64 = "0.10.1" diff --git a/src/dc_imap.rs b/src/dc_imap.rs index 817d9b5b9..c0248dd0b 100644 --- a/src/dc_imap.rs +++ b/src/dc_imap.rs @@ -31,23 +31,8 @@ pub struct Imap { receive_imf: dc_receive_imf_t, session: Arc>>, - // idle: Arc>>, } -// rental! { -// pub mod rent { -// use crate::dc_imap::{Session, IdleHandle}; - -// #[rental_mut] -// pub struct RentSession { -// session: Box, -// idle: IdleHandle<'session>, -// } -// } -// } - -// use rent::*; - #[derive(Debug)] pub enum FolderMeaning { Unknown, @@ -56,13 +41,19 @@ pub enum FolderMeaning { } pub enum Client { - Secure(imap::Client>), - Insecure(imap::Client), + Secure( + imap::Client>, + std::net::TcpStream, + ), + Insecure(imap::Client, std::net::TcpStream), } pub enum Session { - Secure(imap::Session>), - Insecure(imap::Session), + Secure( + imap::Session>, + std::net::TcpStream, + ), + Insecure(imap::Session, std::net::TcpStream), } pub enum IdleHandle<'a> { @@ -70,30 +61,6 @@ pub enum IdleHandle<'a> { Insecure(imap::extensions::idle::Handle<'a, std::net::TcpStream>), } -impl From>> for Client { - fn from(client: imap::Client>) -> Self { - Client::Secure(client) - } -} - -impl From> for Client { - fn from(client: imap::Client) -> Self { - Client::Insecure(client) - } -} - -impl From>> for Session { - fn from(session: imap::Session>) -> Self { - Session::Secure(session) - } -} - -impl From> for Session { - fn from(session: imap::Session) -> Self { - Session::Insecure(session) - } -} - impl<'a> From>> for IdleHandle<'a> { @@ -127,20 +94,65 @@ impl<'a> IdleHandle<'a> { } impl Client { + pub fn connect_secure>( + addr: A, + domain: S, + ) -> imap::error::Result { + let stream = std::net::TcpStream::connect(addr)?; + let tls = native_tls::TlsConnector::builder() + .danger_accept_invalid_hostnames(true) + .build() + .unwrap(); + + let s = stream.try_clone().expect("cloning the stream failed"); + let tls_stream = native_tls::TlsConnector::connect(&tls, domain.as_ref(), s)?; + + let client = imap::Client::new(tls_stream); + // TODO: Read greeting + + Ok(Client::Secure(client, stream)) + } + + pub fn connect_insecure(addr: A) -> imap::error::Result { + let stream = std::net::TcpStream::connect(addr)?; + + let client = imap::Client::new(stream.try_clone().unwrap()); + // TODO: Read greeting + + Ok(Client::Insecure(client, stream)) + } + + pub fn secure>(self, domain: S) -> imap::error::Result { + match self { + Client::Insecure(client, stream) => { + let tls = native_tls::TlsConnector::builder() + .danger_accept_invalid_hostnames(true) + .build() + .unwrap(); + + let client_sec = client.secure(domain, &tls)?; + + Ok(Client::Secure(client_sec, stream)) + } + // Nothing to do + Client::Secure(_, _) => Ok(self), + } + } + pub fn login, P: AsRef>( self, username: U, password: P, ) -> Result { match self { - Client::Secure(i) => i - .login(username, password) - .map(Into::into) - .map_err(|(e, c)| (e, c.into())), - Client::Insecure(i) => i - .login(username, password) - .map(Into::into) - .map_err(|(e, c)| (e, c.into())), + Client::Secure(i, stream) => match i.login(username, password) { + Ok(session) => Ok(Session::Secure(session, stream)), + Err((err, c)) => Err((err, Client::Secure(c, stream))), + }, + Client::Insecure(i, stream) => match i.login(username, password) { + Ok(session) => Ok(Session::Insecure(session, stream)), + Err((err, c)) => Err((err, Client::Insecure(c, stream))), + }, } } } @@ -150,8 +162,8 @@ impl Session { &mut self, ) -> imap::error::Result> { match self { - Session::Secure(i) => i.capabilities(), - Session::Insecure(i) => i.capabilities(), + Session::Secure(i, _) => i.capabilities(), + Session::Insecure(i, _) => i.capabilities(), } } @@ -161,29 +173,36 @@ impl Session { mailbox_pattern: Option<&str>, ) -> imap::error::Result>> { match self { - Session::Secure(i) => i.list(reference_name, mailbox_pattern), - Session::Insecure(i) => i.list(reference_name, mailbox_pattern), + Session::Secure(i, _) => i.list(reference_name, mailbox_pattern), + Session::Insecure(i, _) => i.list(reference_name, mailbox_pattern), } } pub fn create>(&mut self, mailbox_name: S) -> imap::error::Result<()> { match self { - Session::Secure(i) => i.subscribe(mailbox_name), - Session::Insecure(i) => i.subscribe(mailbox_name), + Session::Secure(i, _) => i.subscribe(mailbox_name), + Session::Insecure(i, _) => i.subscribe(mailbox_name), } } pub fn subscribe>(&mut self, mailbox: S) -> imap::error::Result<()> { match self { - Session::Secure(i) => i.subscribe(mailbox), - Session::Insecure(i) => i.subscribe(mailbox), + Session::Secure(i, _) => i.subscribe(mailbox), + Session::Insecure(i, _) => i.subscribe(mailbox), } } pub fn close(&mut self) -> imap::error::Result<()> { match self { - Session::Secure(i) => i.close(), - Session::Insecure(i) => i.close(), + Session::Secure(i, _) => i.close(), + Session::Insecure(i, _) => i.close(), + } + } + + pub fn shutdown(&self) -> std::io::Result<()> { + match self { + Session::Secure(_, stream) => stream.shutdown(std::net::Shutdown::Both), + Session::Insecure(_, stream) => stream.shutdown(std::net::Shutdown::Both), } } @@ -192,8 +211,8 @@ impl Session { mailbox_name: S, ) -> imap::error::Result { match self { - Session::Secure(i) => i.select(mailbox_name), - Session::Insecure(i) => i.select(mailbox_name), + Session::Secure(i, _) => i.select(mailbox_name), + Session::Insecure(i, _) => i.select(mailbox_name), } } @@ -207,8 +226,8 @@ impl Session { S2: AsRef, { match self { - Session::Secure(i) => i.fetch(sequence_set, query), - Session::Insecure(i) => i.fetch(sequence_set, query), + Session::Secure(i, _) => i.fetch(sequence_set, query), + Session::Insecure(i, _) => i.fetch(sequence_set, query), } } @@ -222,15 +241,15 @@ impl Session { S2: AsRef, { match self { - Session::Secure(i) => i.uid_fetch(uid_set, query), - Session::Insecure(i) => i.uid_fetch(uid_set, query), + Session::Secure(i, _) => i.uid_fetch(uid_set, query), + Session::Insecure(i, _) => i.uid_fetch(uid_set, query), } } pub fn idle(&mut self) -> imap::error::Result { match self { - Session::Secure(i) => i.idle().map(Into::into), - Session::Insecure(i) => i.idle().map(Into::into), + Session::Secure(i, _) => i.idle().map(Into::into), + Session::Insecure(i, _) => i.idle().map(Into::into), } } @@ -244,8 +263,8 @@ impl Session { S2: AsRef, { match self { - Session::Secure(i) => i.uid_store(uid_set, query), - Session::Insecure(i) => i.uid_store(uid_set, query), + Session::Secure(i, _) => i.uid_store(uid_set, query), + Session::Insecure(i, _) => i.uid_store(uid_set, query), } } @@ -255,8 +274,8 @@ impl Session { mailbox_name: S2, ) -> imap::error::Result<()> { match self { - Session::Secure(i) => i.uid_mv(uid_set, mailbox_name), - Session::Insecure(i) => i.uid_mv(uid_set, mailbox_name), + Session::Secure(i, _) => i.uid_mv(uid_set, mailbox_name), + Session::Insecure(i, _) => i.uid_mv(uid_set, mailbox_name), } } @@ -266,8 +285,8 @@ impl Session { mailbox_name: S2, ) -> imap::error::Result<()> { match self { - Session::Secure(i) => i.uid_copy(uid_set, mailbox_name), - Session::Insecure(i) => i.uid_copy(uid_set, mailbox_name), + Session::Secure(i, _) => i.uid_copy(uid_set, mailbox_name), + Session::Insecure(i, _) => i.uid_copy(uid_set, mailbox_name), } } } @@ -361,25 +380,15 @@ impl Imap { let connection_res: imap::error::Result = if (server_flags & (DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_PLAIN)) != 0 { - imap::connect_insecure((imap_server, imap_port)).and_then(|client| { + Client::connect_insecure((imap_server, imap_port)).and_then(|client| { if (server_flags & DC_LP_IMAP_SOCKET_STARTTLS) != 0 { - let tls = native_tls::TlsConnector::builder() - // FIXME: unfortunately this is needed to make things work on macos + testrun.org - .danger_accept_invalid_hostnames(true) - .build() - .unwrap(); - client.secure(imap_server, &tls).map(Into::into) + client.secure(imap_server) } else { - Ok(client.into()) + Ok(client) } }) } else { - let tls = native_tls::TlsConnector::builder() - // FIXME: unfortunately this is needed to make things work on macos + testrun.org - .danger_accept_invalid_hostnames(true) - .build() - .unwrap(); - imap::connect((imap_server, imap_port), imap_server, &tls).map(Into::into) + Client::connect_secure((imap_server, imap_port), imap_server) }; match connection_res { @@ -453,12 +462,19 @@ impl Imap { pub fn disconnect(&self, context: &dc_context_t) { let session = self.session.lock().unwrap().take(); if session.is_some() { - match session.unwrap().close() { + let mut session = session.unwrap(); + match session.close() { Ok(_) => {} Err(err) => { eprintln!("failed to close connection: {:?}", err); } } + match session.shutdown() { + Ok(_) => {} + Err(err) => { + eprintln!("failed to shutdown connection: {:?}", err); + } + } } let mut cfg = self.config.write().unwrap(); @@ -1003,8 +1019,14 @@ impl Imap { } pub fn interrupt_idle(&self) { - // TODO: interrupt real idle - // ref: https://github.com/jonhoo/rust-imap/issues/121 + if let Some(ref mut session) = *self.session.lock().unwrap() { + match session.shutdown() { + Ok(_) => {} + Err(err) => { + eprintln!("failed to disconnect: {}", err); + } + } + } let &(ref lock, ref cvar) = &*self.watch.clone(); let mut watch = lock.lock().unwrap(); diff --git a/src/lib.rs b/src/lib.rs index bb954d0bb..92966e158 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,6 @@ extern crate failure; #[macro_use] extern crate num_derive; -// #[macro_use] -// extern crate rental; #[macro_use] pub mod dc_log;