use std::{ collections::BTreeMap, sync::{atomic::AtomicU32, Arc}, time::Duration, }; use ahash::AHashMap; use dashmap::DashMap; use imap_proto::{ protocol::{list::Attribute, ProtocolVersion}, receiver::Receiver, Command, ResponseCode, StatusResponse, }; use jmap::{ auth::{ rate_limit::{AuthenticatedLimiter, RemoteAddress}, AccessToken, }, JMAP, }; use parking_lot::Mutex; use tokio::{ io::{AsyncRead, ReadHalf}, sync::{mpsc, watch}, }; use utils::{ config::Rate, listener::{limiter::InFlight, ServerInstance}, }; pub mod client; pub mod mailbox; pub mod message; pub mod session; pub mod writer; #[derive(Clone)] pub struct ImapSessionManager { pub jmap: Arc, pub imap: Arc, } impl ImapSessionManager { pub fn new(jmap: Arc, imap: Arc) -> Self { Self { jmap, imap } } } pub struct IMAP { pub max_request_size: usize, pub max_auth_failures: u32, pub name_shared: String, pub name_all: String, pub allow_plain_auth: bool, pub timeout_auth: Duration, pub timeout_unauth: Duration, pub timeout_idle: Duration, pub greeting_plain: Vec, pub greeting_tls: Vec, pub rate_limiter: DashMap>>, pub rate_requests: Rate, pub rate_concurrent: u64, } pub struct Session { pub jmap: Arc, pub imap: Arc, pub instance: Arc, pub receiver: Receiver, pub version: ProtocolVersion, pub state: State, pub is_tls: bool, pub is_condstore: bool, pub is_qresync: bool, pub writer: mpsc::Sender, pub stream_rx: ReadHalf, pub in_flight: InFlight, pub remote_addr: RemoteAddress, pub span: tracing::Span, } pub struct SessionData { pub account_id: u32, pub jmap: Arc, pub imap: Arc, pub span: tracing::Span, pub mailboxes: parking_lot::Mutex>, pub writer: mpsc::Sender, pub state: AtomicU32, pub in_flight: InFlight, } #[derive(Debug, Default)] pub struct Mailbox { pub has_children: bool, pub is_subscribed: bool, pub special_use: Option, pub total_messages: Option, pub total_unseen: Option, pub total_deleted: Option, pub uid_validity: Option, pub uid_next: Option, pub size: Option, } #[derive(Debug)] pub struct Account { pub account_id: u32, pub prefix: Option, pub mailbox_names: BTreeMap, pub mailbox_state: AHashMap, pub state_email: Option, pub state_mailbox: Option, } pub struct SelectedMailbox { pub id: MailboxId, pub state: parking_lot::Mutex, pub saved_search: parking_lot::Mutex, pub is_select: bool, pub is_condstore: bool, } #[derive(Debug, PartialEq, Eq)] pub struct MailboxId { pub account_id: u32, pub mailbox_id: Option, } #[derive(Debug)] pub struct MailboxState { pub uid_next: u32, pub uid_validity: u32, pub uid_max: u32, pub id_to_imap: AHashMap, pub uid_to_id: AHashMap, pub total_messages: usize, pub modseq: Option, pub next_state: Option>, } #[derive(Debug)] pub struct NextMailboxState { pub next_state: MailboxState, pub deletions: Vec, } #[derive(Debug, Default)] pub struct MailboxSync { pub added: Vec, pub changed: Vec, pub deleted: Vec, } pub enum SavedSearch { InFlight { rx: watch::Receiver>>, }, Results { items: Arc>, }, None, } #[derive(Debug, Clone, Copy, Default)] pub struct ImapId { pub uid: u32, pub seqnum: u32, } pub enum State { NotAuthenticated { auth_failures: u32, }, Authenticated { data: Arc, }, Selected { data: Arc, mailbox: Arc, }, } impl SessionData { pub async fn get_access_token(&self) -> crate::op::Result> { self.jmap .get_cached_access_token(self.account_id) .await .ok_or_else(|| { StatusResponse::no("Failed to obtain access token") .with_code(ResponseCode::ContactAdmin) }) } }