| | use std::collections::BTreeMap; |
| | use std::ops::{Deref, DerefMut}; |
| |
|
| | use anyhow::{Context as _, Result}; |
| | use async_imap::Session as ImapSession; |
| | use async_imap::types::Mailbox; |
| | use futures::TryStreamExt; |
| | use tokio::sync::Mutex; |
| |
|
| | use crate::imap::capabilities::Capabilities; |
| | use crate::net::session::SessionStream; |
| | use crate::tools; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | const PREFETCH_FLAGS: &str = "(UID INTERNALDATE RFC822.SIZE BODY.PEEK[HEADER.FIELDS (\ |
| | MESSAGE-ID \ |
| | DATE \ |
| | X-MICROSOFT-ORIGINAL-MESSAGE-ID \ |
| | FROM \ |
| | IN-REPLY-TO REFERENCES \ |
| | CHAT-VERSION \ |
| | AUTO-SUBMITTED \ |
| | AUTOCRYPT-SETUP-MESSAGE\ |
| | )])"; |
| |
|
| | #[derive(Debug)] |
| | pub(crate) struct Session { |
| | transport_id: u32, |
| |
|
| | pub(super) inner: ImapSession<Box<dyn SessionStream>>, |
| |
|
| | pub capabilities: Capabilities, |
| |
|
| | |
| | pub selected_folder: Option<String>, |
| |
|
| | |
| | pub selected_mailbox: Option<Mailbox>, |
| |
|
| | pub selected_folder_needs_expunge: bool, |
| |
|
| | pub(crate) last_full_folder_scan: Mutex<Option<tools::Time>>, |
| |
|
| | |
| | |
| | |
| | pub new_mail: bool, |
| |
|
| | pub resync_request_sender: async_channel::Sender<()>, |
| | } |
| |
|
| | impl Deref for Session { |
| | type Target = ImapSession<Box<dyn SessionStream>>; |
| |
|
| | fn deref(&self) -> &Self::Target { |
| | &self.inner |
| | } |
| | } |
| |
|
| | impl DerefMut for Session { |
| | fn deref_mut(&mut self) -> &mut Self::Target { |
| | &mut self.inner |
| | } |
| | } |
| |
|
| | impl Session { |
| | pub(crate) fn new( |
| | inner: ImapSession<Box<dyn SessionStream>>, |
| | capabilities: Capabilities, |
| | resync_request_sender: async_channel::Sender<()>, |
| | transport_id: u32, |
| | ) -> Self { |
| | Self { |
| | transport_id, |
| | inner, |
| | capabilities, |
| | selected_folder: None, |
| | selected_mailbox: None, |
| | selected_folder_needs_expunge: false, |
| | last_full_folder_scan: Mutex::new(None), |
| | new_mail: false, |
| | resync_request_sender, |
| | } |
| | } |
| |
|
| | |
| | pub(crate) fn transport_id(&self) -> u32 { |
| | self.transport_id |
| | } |
| |
|
| | pub fn can_idle(&self) -> bool { |
| | self.capabilities.can_idle |
| | } |
| |
|
| | pub fn can_move(&self) -> bool { |
| | self.capabilities.can_move |
| | } |
| |
|
| | pub fn can_check_quota(&self) -> bool { |
| | self.capabilities.can_check_quota |
| | } |
| |
|
| | pub fn can_condstore(&self) -> bool { |
| | self.capabilities.can_condstore |
| | } |
| |
|
| | pub fn can_metadata(&self) -> bool { |
| | self.capabilities.can_metadata |
| | } |
| |
|
| | pub fn can_push(&self) -> bool { |
| | self.capabilities.can_push |
| | } |
| |
|
| | |
| | pub fn is_chatmail(&self) -> bool { |
| | self.capabilities.is_chatmail |
| | } |
| |
|
| | |
| | pub async fn list_folders(&mut self) -> Result<Vec<async_imap::types::Name>> { |
| | let list = self.list(Some(""), Some("*")).await?.try_collect().await?; |
| | Ok(list) |
| | } |
| |
|
| | |
| | |
| | pub(crate) async fn prefetch( |
| | &mut self, |
| | uid_next: u32, |
| | n_uids: u32, |
| | ) -> Result<Vec<(u32, async_imap::types::Fetch)>> { |
| | let uid_last = uid_next.saturating_add(n_uids - 1); |
| | |
| | let set = format!("{uid_next}:{uid_last}"); |
| | let mut list = self |
| | .uid_fetch(set, PREFETCH_FLAGS) |
| | .await |
| | .context("IMAP could not fetch")?; |
| |
|
| | let mut msgs = BTreeMap::new(); |
| | while let Some(msg) = list.try_next().await? { |
| | if let Some(msg_uid) = msg.uid { |
| | msgs.insert((msg.internal_date(), msg_uid), msg); |
| | } |
| | } |
| |
|
| | Ok(msgs.into_iter().map(|((_, uid), msg)| (uid, msg)).collect()) |
| | } |
| | } |
| |
|