diff options
Diffstat (limited to 'src/imap/command/anonymous.rs')
-rw-r--r-- | src/imap/command/anonymous.rs | 91 |
1 files changed, 38 insertions, 53 deletions
diff --git a/src/imap/command/anonymous.rs b/src/imap/command/anonymous.rs index d258bd3..fbd10e9 100644 --- a/src/imap/command/anonymous.rs +++ b/src/imap/command/anonymous.rs @@ -1,92 +1,77 @@ -use anyhow::{Error, Result}; -use boitalettres::proto::{res::body::Data as Body, Request, Response}; -use imap_codec::types::command::CommandBody; -use imap_codec::types::core::AString; -use imap_codec::types::response::{Capability, Data, Status}; +use anyhow::Result; +use imap_codec::imap_types::command::{Command, CommandBody}; +use imap_codec::imap_types::core::AString; +use imap_codec::imap_types::secret::Secret; +use crate::imap::command::anystate; use crate::imap::flow; +use crate::imap::response::Response; use crate::login::ArcLoginProvider; use crate::mail::user::User; //--- dispatching pub struct AnonymousContext<'a> { - pub req: &'a Request, - pub login_provider: Option<&'a ArcLoginProvider>, + pub req: &'a Command<'static>, + pub login_provider: &'a ArcLoginProvider, } -pub async fn dispatch(ctx: AnonymousContext<'_>) -> Result<(Response, flow::Transition)> { - match &ctx.req.command.body { - CommandBody::Noop => Ok((Response::ok("Noop completed.")?, flow::Transition::None)), - CommandBody::Capability => ctx.capability().await, - CommandBody::Logout => ctx.logout().await, +pub async fn dispatch(ctx: AnonymousContext<'_>) -> Result<(Response<'static>, flow::Transition)> { + match &ctx.req.body { + // Any State + CommandBody::Noop => anystate::noop_nothing(ctx.req.tag.clone()), + CommandBody::Capability => anystate::capability(ctx.req.tag.clone()), + CommandBody::Logout => anystate::logout(), + + // Specific to anonymous context (3 commands) CommandBody::Login { username, password } => ctx.login(username, password).await, - _ => Ok((Response::no("Command unavailable")?, flow::Transition::None)), + CommandBody::Authenticate { .. } => { + anystate::not_implemented(ctx.req.tag.clone(), "authenticate") + } + //StartTLS is not implemented for now, we will probably go full TLS. + + // Collect other commands + _ => anystate::wrong_state(ctx.req.tag.clone()), } } //--- Command controllers, private 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( self, - username: &AString, - password: &AString, - ) -> Result<(Response, flow::Transition)> { + username: &AString<'a>, + password: &Secret<AString<'a>>, + ) -> Result<(Response<'static>, flow::Transition)> { let (u, p) = ( - String::try_from(username.clone())?, - String::try_from(password.clone())?, + std::str::from_utf8(username.as_ref())?, + std::str::from_utf8(password.declassify().as_ref())?, ); tracing::info!(user = %u, "command.login"); - 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 creds = match login_provider.login(&u, &p).await { + let creds = match self.login_provider.login(&u, &p).await { Err(e) => { tracing::debug!(error=%e, "authentication failed"); return Ok(( - Response::no("Authentication failed")?, + Response::build() + .to_req(self.req) + .message("Authentication failed") + .no()?, flow::Transition::None, )); } Ok(c) => c, }; - let user = User::new(u.clone(), creds).await?; + let user = User::new(u.to_string(), creds).await?; tracing::info!(username=%u, "connected"); Ok(( - Response::ok("Completed")?, + Response::build() + .to_req(self.req) + .message("Completed") + .ok()?, 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, - )) - } } |