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