1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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>,
}

// ref https://github.com/jonhoo/rust-imap/blob/v2.2.0/src/client.rs#L88-L94
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
    }
}

// ref https://github.com/jonhoo/rust-imap/blob/v2.2.0/src/client.rs#L96-L100
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
    }
}

// ref https://github.com/jonhoo/rust-imap/blob/v2.2.0/src/client.rs#L226-L233
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 }
    }

    // ref https://github.com/jonhoo/rust-imap/blob/v2.2.0/src/client.rs#L307-L320
    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))
    }
}