deltachat/imap/
session.rs1use std::collections::BTreeMap;
2use std::ops::{Deref, DerefMut};
3
4use anyhow::{Context as _, Result};
5use async_imap::Session as ImapSession;
6use async_imap::types::Mailbox;
7use futures::TryStreamExt;
8use tokio::sync::Mutex;
9
10use crate::imap::capabilities::Capabilities;
11use crate::net::session::SessionStream;
12use crate::tools;
13
14const PREFETCH_FLAGS: &str = "(UID INTERNALDATE RFC822.SIZE BODY.PEEK[HEADER.FIELDS (\
21 MESSAGE-ID \
22 DATE \
23 X-MICROSOFT-ORIGINAL-MESSAGE-ID \
24 FROM \
25 IN-REPLY-TO REFERENCES \
26 CHAT-VERSION \
27 AUTO-SUBMITTED \
28 AUTOCRYPT-SETUP-MESSAGE\
29 )])";
30
31#[derive(Debug)]
32pub(crate) struct Session {
33 transport_id: u32,
34
35 pub(super) inner: ImapSession<Box<dyn SessionStream>>,
36
37 pub capabilities: Capabilities,
38
39 pub selected_folder: Option<String>,
41
42 pub selected_mailbox: Option<Mailbox>,
44
45 pub selected_folder_needs_expunge: bool,
46
47 pub(crate) last_full_folder_scan: Mutex<Option<tools::Time>>,
48
49 pub new_mail: bool,
53
54 pub resync_request_sender: async_channel::Sender<()>,
55}
56
57impl Deref for Session {
58 type Target = ImapSession<Box<dyn SessionStream>>;
59
60 fn deref(&self) -> &Self::Target {
61 &self.inner
62 }
63}
64
65impl DerefMut for Session {
66 fn deref_mut(&mut self) -> &mut Self::Target {
67 &mut self.inner
68 }
69}
70
71impl Session {
72 pub(crate) fn new(
73 inner: ImapSession<Box<dyn SessionStream>>,
74 capabilities: Capabilities,
75 resync_request_sender: async_channel::Sender<()>,
76 transport_id: u32,
77 ) -> Self {
78 Self {
79 transport_id,
80 inner,
81 capabilities,
82 selected_folder: None,
83 selected_mailbox: None,
84 selected_folder_needs_expunge: false,
85 last_full_folder_scan: Mutex::new(None),
86 new_mail: false,
87 resync_request_sender,
88 }
89 }
90
91 pub(crate) fn transport_id(&self) -> u32 {
93 self.transport_id
94 }
95
96 pub fn can_idle(&self) -> bool {
97 self.capabilities.can_idle
98 }
99
100 pub fn can_move(&self) -> bool {
101 self.capabilities.can_move
102 }
103
104 pub fn can_check_quota(&self) -> bool {
105 self.capabilities.can_check_quota
106 }
107
108 pub fn can_condstore(&self) -> bool {
109 self.capabilities.can_condstore
110 }
111
112 pub fn can_metadata(&self) -> bool {
113 self.capabilities.can_metadata
114 }
115
116 pub fn can_push(&self) -> bool {
117 self.capabilities.can_push
118 }
119
120 pub fn is_chatmail(&self) -> bool {
122 self.capabilities.is_chatmail
123 }
124
125 pub async fn list_folders(&mut self) -> Result<Vec<async_imap::types::Name>> {
127 let list = self.list(Some(""), Some("*")).await?.try_collect().await?;
128 Ok(list)
129 }
130
131 pub(crate) async fn prefetch(
134 &mut self,
135 uid_next: u32,
136 n_uids: u32,
137 ) -> Result<Vec<(u32, async_imap::types::Fetch)>> {
138 let uid_last = uid_next.saturating_add(n_uids - 1);
139 let set = format!("{uid_next}:{uid_last}");
141 let mut list = self
142 .uid_fetch(set, PREFETCH_FLAGS)
143 .await
144 .context("IMAP could not fetch")?;
145
146 let mut msgs = BTreeMap::new();
147 while let Some(msg) = list.try_next().await? {
148 if let Some(msg_uid) = msg.uid {
149 msgs.insert((msg.internal_date(), msg_uid), msg);
150 }
151 }
152
153 Ok(msgs.into_iter().map(|((_, uid), msg)| (uid, msg)).collect())
154 }
155}