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;
8
9use crate::imap::capabilities::Capabilities;
10use crate::net::session::SessionStream;
11
12const PREFETCH_FLAGS: &str = "(UID INTERNALDATE RFC822.SIZE BODY.PEEK[HEADER.FIELDS (\
20 MESSAGE-ID \
21 DATE \
22 X-MICROSOFT-ORIGINAL-MESSAGE-ID \
23 FROM \
24 IN-REPLY-TO REFERENCES \
25 CHAT-VERSION \
26 CHAT-IS-POST-MESSAGE \
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 new_mail: bool,
51
52 pub resync_request_sender: async_channel::Sender<()>,
53}
54
55impl Deref for Session {
56 type Target = ImapSession<Box<dyn SessionStream>>;
57
58 fn deref(&self) -> &Self::Target {
59 &self.inner
60 }
61}
62
63impl DerefMut for Session {
64 fn deref_mut(&mut self) -> &mut Self::Target {
65 &mut self.inner
66 }
67}
68
69impl Session {
70 pub(crate) fn new(
71 inner: ImapSession<Box<dyn SessionStream>>,
72 capabilities: Capabilities,
73 resync_request_sender: async_channel::Sender<()>,
74 transport_id: u32,
75 ) -> Self {
76 Self {
77 transport_id,
78 inner,
79 capabilities,
80 selected_folder: None,
81 selected_mailbox: None,
82 selected_folder_needs_expunge: false,
83 new_mail: false,
84 resync_request_sender,
85 }
86 }
87
88 pub(crate) fn transport_id(&self) -> u32 {
90 self.transport_id
91 }
92
93 pub fn can_idle(&self) -> bool {
94 self.capabilities.can_idle
95 }
96
97 pub fn can_move(&self) -> bool {
98 self.capabilities.can_move
99 }
100
101 pub fn can_check_quota(&self) -> bool {
102 self.capabilities.can_check_quota
103 }
104
105 pub fn can_condstore(&self) -> bool {
106 self.capabilities.can_condstore
107 }
108
109 pub fn can_metadata(&self) -> bool {
110 self.capabilities.can_metadata
111 }
112
113 pub fn can_push(&self) -> bool {
114 self.capabilities.can_push
115 }
116
117 pub fn is_chatmail(&self) -> bool {
119 self.capabilities.is_chatmail
120 }
121
122 pub async fn list_folders(&mut self) -> Result<Vec<async_imap::types::Name>> {
124 let list = self.list(Some(""), Some("*")).await?.try_collect().await?;
125 Ok(list)
126 }
127
128 pub(crate) async fn prefetch(
131 &mut self,
132 uid_next: u32,
133 n_uids: u32,
134 ) -> Result<Vec<(u32, async_imap::types::Fetch)>> {
135 let uid_last = uid_next.saturating_add(n_uids - 1);
136 let set = format!("{uid_next}:{uid_last}");
138 let mut list = self
139 .uid_fetch(set, PREFETCH_FLAGS)
140 .await
141 .context("IMAP could not fetch")?;
142
143 let mut msgs = BTreeMap::new();
144 while let Some(msg) = list.try_next().await? {
145 if let Some(msg_uid) = msg.uid {
146 msgs.insert((msg.internal_date(), msg_uid), msg);
147 }
148 }
149
150 Ok(msgs.into_iter().map(|((_, uid), msg)| (uid, msg)).collect())
151 }
152}