diff options
Diffstat (limited to 'src/imap/command/anonymous.rs')
-rw-r--r-- | src/imap/command/anonymous.rs | 85 |
1 files changed, 47 insertions, 38 deletions
diff --git a/src/imap/command/anonymous.rs b/src/imap/command/anonymous.rs index 9f4563f..9bbb3b7 100644 --- a/src/imap/command/anonymous.rs +++ b/src/imap/command/anonymous.rs @@ -1,9 +1,11 @@ -use anyhow::{Error, Result}; +use anyhow::Result; use imap_codec::imap_types::command::{Command, CommandBody}; -use imap_codec::imap_types::core::AString; -use imap_codec::imap_types::response::{Capability, Data, Status, CommandContinuationRequest}; +use imap_codec::imap_types::core::{AString, NonEmptyVec}; +use imap_codec::imap_types::response::{Capability, Data}; +use imap_codec::imap_types::secret::Secret; use crate::imap::flow; +use crate::imap::response::Response; use crate::login::ArcLoginProvider; use crate::mail::user::User; @@ -11,18 +13,30 @@ use crate::mail::user::User; pub struct AnonymousContext<'a> { pub req: &'a Command<'static>, - pub login_provider: Option<&'a ArcLoginProvider>, + pub login_provider: &'a ArcLoginProvider, } -pub async fn dispatch(ctx: AnonymousContext<'_>) -> Result<(Status, flow::Transition)> { +pub async fn dispatch(ctx: AnonymousContext<'_>) -> Result<(Response, flow::Transition)> { match &ctx.req.body { - CommandBody::Noop => Ok((Response::ok("Noop completed.")?, flow::Transition::None)), + CommandBody::Noop => Ok(( + Response::ok() + .to_req(ctx.req) + .message("Noop completed.") + .build()?, + flow::Transition::None, + )), CommandBody::Capability => ctx.capability().await, CommandBody::Logout => ctx.logout().await, CommandBody::Login { username, password } => ctx.login(username, password).await, cmd => { - tracing::warn!("Unknown command {:?}", cmd); - Ok((Response::no("Command unavailable")?, flow::Transition::None)) + tracing::warn!("Unknown command for the anonymous state {:?}", cmd); + Ok(( + Response::bad() + .to_req(ctx.req) + .message("Command unavailable") + .build()?, + flow::Transition::None, + )) } } } @@ -30,49 +44,50 @@ pub async fn dispatch(ctx: AnonymousContext<'_>) -> Result<(Status, flow::Transi //--- Command controllers, private impl<'a> AnonymousContext<'a> { - async fn capability(self) -> Result<(Status, flow::Transition)> { - let capabilities = vec![Capability::Imap4Rev1, Capability::Idle]; - let res = Response::ok("Server capabilities")?.with_body(Data::Capability(capabilities)); + async fn capability(self) -> Result<(Response, flow::Transition)> { + let capabilities: NonEmptyVec<Capability> = + (vec![Capability::Imap4Rev1, Capability::Idle]).try_into()?; + let res = Response::ok() + .to_req(self.req) + .message("Server capabilities") + .data(Data::Capability(capabilities)) + .build()?; Ok((res, flow::Transition::None)) } async fn login( self, - username: &AString, - password: &AString, - ) -> Result<(Status, flow::Transition)> { + username: &AString<'a>, + password: &Secret<AString<'a>>, + ) -> Result<(Response, 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::no() + .to_req(self.req) + .message("Authentication failed") + .build()?, 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::ok() + .to_req(self.req) + .message("Completed") + .build()?, flow::Transition::Authenticate(user), )) } @@ -80,15 +95,9 @@ impl<'a> AnonymousContext<'a> { // C: 10 logout // S: * BYE Logging out // S: 10 OK Logout completed. - async fn logout(self) -> Result<(Status, flow::Transition)> { + 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, - )) + Ok((Response::bye()?, flow::Transition::Logout)) } } |