use std::ops::{Deref, DerefMut};
use std::result;
use crate::connection::{
AsRawFdOrSocket, Async, AsyncConnection, AsyncRead, AsyncWrite, TlsClientUpgrader,
UpgraderExtRefer,
};
use crate::imap::{validate_str, Error};
use crate::session::AsyncSession;
pub struct AsyncClient<AS, ASTU>
where
AS: AsRawFdOrSocket,
Async<AS>: AsyncRead + AsyncWrite,
ASTU: TlsClientUpgrader<Async<AS>> + Unpin,
ASTU::Output: AsyncRead + AsyncWrite + Unpin,
{
conn: AsyncConnection<AS, ASTU>,
}
impl<AS, ASTU> Deref for AsyncClient<AS, ASTU>
where
AS: AsRawFdOrSocket,
Async<AS>: AsyncRead + AsyncWrite,
ASTU: TlsClientUpgrader<Async<AS>> + Unpin,
ASTU::Output: AsyncRead + AsyncWrite + Unpin,
{
type Target = AsyncConnection<AS, ASTU>;
fn deref(&self) -> &AsyncConnection<AS, ASTU> {
&self.conn
}
}
impl<AS, ASTU> DerefMut for AsyncClient<AS, ASTU>
where
AS: AsRawFdOrSocket,
Async<AS>: AsyncRead + AsyncWrite,
ASTU: TlsClientUpgrader<Async<AS>> + Unpin,
ASTU::Output: AsyncRead + AsyncWrite + Unpin,
{
fn deref_mut(&mut self) -> &mut AsyncConnection<AS, ASTU> {
&mut self.conn
}
}
macro_rules! ok_or_unauth_client_err {
($r:expr, $self:expr) => {
match $r {
Ok(o) => o,
Err(e) => return Err((e, $self)),
}
};
}
impl<AS, ASTU> AsyncClient<AS, ASTU>
where
AS: AsRawFdOrSocket,
Async<AS>: AsyncRead + AsyncWrite,
ASTU: TlsClientUpgrader<Async<AS>> + UpgraderExtRefer<Async<AS>> + Unpin,
ASTU::Output: AsyncRead + AsyncWrite + Unpin,
{
pub(crate) fn new(conn: AsyncConnection<AS, ASTU>) -> Self {
Self { conn }
}
pub async fn login<U: AsRef<str>, P: AsRef<str>>(
mut self,
username: U,
password: P,
) -> result::Result<AsyncSession<AS, ASTU>, (Error, Self)> {
let u = ok_or_unauth_client_err!(validate_str(username.as_ref()), self);
let p = ok_or_unauth_client_err!(validate_str(password.as_ref()), self);
ok_or_unauth_client_err!(
self.run_command_and_check_ok(&format!("LOGIN {} {}", u, p))
.await,
self
);
Ok(AsyncSession::new(self.conn))
}
}