Skip to main content

imap_client/client/
mod.rs

1pub mod tokio;
2pub mod verifier;
3
4use std::time::Duration;
5
6use imap_next::{
7    client::Options as ClientOptions,
8    imap_types::{auth::AuthMechanism, core::Vec1, response::Capability},
9};
10
11use crate::tasks::resolver::Resolver;
12
13pub struct Client {
14    resolver: Resolver,
15    capabilities: Vec1<Capability<'static>>,
16    idle_timeout: Duration,
17}
18
19impl Client {
20    pub fn new(opts: ClientOptions) -> Self {
21        let client = imap_next::client::Client::new(opts);
22        let resolver = Resolver::new(client);
23
24        Self {
25            resolver,
26            capabilities: Vec1::from(Capability::Imap4Rev1),
27            idle_timeout: Duration::from_secs(5 * 60), // 5 min
28        }
29    }
30
31    pub fn get_idle_timeout(&self) -> &Duration {
32        &self.idle_timeout
33    }
34
35    pub fn set_idle_timeout(&mut self, timeout: Duration) {
36        self.idle_timeout = timeout;
37    }
38
39    pub fn set_some_idle_timeout(&mut self, timeout: Option<Duration>) {
40        if let Some(timeout) = timeout {
41            self.set_idle_timeout(timeout)
42        }
43    }
44
45    pub fn with_idle_timeout(mut self, timeout: Duration) -> Self {
46        self.set_idle_timeout(timeout);
47        self
48    }
49
50    pub fn with_some_idle_timeout(mut self, timeout: Option<Duration>) -> Self {
51        self.set_some_idle_timeout(timeout);
52        self
53    }
54
55    /// Returns the server capabilities.
56    ///
57    /// This function does not *fetch* capabilities from server, it
58    /// just returns capabilities saved during the creation of this
59    /// client (using [`Client::insecure`], [`Client::tls`] or
60    /// [`Client::starttls`]).
61    pub fn capabilities(&self) -> &Vec1<Capability<'static>> {
62        &self.capabilities
63    }
64
65    /// Returns the server capabilities, as an iterator.
66    ///
67    /// Same as [`Client::capabilities`], but just returns an iterator
68    /// instead.
69    pub fn capabilities_iter(&self) -> impl Iterator<Item = &Capability<'static>> + '_ {
70        self.capabilities().as_ref().iter()
71    }
72
73    /// Returns supported authentication mechanisms, as an iterator.
74    pub fn supported_auth_mechanisms(&self) -> impl Iterator<Item = &AuthMechanism<'static>> + '_ {
75        self.capabilities_iter().filter_map(|capability| {
76            if let Capability::Auth(mechanism) = capability {
77                Some(mechanism)
78            } else {
79                None
80            }
81        })
82    }
83
84    /// Returns `true` if the given authentication mechanism is
85    /// supported by the server.
86    pub fn supports_auth_mechanism(&self, mechanism: AuthMechanism<'static>) -> bool {
87        self.capabilities_iter().any(|capability| {
88            if let Capability::Auth(m) = capability {
89                m == &mechanism
90            } else {
91                false
92            }
93        })
94    }
95
96    /// Returns `true` if `LOGIN` is supported by the server.
97    pub fn login_supported(&self) -> bool {
98        !self
99            .capabilities_iter()
100            .any(|c| matches!(c, Capability::LoginDisabled))
101    }
102
103    /// Returns `true` if the `ENABLE` extension is supported by the
104    /// server.
105    pub fn ext_enable_supported(&self) -> bool {
106        self.capabilities_iter()
107            .any(|c| matches!(c, Capability::Enable))
108    }
109
110    /// Returns `true` if the `SASL-IR` extension is supported by the
111    /// server.
112    pub fn ext_sasl_ir_supported(&self) -> bool {
113        self.capabilities_iter()
114            .any(|c| matches!(c, Capability::SaslIr))
115    }
116
117    /// Returns `true` if the `ID` extension is supported by the
118    /// server.
119    pub fn ext_id_supported(&self) -> bool {
120        self.capabilities_iter()
121            .any(|c| matches!(c, Capability::Id))
122    }
123
124    /// Returns `true` if the `UIDPLUS` extension is supported by the
125    /// server.
126    pub fn ext_uidplus_supported(&self) -> bool {
127        self.capabilities_iter()
128            .any(|c| matches!(c, Capability::UidPlus))
129    }
130
131    /// Returns `true` if the `SORT` extension is supported by the
132    /// server.
133    pub fn ext_sort_supported(&self) -> bool {
134        self.capabilities_iter()
135            .any(|c| matches!(c, Capability::Sort(_)))
136    }
137
138    /// Returns `true` if the `THREAD` extension is supported by the
139    /// server.
140    pub fn ext_thread_supported(&self) -> bool {
141        self.capabilities_iter()
142            .any(|c| matches!(c, Capability::Thread(_)))
143    }
144
145    /// Returns `true` if the `IDLE` extension is supported by the
146    /// server.
147    pub fn ext_idle_supported(&self) -> bool {
148        self.capabilities_iter()
149            .any(|c| matches!(c, Capability::Idle))
150    }
151
152    /// Returns `true` if the `BINARY` extension is supported by the
153    /// server.
154    pub fn ext_binary_supported(&self) -> bool {
155        self.capabilities_iter()
156            .any(|c| matches!(c, Capability::Binary))
157    }
158
159    /// Returns `true` if the `MOVE` extension is supported by the
160    /// server.
161    pub fn ext_move_supported(&self) -> bool {
162        self.capabilities_iter()
163            .any(|c| matches!(c, Capability::Move))
164    }
165}