aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-01-17 10:14:48 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-01-17 10:14:48 +0100
commit1a0247e9352619bed45dfb8101133261cfecb512 (patch)
treef232ee1f31c1a6b47ee60c5ee5e465c2fbe35121
parent0eb8156cde27c54734cbe3d269ab05a876ef53ac (diff)
downloadaerogramme-1a0247e9352619bed45dfb8101133261cfecb512.tar.gz
aerogramme-1a0247e9352619bed45dfb8101133261cfecb512.zip
WIP idle
-rw-r--r--src/imap/command/selected.rs5
-rw-r--r--src/imap/flow.rs11
-rw-r--r--src/imap/mod.rs48
-rw-r--r--src/imap/request.rs2
-rw-r--r--src/imap/response.rs3
-rw-r--r--src/imap/session.rs10
6 files changed, 59 insertions, 20 deletions
diff --git a/src/imap/command/selected.rs b/src/imap/command/selected.rs
index c9c5337..b62e2cb 100644
--- a/src/imap/command/selected.rs
+++ b/src/imap/command/selected.rs
@@ -81,7 +81,10 @@ pub async fn dispatch<'a>(
// IDLE extension (rfc2177)
CommandBody::Idle => {
- unimplemented!()
+ Ok((
+ Response::build().to_req(ctx.req).message("DUMMY response due to anti-pattern").ok()?,
+ flow::Transition::Idle(tokio::sync::Notify::new()),
+ ))
}
// In selected mode, we fallback to authenticated when needed
diff --git a/src/imap/flow.rs b/src/imap/flow.rs
index ff348ca..d1e27d4 100644
--- a/src/imap/flow.rs
+++ b/src/imap/flow.rs
@@ -1,6 +1,7 @@
use std::error::Error as StdError;
use std::fmt;
use std::sync::Arc;
+use tokio::sync::Notify;
use crate::imap::mailbox_view::MailboxView;
use crate::mail::user::User;
@@ -20,7 +21,7 @@ pub enum State {
NotAuthenticated,
Authenticated(Arc<User>),
Selected(Arc<User>, MailboxView, MailboxPerm),
- Idle(Arc<User>, MailboxView, MailboxPerm),
+ Idle(Arc<User>, MailboxView, MailboxPerm, Notify),
Logout,
}
@@ -34,7 +35,7 @@ pub enum Transition {
None,
Authenticate(Arc<User>),
Select(MailboxView, MailboxPerm),
- Idle,
+ Idle(Notify),
UnIdle,
Unselect,
Logout,
@@ -54,10 +55,10 @@ impl State {
(State::Selected(u, _, _) , Transition::Unselect) => {
State::Authenticated(u.clone())
}
- (State::Selected(u, m, p), Transition::Idle) => {
- State::Idle(u, m, p)
+ (State::Selected(u, m, p), Transition::Idle(s)) => {
+ State::Idle(u, m, p, 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/mod.rs b/src/imap/mod.rs
index baa15f7..edfbbc4 100644
--- a/src/imap/mod.rs
+++ b/src/imap/mod.rs
@@ -101,9 +101,10 @@ use tokio::sync::mpsc::*;
enum LoopMode {
Quit,
Interactive,
- IdleUntil(tokio::sync::Notify),
+ Idle,
}
+// @FIXME a full refactor of this part of the code will be needed sooner or later
struct NetLoop {
ctx: ClientContext,
server: ServerFlow,
@@ -189,7 +190,7 @@ impl NetLoop {
loop {
mode = match mode {
LoopMode::Interactive => self.interactive_mode().await?,
- LoopMode::IdleUntil(notif) => self.idle_mode(notif).await?,
+ LoopMode::Idle => self.idle_mode().await?,
LoopMode::Quit => break,
}
}
@@ -237,15 +238,18 @@ impl NetLoop {
}
self.server.enqueue_status(response.completion);
},
- Some(ResponseOrIdle::Idle) => {
- let cr = CommandContinuationRequest::basic(None, "idling")?;
+ Some(ResponseOrIdle::StartIdle) => {
+ let cr = CommandContinuationRequest::basic(None, "Idling")?;
self.server.enqueue_continuation(cr);
- return Ok(LoopMode::IdleUntil(tokio::sync::Notify::new()))
+ self.cmd_tx.try_send(Request::Idle)?;
+ return Ok(LoopMode::Idle)
},
None => {
self.server.enqueue_status(Status::bye(None, "Internal session exited").unwrap());
tracing::error!("session task exited for {:?}, quitting", self.ctx.addr);
},
+ Some(_) => unreachable!(),
+
},
// When receiving a CTRL+C
@@ -256,7 +260,37 @@ impl NetLoop {
Ok(LoopMode::Interactive)
}
- async fn idle_mode(&mut self, notif: tokio::sync::Notify) -> Result<LoopMode> {
- Ok(LoopMode::IdleUntil(notif))
+ async fn idle_mode(&mut self) -> Result<LoopMode> {
+ tokio::select! {
+ maybe_msg = self.resp_rx.recv() => match maybe_msg {
+ Some(ResponseOrIdle::Response(response)) => {
+ for body_elem in response.body.into_iter() {
+ let _handle = match body_elem {
+ Body::Data(d) => self.server.enqueue_data(d),
+ Body::Status(s) => self.server.enqueue_status(s),
+ };
+ }
+ self.server.enqueue_status(response.completion);
+ return Ok(LoopMode::Interactive)
+ },
+ Some(ResponseOrIdle::IdleEvent(elems)) => {
+ for body_elem in elems.into_iter() {
+ let _handle = match body_elem {
+ Body::Data(d) => self.server.enqueue_data(d),
+ Body::Status(s) => self.server.enqueue_status(s),
+ };
+ }
+ return Ok(LoopMode::Idle)
+ },
+ None => {
+ self.server.enqueue_status(Status::bye(None, "Internal session exited").unwrap());
+ tracing::error!("session task exited for {:?}, quitting", self.ctx.addr);
+ return Ok(LoopMode::Interactive)
+ },
+ Some(ResponseOrIdle::StartIdle) => unreachable!(),
+ }
+ };
+ /*self.cmd_tx.try_send(Request::Idle).unwrap();
+ Ok(LoopMode::Idle)*/
}
}
diff --git a/src/imap/request.rs b/src/imap/request.rs
index c458276..2382b09 100644
--- a/src/imap/request.rs
+++ b/src/imap/request.rs
@@ -4,5 +4,5 @@ use tokio::sync::Notify;
#[derive(Debug)]
pub enum Request {
ImapCommand(Command<'static>),
- IdleUntil(Notify),
+ Idle,
}
diff --git a/src/imap/response.rs b/src/imap/response.rs
index a9978e1..7b7f92d 100644
--- a/src/imap/response.rs
+++ b/src/imap/response.rs
@@ -116,5 +116,6 @@ impl<'a> Response<'a> {
#[derive(Debug)]
pub enum ResponseOrIdle {
Response(Response<'static>),
- Idle,
+ StartIdle,
+ IdleEvent(Vec<Body<'static>>),
}
diff --git a/src/imap/session.rs b/src/imap/session.rs
index 11c2764..d15016f 100644
--- a/src/imap/session.rs
+++ b/src/imap/session.rs
@@ -27,14 +27,14 @@ impl Instance {
pub async fn request(&mut self, req: Request) -> ResponseOrIdle {
match req {
- Request::IdleUntil(stop) => ResponseOrIdle::Response(self.idle(stop).await),
+ Request::Idle => ResponseOrIdle::Response(self.idle().await),
Request::ImapCommand(cmd) => self.command(cmd).await,
}
}
- pub async fn idle(&mut self, stop: tokio::sync::Notify) -> Response<'static> {
- let (user, mbx) = match &mut self.state {
- flow::State::Idle(ref user, ref mut mailbox, ref perm) => (user, mailbox),
+ 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!(),
};
@@ -109,7 +109,7 @@ impl Instance {
}
match self.state {
- flow::State::Idle(..) => ResponseOrIdle::Idle,
+ flow::State::Idle(..) => ResponseOrIdle::StartIdle,
_ => ResponseOrIdle::Response(resp),
}
}