aboutsummaryrefslogtreecommitdiff
path: root/src/imap
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-01-18 17:33:57 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-01-18 17:33:57 +0100
commit185033c462b92854117bc57258bf33b3579a7ca5 (patch)
tree172ce596ddbae14950a49bd1893b8cd032e28783 /src/imap
parente1161cab0e71ec604e376d2d87f7d1226f3f0244 (diff)
downloadaerogramme-185033c462b92854117bc57258bf33b3579a7ca5.tar.gz
aerogramme-185033c462b92854117bc57258bf33b3579a7ca5.zip
idling works!!!
Diffstat (limited to 'src/imap')
-rw-r--r--src/imap/command/selected.rs2
-rw-r--r--src/imap/flow.rs11
-rw-r--r--src/imap/mailbox_view.rs6
-rw-r--r--src/imap/session.rs38
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),
}
}