mirror of
https://github.com/chatmail/core.git
synced 2026-04-21 15:36:30 +03:00
feat: add proper shutdown logic for imap
This commit is contained in:
@@ -24,7 +24,6 @@ num-traits = "0.2.6"
|
|||||||
native-tls = "0.2.3"
|
native-tls = "0.2.3"
|
||||||
lettre = "0.9.0"
|
lettre = "0.9.0"
|
||||||
imap = "1.0.1"
|
imap = "1.0.1"
|
||||||
# rental = "0.5.3"
|
|
||||||
mmime = { git = "https://github.com/dignifiedquire/mmime" }
|
mmime = { git = "https://github.com/dignifiedquire/mmime" }
|
||||||
base64 = "0.10.1"
|
base64 = "0.10.1"
|
||||||
|
|
||||||
|
|||||||
206
src/dc_imap.rs
206
src/dc_imap.rs
@@ -31,23 +31,8 @@ pub struct Imap {
|
|||||||
receive_imf: dc_receive_imf_t,
|
receive_imf: dc_receive_imf_t,
|
||||||
|
|
||||||
session: Arc<Mutex<Option<Session>>>,
|
session: Arc<Mutex<Option<Session>>>,
|
||||||
// idle: Arc<Mutex<Option<RentSession>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rental! {
|
|
||||||
// pub mod rent {
|
|
||||||
// use crate::dc_imap::{Session, IdleHandle};
|
|
||||||
|
|
||||||
// #[rental_mut]
|
|
||||||
// pub struct RentSession {
|
|
||||||
// session: Box<Session>,
|
|
||||||
// idle: IdleHandle<'session>,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// use rent::*;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FolderMeaning {
|
pub enum FolderMeaning {
|
||||||
Unknown,
|
Unknown,
|
||||||
@@ -56,13 +41,19 @@ pub enum FolderMeaning {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum Client {
|
pub enum Client {
|
||||||
Secure(imap::Client<native_tls::TlsStream<std::net::TcpStream>>),
|
Secure(
|
||||||
Insecure(imap::Client<std::net::TcpStream>),
|
imap::Client<native_tls::TlsStream<std::net::TcpStream>>,
|
||||||
|
std::net::TcpStream,
|
||||||
|
),
|
||||||
|
Insecure(imap::Client<std::net::TcpStream>, std::net::TcpStream),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Session {
|
pub enum Session {
|
||||||
Secure(imap::Session<native_tls::TlsStream<std::net::TcpStream>>),
|
Secure(
|
||||||
Insecure(imap::Session<std::net::TcpStream>),
|
imap::Session<native_tls::TlsStream<std::net::TcpStream>>,
|
||||||
|
std::net::TcpStream,
|
||||||
|
),
|
||||||
|
Insecure(imap::Session<std::net::TcpStream>, std::net::TcpStream),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum IdleHandle<'a> {
|
pub enum IdleHandle<'a> {
|
||||||
@@ -70,30 +61,6 @@ pub enum IdleHandle<'a> {
|
|||||||
Insecure(imap::extensions::idle::Handle<'a, std::net::TcpStream>),
|
Insecure(imap::extensions::idle::Handle<'a, std::net::TcpStream>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<imap::Client<native_tls::TlsStream<std::net::TcpStream>>> for Client {
|
|
||||||
fn from(client: imap::Client<native_tls::TlsStream<std::net::TcpStream>>) -> Self {
|
|
||||||
Client::Secure(client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<imap::Client<std::net::TcpStream>> for Client {
|
|
||||||
fn from(client: imap::Client<std::net::TcpStream>) -> Self {
|
|
||||||
Client::Insecure(client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<imap::Session<native_tls::TlsStream<std::net::TcpStream>>> for Session {
|
|
||||||
fn from(session: imap::Session<native_tls::TlsStream<std::net::TcpStream>>) -> Self {
|
|
||||||
Session::Secure(session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<imap::Session<std::net::TcpStream>> for Session {
|
|
||||||
fn from(session: imap::Session<std::net::TcpStream>) -> Self {
|
|
||||||
Session::Insecure(session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<imap::extensions::idle::Handle<'a, native_tls::TlsStream<std::net::TcpStream>>>
|
impl<'a> From<imap::extensions::idle::Handle<'a, native_tls::TlsStream<std::net::TcpStream>>>
|
||||||
for IdleHandle<'a>
|
for IdleHandle<'a>
|
||||||
{
|
{
|
||||||
@@ -127,20 +94,65 @@ impl<'a> IdleHandle<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
|
pub fn connect_secure<A: std::net::ToSocketAddrs, S: AsRef<str>>(
|
||||||
|
addr: A,
|
||||||
|
domain: S,
|
||||||
|
) -> imap::error::Result<Self> {
|
||||||
|
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<A: std::net::ToSocketAddrs>(addr: A) -> imap::error::Result<Self> {
|
||||||
|
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<S: AsRef<str>>(self, domain: S) -> imap::error::Result<Client> {
|
||||||
|
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<U: AsRef<str>, P: AsRef<str>>(
|
pub fn login<U: AsRef<str>, P: AsRef<str>>(
|
||||||
self,
|
self,
|
||||||
username: U,
|
username: U,
|
||||||
password: P,
|
password: P,
|
||||||
) -> Result<Session, (imap::error::Error, Client)> {
|
) -> Result<Session, (imap::error::Error, Client)> {
|
||||||
match self {
|
match self {
|
||||||
Client::Secure(i) => i
|
Client::Secure(i, stream) => match i.login(username, password) {
|
||||||
.login(username, password)
|
Ok(session) => Ok(Session::Secure(session, stream)),
|
||||||
.map(Into::into)
|
Err((err, c)) => Err((err, Client::Secure(c, stream))),
|
||||||
.map_err(|(e, c)| (e, c.into())),
|
},
|
||||||
Client::Insecure(i) => i
|
Client::Insecure(i, stream) => match i.login(username, password) {
|
||||||
.login(username, password)
|
Ok(session) => Ok(Session::Insecure(session, stream)),
|
||||||
.map(Into::into)
|
Err((err, c)) => Err((err, Client::Insecure(c, stream))),
|
||||||
.map_err(|(e, c)| (e, c.into())),
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,8 +162,8 @@ impl Session {
|
|||||||
&mut self,
|
&mut self,
|
||||||
) -> imap::error::Result<imap::types::ZeroCopy<imap::types::Capabilities>> {
|
) -> imap::error::Result<imap::types::ZeroCopy<imap::types::Capabilities>> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.capabilities(),
|
Session::Secure(i, _) => i.capabilities(),
|
||||||
Session::Insecure(i) => i.capabilities(),
|
Session::Insecure(i, _) => i.capabilities(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,29 +173,36 @@ impl Session {
|
|||||||
mailbox_pattern: Option<&str>,
|
mailbox_pattern: Option<&str>,
|
||||||
) -> imap::error::Result<imap::types::ZeroCopy<Vec<imap::types::Name>>> {
|
) -> imap::error::Result<imap::types::ZeroCopy<Vec<imap::types::Name>>> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(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),
|
Session::Insecure(i, _) => i.list(reference_name, mailbox_pattern),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create<S: AsRef<str>>(&mut self, mailbox_name: S) -> imap::error::Result<()> {
|
pub fn create<S: AsRef<str>>(&mut self, mailbox_name: S) -> imap::error::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.subscribe(mailbox_name),
|
Session::Secure(i, _) => i.subscribe(mailbox_name),
|
||||||
Session::Insecure(i) => i.subscribe(mailbox_name),
|
Session::Insecure(i, _) => i.subscribe(mailbox_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe<S: AsRef<str>>(&mut self, mailbox: S) -> imap::error::Result<()> {
|
pub fn subscribe<S: AsRef<str>>(&mut self, mailbox: S) -> imap::error::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.subscribe(mailbox),
|
Session::Secure(i, _) => i.subscribe(mailbox),
|
||||||
Session::Insecure(i) => i.subscribe(mailbox),
|
Session::Insecure(i, _) => i.subscribe(mailbox),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&mut self) -> imap::error::Result<()> {
|
pub fn close(&mut self) -> imap::error::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.close(),
|
Session::Secure(i, _) => i.close(),
|
||||||
Session::Insecure(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,
|
mailbox_name: S,
|
||||||
) -> imap::error::Result<imap::types::Mailbox> {
|
) -> imap::error::Result<imap::types::Mailbox> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.select(mailbox_name),
|
Session::Secure(i, _) => i.select(mailbox_name),
|
||||||
Session::Insecure(i) => i.select(mailbox_name),
|
Session::Insecure(i, _) => i.select(mailbox_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,8 +226,8 @@ impl Session {
|
|||||||
S2: AsRef<str>,
|
S2: AsRef<str>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.fetch(sequence_set, query),
|
Session::Secure(i, _) => i.fetch(sequence_set, query),
|
||||||
Session::Insecure(i) => i.fetch(sequence_set, query),
|
Session::Insecure(i, _) => i.fetch(sequence_set, query),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,15 +241,15 @@ impl Session {
|
|||||||
S2: AsRef<str>,
|
S2: AsRef<str>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(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),
|
Session::Insecure(i, _) => i.uid_fetch(uid_set, query),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn idle(&mut self) -> imap::error::Result<IdleHandle> {
|
pub fn idle(&mut self) -> imap::error::Result<IdleHandle> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(i) => i.idle().map(Into::into),
|
Session::Secure(i, _) => i.idle().map(Into::into),
|
||||||
Session::Insecure(i) => i.idle().map(Into::into),
|
Session::Insecure(i, _) => i.idle().map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,8 +263,8 @@ impl Session {
|
|||||||
S2: AsRef<str>,
|
S2: AsRef<str>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(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),
|
Session::Insecure(i, _) => i.uid_store(uid_set, query),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,8 +274,8 @@ impl Session {
|
|||||||
mailbox_name: S2,
|
mailbox_name: S2,
|
||||||
) -> imap::error::Result<()> {
|
) -> imap::error::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(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),
|
Session::Insecure(i, _) => i.uid_mv(uid_set, mailbox_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,8 +285,8 @@ impl Session {
|
|||||||
mailbox_name: S2,
|
mailbox_name: S2,
|
||||||
) -> imap::error::Result<()> {
|
) -> imap::error::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Session::Secure(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),
|
Session::Insecure(i, _) => i.uid_copy(uid_set, mailbox_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,25 +380,15 @@ impl Imap {
|
|||||||
|
|
||||||
let connection_res: imap::error::Result<Client> =
|
let connection_res: imap::error::Result<Client> =
|
||||||
if (server_flags & (DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_PLAIN)) != 0 {
|
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 {
|
if (server_flags & DC_LP_IMAP_SOCKET_STARTTLS) != 0 {
|
||||||
let tls = native_tls::TlsConnector::builder()
|
client.secure(imap_server)
|
||||||
// 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)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(client.into())
|
Ok(client)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let tls = native_tls::TlsConnector::builder()
|
Client::connect_secure((imap_server, imap_port), imap_server)
|
||||||
// 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)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match connection_res {
|
match connection_res {
|
||||||
@@ -453,12 +462,19 @@ impl Imap {
|
|||||||
pub fn disconnect(&self, context: &dc_context_t) {
|
pub fn disconnect(&self, context: &dc_context_t) {
|
||||||
let session = self.session.lock().unwrap().take();
|
let session = self.session.lock().unwrap().take();
|
||||||
if session.is_some() {
|
if session.is_some() {
|
||||||
match session.unwrap().close() {
|
let mut session = session.unwrap();
|
||||||
|
match session.close() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("failed to close connection: {:?}", 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();
|
let mut cfg = self.config.write().unwrap();
|
||||||
@@ -1003,8 +1019,14 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_idle(&self) {
|
pub fn interrupt_idle(&self) {
|
||||||
// TODO: interrupt real idle
|
if let Some(ref mut session) = *self.session.lock().unwrap() {
|
||||||
// ref: https://github.com/jonhoo/rust-imap/issues/121
|
match session.shutdown() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to disconnect: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let &(ref lock, ref cvar) = &*self.watch.clone();
|
let &(ref lock, ref cvar) = &*self.watch.clone();
|
||||||
let mut watch = lock.lock().unwrap();
|
let mut watch = lock.lock().unwrap();
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
// #[macro_use]
|
|
||||||
// extern crate rental;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod dc_log;
|
pub mod dc_log;
|
||||||
|
|||||||
Reference in New Issue
Block a user