use async_imap::{ error::{Error as ImapError, Result as ImapResult}, extensions::idle::Handle as ImapIdleHandle, types::{Capabilities, Fetch, Mailbox, Name}, Client as ImapClient, Session as ImapSession, }; use async_std::net::{self, TcpStream}; use async_std::prelude::*; use async_std::sync::Arc; use async_tls::client::TlsStream; use crate::login_param::{dc_build_tls_config, CertificateChecks}; const DCC_IMAP_DEBUG: &str = "DCC_IMAP_DEBUG"; #[derive(Debug)] pub(crate) enum Client { Secure(ImapClient>), Insecure(ImapClient), } #[derive(Debug)] pub(crate) enum Session { Secure(ImapSession>), Insecure(ImapSession), } #[derive(Debug)] pub(crate) enum IdleHandle { Secure(ImapIdleHandle>), Insecure(ImapIdleHandle), } impl Client { pub async fn connect_secure>( addr: A, domain: S, certificate_checks: CertificateChecks, ) -> ImapResult { let stream = TcpStream::connect(addr).await?; let tls_config = dc_build_tls_config(certificate_checks); let tls_connector: async_tls::TlsConnector = Arc::new(tls_config).into(); let tls_stream = tls_connector.connect(domain.as_ref(), stream)?.await?; let mut client = ImapClient::new(tls_stream); if std::env::var(DCC_IMAP_DEBUG).is_ok() { client.debug = true; } let _greeting = client .read_response() .await .expect("failed to read greeting"); Ok(Client::Secure(client)) } pub async fn connect_insecure(addr: A) -> ImapResult { let stream = TcpStream::connect(addr).await?; let mut client = ImapClient::new(stream); if std::env::var(DCC_IMAP_DEBUG).is_ok() { client.debug = true; } let _greeting = client .read_response() .await .expect("failed to read greeting"); Ok(Client::Insecure(client)) } pub async fn secure>( self, domain: S, certificate_checks: CertificateChecks, ) -> ImapResult { match self { Client::Insecure(client) => { let tls_config = dc_build_tls_config(certificate_checks); let tls: async_tls::TlsConnector = Arc::new(tls_config).into(); let client_sec = client.secure(domain, &tls).await?; Ok(Client::Secure(client_sec)) } // Nothing to do Client::Secure(_) => Ok(self), } } pub async fn authenticate>( self, auth_type: S, authenticator: &A, ) -> Result { match self { Client::Secure(i) => match i.authenticate(auth_type, authenticator).await { Ok(session) => Ok(Session::Secure(session)), Err((err, c)) => Err((err, Client::Secure(c))), }, Client::Insecure(i) => match i.authenticate(auth_type, authenticator).await { Ok(session) => Ok(Session::Insecure(session)), Err((err, c)) => Err((err, Client::Insecure(c))), }, } } pub async fn login, P: AsRef>( self, username: U, password: P, ) -> Result { match self { Client::Secure(i) => match i.login(username, password).await { Ok(session) => Ok(Session::Secure(session)), Err((err, c)) => Err((err, Client::Secure(c))), }, Client::Insecure(i) => match i.login(username, password).await { Ok(session) => Ok(Session::Insecure(session)), Err((err, c)) => Err((err, Client::Insecure(c))), }, } } } impl Session { pub async fn capabilities(&mut self) -> ImapResult { let res = match self { Session::Secure(i) => i.capabilities().await?, Session::Insecure(i) => i.capabilities().await?, }; Ok(res) } pub async fn list( &mut self, reference_name: Option<&str>, mailbox_pattern: Option<&str>, ) -> ImapResult> { let res = match self { Session::Secure(i) => { i.list(reference_name, mailbox_pattern) .await? .collect::>() .await? } Session::Insecure(i) => { i.list(reference_name, mailbox_pattern) .await? .collect::>() .await? } }; Ok(res) } pub async fn create>(&mut self, mailbox_name: S) -> ImapResult<()> { match self { Session::Secure(i) => i.create(mailbox_name).await?, Session::Insecure(i) => i.create(mailbox_name).await?, } Ok(()) } pub async fn subscribe>(&mut self, mailbox: S) -> ImapResult<()> { match self { Session::Secure(i) => i.subscribe(mailbox).await?, Session::Insecure(i) => i.subscribe(mailbox).await?, } Ok(()) } pub async fn close(&mut self) -> ImapResult<()> { match self { Session::Secure(i) => i.close().await?, Session::Insecure(i) => i.close().await?, } Ok(()) } pub async fn select>(&mut self, mailbox_name: S) -> ImapResult { let mbox = match self { Session::Secure(i) => i.select(mailbox_name).await?, Session::Insecure(i) => i.select(mailbox_name).await?, }; Ok(mbox) } pub async fn fetch(&mut self, sequence_set: S1, query: S2) -> ImapResult> where S1: AsRef, S2: AsRef, { let res = match self { Session::Secure(i) => { i.fetch(sequence_set, query) .await? .collect::>() .await? } Session::Insecure(i) => { i.fetch(sequence_set, query) .await? .collect::>() .await? } }; Ok(res) } pub async fn uid_fetch(&mut self, uid_set: S1, query: S2) -> ImapResult> where S1: AsRef, S2: AsRef, { let res = match self { Session::Secure(i) => { i.uid_fetch(uid_set, query) .await? .collect::>() .await? } Session::Insecure(i) => { i.uid_fetch(uid_set, query) .await? .collect::>() .await? } }; Ok(res) } pub fn idle(self) -> IdleHandle { match self { Session::Secure(i) => { let h = i.idle(); IdleHandle::Secure(h) } Session::Insecure(i) => { let h = i.idle(); IdleHandle::Insecure(h) } } } pub async fn uid_store(&mut self, uid_set: S1, query: S2) -> ImapResult> where S1: AsRef, S2: AsRef, { let res = match self { Session::Secure(i) => { i.uid_store(uid_set, query) .await? .collect::>() .await? } Session::Insecure(i) => { i.uid_store(uid_set, query) .await? .collect::>() .await? } }; Ok(res) } pub async fn uid_mv, S2: AsRef>( &mut self, uid_set: S1, mailbox_name: S2, ) -> ImapResult<()> { match self { Session::Secure(i) => i.uid_mv(uid_set, mailbox_name).await?, Session::Insecure(i) => i.uid_mv(uid_set, mailbox_name).await?, } Ok(()) } pub async fn uid_copy, S2: AsRef>( &mut self, uid_set: S1, mailbox_name: S2, ) -> ImapResult<()> { match self { Session::Secure(i) => i.uid_copy(uid_set, mailbox_name).await?, Session::Insecure(i) => i.uid_copy(uid_set, mailbox_name).await?, } Ok(()) } }