diff options
author | Alex Auvolat <alex@adnab.me> | 2022-06-29 12:50:44 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2022-06-29 12:50:44 +0200 |
commit | 90b143e1c57c6561998176878b2cc586b2d89c80 (patch) | |
tree | a9f07995d9d29e9f884756cad5732bfb2cbeb3fc /src/imap/command/anonymous.rs | |
parent | 9979671b001ccb25917da7091d13ad3fc1096330 (diff) | |
download | aerogramme-90b143e1c57c6561998176878b2cc586b2d89c80.tar.gz aerogramme-90b143e1c57c6561998176878b2cc586b2d89c80.zip |
Refactor to allow mutability
Diffstat (limited to 'src/imap/command/anonymous.rs')
-rw-r--r-- | src/imap/command/anonymous.rs | 127 |
1 files changed, 74 insertions, 53 deletions
diff --git a/src/imap/command/anonymous.rs b/src/imap/command/anonymous.rs index 2ab3f97..f5707ef 100644 --- a/src/imap/command/anonymous.rs +++ b/src/imap/command/anonymous.rs @@ -1,76 +1,97 @@ use anyhow::{Error, Result}; -use boitalettres::proto::{res::body::Data as Body, Response}; +use boitalettres::proto::{res::body::Data as Body, Request, Response}; use imap_codec::types::command::CommandBody; use imap_codec::types::core::{AString, Atom}; use imap_codec::types::response::{Capability, Code, Data, Response as ImapRes, Status}; use crate::imap::flow; -use crate::imap::session::InnerContext; +use crate::login::ArcLoginProvider; //--- dispatching -pub async fn dispatch<'a>(ctx: InnerContext<'a>) -> Result<(Response, flow::Transition)> { +pub struct AnonymousContext<'a> { + pub req: &'a Request, + pub login_provider: Option<&'a ArcLoginProvider>, +} + +pub async fn dispatch<'a>(ctx: AnonymousContext<'a>) -> Result<(Response, flow::Transition)> { match &ctx.req.command.body { - CommandBody::Noop => Ok((Response::ok("Noop completed.")?, flow::Transition::No)), - CommandBody::Capability => capability(ctx).await, - CommandBody::Logout => logout(ctx).await, - CommandBody::Login { username, password } => login(ctx, username, password).await, + CommandBody::Noop => Ok((Response::ok("Noop completed.")?, flow::Transition::None)), + CommandBody::Capability => ctx.capability().await, + CommandBody::Logout => ctx.logout().await, + CommandBody::Login { username, password } => ctx.login(username, password).await, _ => Ok(( Response::no("This command is not available in the ANONYMOUS state.")?, - flow::Transition::No, + flow::Transition::None, )), } } //--- Command controllers, private -async fn capability<'a>(ctx: InnerContext<'a>) -> Result<(Response, flow::Transition)> { - let capabilities = vec![Capability::Imap4Rev1, Capability::Idle]; - let res = Response::ok("Server capabilities")?.with_body(Data::Capability(capabilities)); - Ok((res, flow::Transition::No)) -} +impl<'a> AnonymousContext<'a> { + async fn capability(self) -> Result<(Response, flow::Transition)> { + let capabilities = vec![Capability::Imap4Rev1, Capability::Idle]; + let res = Response::ok("Server capabilities")?.with_body(Data::Capability(capabilities)); + Ok((res, flow::Transition::None)) + } -async fn login<'a>( - ctx: InnerContext<'a>, - username: &AString, - password: &AString, -) -> Result<(Response, flow::Transition)> { - let (u, p) = ( - String::try_from(username.clone())?, - String::try_from(password.clone())?, - ); - tracing::info!(user = %u, "command.login"); + async fn login( + self, + username: &AString, + password: &AString, + ) -> Result<(Response, flow::Transition)> { + let (u, p) = ( + String::try_from(username.clone())?, + String::try_from(password.clone())?, + ); + tracing::info!(user = %u, "command.login"); - let creds = match ctx.login.login(&u, &p).await { - Err(e) => { - tracing::debug!(error=%e, "authentication failed"); - return Ok((Response::no("Authentication failed")?, flow::Transition::No)); - } - Ok(c) => c, - }; + let login_provider = match &self.login_provider { + Some(lp) => lp, + None => { + return Ok(( + Response::no("Login command not available (already logged in)")?, + flow::Transition::None, + )) + } + }; - let user = flow::User { - creds, - name: u.clone(), - }; + let creds = match login_provider.login(&u, &p).await { + Err(e) => { + tracing::debug!(error=%e, "authentication failed"); + return Ok(( + Response::no("Authentication failed")?, + flow::Transition::None, + )); + } + Ok(c) => c, + }; - tracing::info!(username=%u, "connected"); - Ok(( - Response::ok("Completed")?, - flow::Transition::Authenticate(user), - )) -} -// C: 10 logout -// S: * BYE Logging out -// S: 10 OK Logout completed. -async fn logout<'a>(ctx: InnerContext<'a>) -> Result<(Response, flow::Transition)> { - // @FIXME we should implement From<Vec<Status>> and From<Vec<ImapStatus>> in - // boitalettres/src/proto/res/body.rs - Ok(( - Response::ok("Logout completed")?.with_body(vec![Body::Status( - Status::bye(None, "Logging out") - .map_err(|e| Error::msg(e).context("Unable to generate IMAP status"))?, - )]), - flow::Transition::Logout, - )) + let user = flow::User { + creds, + name: u.clone(), + }; + + tracing::info!(username=%u, "connected"); + Ok(( + Response::ok("Completed")?, + flow::Transition::Authenticate(user), + )) + } + + // C: 10 logout + // S: * BYE Logging out + // S: 10 OK Logout completed. + async fn logout(self) -> Result<(Response, flow::Transition)> { + // @FIXME we should implement From<Vec<Status>> and From<Vec<ImapStatus>> in + // boitalettres/src/proto/res/body.rs + Ok(( + Response::ok("Logout completed")?.with_body(vec![Body::Status( + Status::bye(None, "Logging out") + .map_err(|e| Error::msg(e).context("Unable to generate IMAP status"))?, + )]), + flow::Transition::Logout, + )) + } } |