imap_client/client/
mod.rs

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