aboutsummaryrefslogtreecommitdiff
path: root/src/imap/session.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/imap/session.rs')
-rw-r--r--src/imap/session.rs52
1 files changed, 44 insertions, 8 deletions
diff --git a/src/imap/session.rs b/src/imap/session.rs
index 12bbfee..fa3232a 100644
--- a/src/imap/session.rs
+++ b/src/imap/session.rs
@@ -4,8 +4,8 @@ use crate::imap::flow;
use crate::imap::request::Request;
use crate::imap::response::{Response, ResponseOrIdle};
use crate::login::ArcLoginProvider;
-use anyhow::{anyhow, bail, Result};
-use imap_codec::imap_types::command::Command;
+use anyhow::{anyhow, bail, Context, Result};
+use imap_codec::imap_types::{command::Command, core::Tag};
//-----
pub struct Instance {
@@ -27,13 +27,48 @@ impl Instance {
pub async fn request(&mut self, req: Request) -> ResponseOrIdle {
match req {
- Request::Idle => self.idle().await,
+ Request::IdleStart(tag) => self.idle_init(tag),
+ Request::IdlePoll => self.idle_poll().await,
Request::ImapCommand(cmd) => self.command(cmd).await,
}
}
- pub async fn idle(&mut self) -> ResponseOrIdle {
- match self.idle_happy().await {
+ pub fn idle_init(&mut self, tag: Tag<'static>) -> ResponseOrIdle {
+ // Build transition
+ //@FIXME the notifier should be hidden inside the state and thus not part of the transition!
+ let transition = flow::Transition::Idle(tag.clone(), tokio::sync::Notify::new());
+
+ // Try to apply the transition and get the stop notifier
+ let maybe_stop = self
+ .state
+ .apply(transition)
+ .context("IDLE transition failed")
+ .and_then(|_| {
+ self.state
+ .notify()
+ .ok_or(anyhow!("IDLE state has no Notify object"))
+ });
+
+ // Build an appropriate response
+ match maybe_stop {
+ Ok(stop) => ResponseOrIdle::IdleAccept(stop),
+ Err(e) => {
+ tracing::error!(err=?e, "unable to init idle due to a transition error");
+ //ResponseOrIdle::IdleReject(tag)
+ let no = Response::build()
+ .tag(tag)
+ .message(
+ "Internal error, processing command triggered an illegal IMAP state transition",
+ )
+ .no()
+ .unwrap();
+ ResponseOrIdle::IdleReject(no)
+ }
+ }
+ }
+
+ pub async fn idle_poll(&mut self) -> ResponseOrIdle {
+ match self.idle_poll_happy().await {
Ok(r) => r,
Err(e) => {
tracing::error!(err=?e, "something bad happened in idle");
@@ -42,7 +77,7 @@ impl Instance {
}
}
- pub async fn idle_happy(&mut self) -> Result<ResponseOrIdle> {
+ pub async fn idle_poll_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"),
@@ -128,10 +163,11 @@ impl Instance {
.bad()
.unwrap());
}
+ ResponseOrIdle::Response(resp)
- match &self.state {
+ /*match &self.state {
flow::State::Idle(_, _, _, _, n) => ResponseOrIdle::StartIdle(n.clone()),
_ => ResponseOrIdle::Response(resp),
- }
+ }*/
}
}