melib/imap/sync/
cache.rs

1/*
2 * meli - imap melib
3 *
4 * Copyright 2020 Manos Pitsidianakis
5 *
6 * This file is part of meli.
7 *
8 * meli is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * meli is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with meli. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22use std::{convert::TryFrom, path::Path};
23
24use super::*;
25use crate::{
26    backends::MailboxHash,
27    email::{Envelope, EnvelopeHash},
28    error::*,
29};
30
31#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
32pub struct ModSequence(pub std::num::NonZeroU64);
33
34impl TryFrom<i64> for ModSequence {
35    type Error = ();
36    fn try_from(val: i64) -> std::result::Result<Self, ()> {
37        std::num::NonZeroU64::new(val as u64)
38            .map(|u| Ok(Self(u)))
39            .unwrap_or(Err(()))
40    }
41}
42
43impl std::fmt::Display for ModSequence {
44    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
45        write!(fmt, "{}", &self.0)
46    }
47}
48
49#[derive(Debug)]
50pub struct CachedEnvelope {
51    pub inner: Envelope,
52    pub uid: UID,
53    pub mailbox_hash: MailboxHash,
54    pub modsequence: Option<ModSequence>,
55}
56
57#[derive(Clone, Copy, Debug)]
58pub struct CachedState {
59    pub uidvalidity: UID,
60    pub highestmodseq: Option<ModSequence>,
61}
62
63/// Helper function for ignoring cache misses with
64/// `.or_else(ignore_not_found)?`.
65pub fn ignore_not_found(err: Error) -> Result<()> {
66    if matches!(err.kind, ErrorKind::NotFound) {
67        return Ok(());
68    }
69    Err(err)
70}
71
72pub trait ImapCache: Send + std::fmt::Debug {
73    fn reset(&mut self) -> Result<()>;
74    fn mailbox_state(&mut self, mailbox_hash: MailboxHash) -> Result<Option<CachedState>>;
75
76    fn max_uid(&mut self, mailbox_hash: MailboxHash) -> Result<Option<UID>>;
77
78    fn find_envelope(
79        &mut self,
80        identifier: std::result::Result<UID, EnvelopeHash>,
81        mailbox_hash: MailboxHash,
82    ) -> Result<Option<CachedEnvelope>>;
83
84    fn update(
85        &mut self,
86        mailbox_hash: MailboxHash,
87        refresh_events: &[(UID, RefreshEvent)],
88    ) -> Result<()>;
89
90    fn update_mailbox(
91        &mut self,
92        mailbox_hash: MailboxHash,
93        select_response: &SelectResponse,
94    ) -> Result<()>;
95
96    fn insert_envelopes(
97        &mut self,
98        mailbox_hash: MailboxHash,
99        fetches: &[FetchResponse<'_>],
100    ) -> Result<()>;
101
102    fn envelopes(
103        &mut self,
104        mailbox_hash: MailboxHash,
105        max_uid: UID,
106        batch_size: usize,
107    ) -> Result<Option<Vec<EnvelopeHash>>>;
108
109    fn init_mailbox(
110        &mut self,
111        mailbox_hash: MailboxHash,
112        select_response: &SelectResponse,
113    ) -> Result<()>;
114
115    fn rfc822(
116        &mut self,
117        identifier: std::result::Result<UID, EnvelopeHash>,
118        mailbox_hash: MailboxHash,
119    ) -> Result<Option<Vec<u8>>>;
120
121    fn update_flags(
122        &mut self,
123        env_hashes: EnvelopeHashBatch,
124        mailbox_hash: MailboxHash,
125        flags: SmallVec<[FlagOp; 8]>,
126    ) -> Result<()>;
127}
128
129pub trait ImapCacheReset: Send + std::fmt::Debug {
130    fn reset_db(uid_store: &UIDStore, data_dir: Option<&Path>) -> Result<()>
131    where
132        Self: Sized;
133}
134
135impl ImapCache for Arc<UIDStore> {
136    fn reset(&mut self) -> Result<()> {
137        if !self.keep_offline_cache.load(Ordering::SeqCst) {
138            return Ok(());
139        }
140        #[cfg(feature = "sqlite3")]
141        {
142            sync::sqlite3_cache::Sqlite3Cache::reset_db(self, None)?;
143        }
144        Ok(())
145    }
146
147    fn mailbox_state(&mut self, mailbox_hash: MailboxHash) -> Result<Option<CachedState>> {
148        if !self.keep_offline_cache.load(Ordering::SeqCst) {
149            return Ok(None);
150        }
151        let mut mutex = self.offline_cache.lock().unwrap();
152        self.init_cache(&mut mutex)?;
153
154        if let Some(ref mut cache_handle) = *mutex {
155            return cache_handle.mailbox_state(mailbox_hash);
156        }
157        Ok(None)
158    }
159
160    fn max_uid(&mut self, mailbox_hash: MailboxHash) -> Result<Option<UID>> {
161        if !self.keep_offline_cache.load(Ordering::SeqCst) {
162            return Ok(None);
163        }
164        let mut mutex = self.offline_cache.lock().unwrap();
165        self.init_cache(&mut mutex)?;
166
167        if let Some(ref mut cache_handle) = *mutex {
168            return cache_handle.max_uid(mailbox_hash);
169        }
170        Ok(None)
171    }
172
173    fn find_envelope(
174        &mut self,
175        identifier: std::result::Result<UID, EnvelopeHash>,
176        mailbox_hash: MailboxHash,
177    ) -> Result<Option<CachedEnvelope>> {
178        if !self.keep_offline_cache.load(Ordering::SeqCst) {
179            return Ok(None);
180        }
181        let mut mutex = self.offline_cache.lock().unwrap();
182        self.init_cache(&mut mutex)?;
183
184        if let Some(ref mut cache_handle) = *mutex {
185            return cache_handle.find_envelope(identifier, mailbox_hash);
186        }
187        Ok(None)
188    }
189
190    fn update(
191        &mut self,
192        mailbox_hash: MailboxHash,
193        refresh_events: &[(UID, RefreshEvent)],
194    ) -> Result<()> {
195        if !self.keep_offline_cache.load(Ordering::SeqCst) {
196            return Ok(());
197        }
198        let mut mutex = self.offline_cache.lock().unwrap();
199        self.init_cache(&mut mutex)?;
200
201        if let Some(ref mut cache_handle) = *mutex {
202            return cache_handle.update(mailbox_hash, refresh_events);
203        }
204        Ok(())
205    }
206
207    fn update_mailbox(
208        &mut self,
209        mailbox_hash: MailboxHash,
210        select_response: &SelectResponse,
211    ) -> Result<()> {
212        if !self.keep_offline_cache.load(Ordering::SeqCst) {
213            return Ok(());
214        }
215        let mut mutex = self.offline_cache.lock().unwrap();
216        self.init_cache(&mut mutex)?;
217
218        if let Some(ref mut cache_handle) = *mutex {
219            return cache_handle.update_mailbox(mailbox_hash, select_response);
220        }
221        Ok(())
222    }
223
224    fn insert_envelopes(
225        &mut self,
226        mailbox_hash: MailboxHash,
227        fetches: &[FetchResponse<'_>],
228    ) -> Result<()> {
229        if !self.keep_offline_cache.load(Ordering::SeqCst) {
230            return Ok(());
231        }
232        let mut mutex = self.offline_cache.lock().unwrap();
233        self.init_cache(&mut mutex)?;
234
235        if let Some(ref mut cache_handle) = *mutex {
236            return cache_handle.insert_envelopes(mailbox_hash, fetches);
237        }
238        Ok(())
239    }
240
241    fn envelopes(
242        &mut self,
243        mailbox_hash: MailboxHash,
244        max_uid: UID,
245        batch_size: usize,
246    ) -> Result<Option<Vec<EnvelopeHash>>> {
247        if !self.keep_offline_cache.load(Ordering::SeqCst) {
248            return Ok(None);
249        }
250        let mut mutex = self.offline_cache.lock().unwrap();
251        self.init_cache(&mut mutex)?;
252
253        if let Some(ref mut cache_handle) = *mutex {
254            return cache_handle.envelopes(mailbox_hash, max_uid, batch_size);
255        }
256        Ok(None)
257    }
258
259    fn init_mailbox(
260        &mut self,
261        mailbox_hash: MailboxHash,
262        select_response: &SelectResponse,
263    ) -> Result<()> {
264        if !self.keep_offline_cache.load(Ordering::SeqCst) {
265            return Ok(());
266        }
267        let mut mutex = self.offline_cache.lock().unwrap();
268        self.init_cache(&mut mutex)?;
269
270        if let Some(ref mut cache_handle) = *mutex {
271            return cache_handle.init_mailbox(mailbox_hash, select_response);
272        }
273        Ok(())
274    }
275
276    fn rfc822(
277        &mut self,
278        identifier: std::result::Result<UID, EnvelopeHash>,
279        mailbox_hash: MailboxHash,
280    ) -> Result<Option<Vec<u8>>> {
281        if !self.keep_offline_cache.load(Ordering::SeqCst) {
282            return Ok(None);
283        }
284        let mut mutex = self.offline_cache.lock().unwrap();
285        self.init_cache(&mut mutex)?;
286
287        if let Some(ref mut cache_handle) = *mutex {
288            return cache_handle.rfc822(identifier, mailbox_hash);
289        }
290        Ok(None)
291    }
292
293    fn update_flags(
294        &mut self,
295        env_hashes: EnvelopeHashBatch,
296        mailbox_hash: MailboxHash,
297        flags: SmallVec<[FlagOp; 8]>,
298    ) -> Result<()> {
299        if !self.keep_offline_cache.load(Ordering::SeqCst) {
300            return Ok(());
301        }
302        let mut mutex = self.offline_cache.lock().unwrap();
303        self.init_cache(&mut mutex)?;
304
305        if let Some(ref mut cache_handle) = *mutex {
306            return cache_handle.update_flags(env_hashes, mailbox_hash, flags);
307        }
308        Ok(())
309    }
310}