diff options
Diffstat (limited to 'src/imap')
-rw-r--r-- | src/imap/command/selected.rs | 2 | ||||
-rw-r--r-- | src/imap/flow.rs | 11 | ||||
-rw-r--r-- | src/imap/mailbox_view.rs | 6 | ||||
-rw-r--r-- | src/imap/session.rs | 38 |
4 files changed, 38 insertions, 19 deletions
diff --git a/src/imap/command/selected.rs b/src/imap/command/selected.rs index 4eb4e61..ca2e268 100644 --- a/src/imap/command/selected.rs +++ b/src/imap/command/selected.rs @@ -83,7 +83,7 @@ pub async fn dispatch<'a>( CommandBody::Idle => { Ok(( Response::build().to_req(ctx.req).message("DUMMY command due to anti-pattern in the code").ok()?, - flow::Transition::Idle(tokio::sync::Notify::new()), + flow::Transition::Idle(ctx.req.tag.clone(), tokio::sync::Notify::new()), )) } diff --git a/src/imap/flow.rs b/src/imap/flow.rs index 37f225b..72d9e8e 100644 --- a/src/imap/flow.rs +++ b/src/imap/flow.rs @@ -3,6 +3,7 @@ use std::fmt; use std::sync::Arc; use tokio::sync::Notify; +use imap_codec::imap_types::core::Tag; use crate::imap::mailbox_view::MailboxView; use crate::mail::user::User; @@ -21,7 +22,7 @@ pub enum State { NotAuthenticated, Authenticated(Arc<User>), Selected(Arc<User>, MailboxView, MailboxPerm), - Idle(Arc<User>, MailboxView, MailboxPerm, Arc<Notify>), + Idle(Arc<User>, MailboxView, MailboxPerm, Tag<'static>, Arc<Notify>), Logout, } @@ -35,7 +36,7 @@ pub enum Transition { None, Authenticate(Arc<User>), Select(MailboxView, MailboxPerm), - Idle(Notify), + Idle(Tag<'static>, Notify), UnIdle, Unselect, Logout, @@ -55,10 +56,10 @@ impl State { (State::Selected(u, _, _) , Transition::Unselect) => { State::Authenticated(u.clone()) } - (State::Selected(u, m, p), Transition::Idle(s)) => { - State::Idle(u, m, p, Arc::new(s)) + (State::Selected(u, m, p), Transition::Idle(t, s)) => { + State::Idle(u, m, p, t, Arc::new(s)) }, - (State::Idle(u, m, p, _), Transition::UnIdle) => { + (State::Idle(u, m, p, _, _), Transition::UnIdle) => { State::Selected(u, m, p) }, (_, Transition::Logout) => State::Logout, diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs index 07fa3ad..85a4961 100644 --- a/src/imap/mailbox_view.rs +++ b/src/imap/mailbox_view.rs @@ -224,6 +224,12 @@ impl MailboxView { Ok((summary, conflict_id_or_uid)) } + pub async fn idle_sync(&mut self) -> Result<Vec<Body<'static>>> { + self.internal.mailbox.notify().await.upgrade().ok_or(anyhow!("test"))?.notified().await; + self.internal.mailbox.opportunistic_sync().await?; + self.update(UpdateParameters::default()).await + } + pub async fn expunge(&mut self) -> Result<Vec<Body<'static>>> { self.internal.sync().await?; let state = self.internal.peek().await; diff --git a/src/imap/session.rs b/src/imap/session.rs index 1d473ed..f4e3d0f 100644 --- a/src/imap/session.rs +++ b/src/imap/session.rs @@ -1,4 +1,4 @@ -use anyhow::anyhow; +use anyhow::{Result, anyhow, bail}; use crate::imap::capability::{ClientCapability, ServerCapability}; use crate::imap::command::{anonymous, authenticated, selected}; use crate::imap::flow; @@ -27,28 +27,40 @@ impl Instance { pub async fn request(&mut self, req: Request) -> ResponseOrIdle { match req { - Request::Idle => ResponseOrIdle::Response(self.idle().await), + Request::Idle => self.idle().await, Request::ImapCommand(cmd) => self.command(cmd).await, } } - pub async fn idle(&mut self) -> Response<'static> { - let (user, mbx, perm, stop) = match &mut self.state { - flow::State::Idle(ref user, ref mut mailbox, ref perm, ref stop) => (user, mailbox, perm, stop), - _ => unreachable!(), + pub async fn idle(&mut self) -> ResponseOrIdle { + match self.idle_happy().await { + Ok(r) => r, + Err(e) => { + tracing::error!(err=?e, "something bad happened in idle"); + ResponseOrIdle::Response(Response::bye().unwrap()) + } + } + } + + pub async fn idle_happy(&mut self) -> Result<ResponseOrIdle> { + let (mbx, tag, stop) = match &mut self.state { + flow::State::Idle(_, ref mut mbx, _, tag, stop) => (mbx, tag.clone(), stop.clone()), + _ => bail!("Invalid session state, can't idle"), }; tokio::select! { _ = stop.notified() => { - return Response::build() - .tag(imap_codec::imap_types::core::Tag::try_from("FIXME").unwrap()) + self.state.apply(flow::Transition::UnIdle)?; + return Ok(ResponseOrIdle::Response(Response::build() + .tag(tag.clone()) .message("IDLE completed") - .ok() - .unwrap() + .ok()?)) + }, + change = mbx.idle_sync() => { + tracing::debug!("idle event"); + return Ok(ResponseOrIdle::IdleEvent(change?)); } } - - unimplemented!(); } @@ -119,7 +131,7 @@ impl Instance { } match &self.state { - flow::State::Idle(_, _, _, n) => ResponseOrIdle::StartIdle(n.clone()), + flow::State::Idle(_, _, _, _, n) => ResponseOrIdle::StartIdle(n.clone()), _ => ResponseOrIdle::Response(resp), } } |