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.rs173
1 files changed, 0 insertions, 173 deletions
diff --git a/src/imap/session.rs b/src/imap/session.rs
deleted file mode 100644
index fa3232a..0000000
--- a/src/imap/session.rs
+++ /dev/null
@@ -1,173 +0,0 @@
-use crate::imap::capability::{ClientCapability, ServerCapability};
-use crate::imap::command::{anonymous, authenticated, selected};
-use crate::imap::flow;
-use crate::imap::request::Request;
-use crate::imap::response::{Response, ResponseOrIdle};
-use crate::login::ArcLoginProvider;
-use anyhow::{anyhow, bail, Context, Result};
-use imap_codec::imap_types::{command::Command, core::Tag};
-
-//-----
-pub struct Instance {
- pub login_provider: ArcLoginProvider,
- pub server_capabilities: ServerCapability,
- pub client_capabilities: ClientCapability,
- pub state: flow::State,
-}
-impl Instance {
- pub fn new(login_provider: ArcLoginProvider, cap: ServerCapability) -> Self {
- let client_cap = ClientCapability::new(&cap);
- Self {
- login_provider,
- state: flow::State::NotAuthenticated,
- server_capabilities: cap,
- client_capabilities: client_cap,
- }
- }
-
- pub async fn request(&mut self, req: Request) -> ResponseOrIdle {
- match req {
- Request::IdleStart(tag) => self.idle_init(tag),
- Request::IdlePoll => self.idle_poll().await,
- Request::ImapCommand(cmd) => self.command(cmd).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");
- ResponseOrIdle::Response(Response::bye().unwrap())
- }
- }
- }
-
- 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"),
- };
-
- tokio::select! {
- _ = stop.notified() => {
- self.state.apply(flow::Transition::UnIdle)?;
- return Ok(ResponseOrIdle::Response(Response::build()
- .tag(tag.clone())
- .message("IDLE completed")
- .ok()?))
- },
- change = mbx.idle_sync() => {
- tracing::debug!("idle event");
- return Ok(ResponseOrIdle::IdleEvent(change?));
- }
- }
- }
-
- pub async fn command(&mut self, cmd: Command<'static>) -> ResponseOrIdle {
- // Command behavior is modulated by the state.
- // To prevent state error, we handle the same command in separate code paths.
- let (resp, tr) = match &mut self.state {
- flow::State::NotAuthenticated => {
- let ctx = anonymous::AnonymousContext {
- req: &cmd,
- login_provider: &self.login_provider,
- server_capabilities: &self.server_capabilities,
- };
- anonymous::dispatch(ctx).await
- }
- flow::State::Authenticated(ref user) => {
- let ctx = authenticated::AuthenticatedContext {
- req: &cmd,
- server_capabilities: &self.server_capabilities,
- client_capabilities: &mut self.client_capabilities,
- user,
- };
- authenticated::dispatch(ctx).await
- }
- flow::State::Selected(ref user, ref mut mailbox, ref perm) => {
- let ctx = selected::SelectedContext {
- req: &cmd,
- server_capabilities: &self.server_capabilities,
- client_capabilities: &mut self.client_capabilities,
- user,
- mailbox,
- perm,
- };
- selected::dispatch(ctx).await
- }
- flow::State::Idle(..) => Err(anyhow!("can not receive command while idling")),
- flow::State::Logout => Response::build()
- .tag(cmd.tag.clone())
- .message("No commands are allowed in the LOGOUT state.")
- .bad()
- .map(|r| (r, flow::Transition::None)),
- }
- .unwrap_or_else(|err| {
- tracing::error!("Command error {:?} occured while processing {:?}", err, cmd);
- (
- Response::build()
- .to_req(&cmd)
- .message("Internal error while processing command")
- .bad()
- .unwrap(),
- flow::Transition::None,
- )
- });
-
- if let Err(e) = self.state.apply(tr) {
- tracing::error!(
- "Transition error {:?} occured while processing on command {:?}",
- e,
- cmd
- );
- return ResponseOrIdle::Response(Response::build()
- .to_req(&cmd)
- .message(
- "Internal error, processing command triggered an illegal IMAP state transition",
- )
- .bad()
- .unwrap());
- }
- ResponseOrIdle::Response(resp)
-
- /*match &self.state {
- flow::State::Idle(_, _, _, _, n) => ResponseOrIdle::StartIdle(n.clone()),
- _ => ResponseOrIdle::Response(resp),
- }*/
- }
-}