cargo fmt + implement noop
This commit is contained in:
parent
927b461f25
commit
36bbc2138b
6 changed files with 70 additions and 56 deletions
|
@ -11,11 +11,12 @@ use crate::imap::session::InnerContext;
|
||||||
|
|
||||||
pub async fn dispatch<'a>(ctx: InnerContext<'a>) -> Result<(Response, flow::Transition)> {
|
pub async fn dispatch<'a>(ctx: InnerContext<'a>) -> Result<(Response, flow::Transition)> {
|
||||||
match &ctx.req.command.body {
|
match &ctx.req.command.body {
|
||||||
|
CommandBody::Noop => Ok((Response::ok("Noop completed.")?, flow::Transition::No)),
|
||||||
CommandBody::Capability => capability(ctx).await,
|
CommandBody::Capability => capability(ctx).await,
|
||||||
CommandBody::Login { username, password } => login(ctx, username, password).await,
|
CommandBody::Login { username, password } => login(ctx, username, password).await,
|
||||||
_ => Ok((
|
_ => Ok((
|
||||||
Response::no("This command is not available in the ANONYMOUS state.")?,
|
Response::no("This command is not available in the ANONYMOUS state.")?,
|
||||||
flow::Transition::No
|
flow::Transition::No,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +56,6 @@ async fn login<'a>(
|
||||||
tracing::info!(username=%u, "connected");
|
tracing::info!(username=%u, "connected");
|
||||||
Ok((
|
Ok((
|
||||||
Response::ok("Completed")?,
|
Response::ok("Completed")?,
|
||||||
flow::Transition::Authenticate(user)
|
flow::Transition::Authenticate(user),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
use boitalettres::proto::{Response, res::body::Data as Body};
|
use boitalettres::proto::{res::body::Data as Body, Response};
|
||||||
use imap_codec::types::command::CommandBody;
|
use imap_codec::types::command::CommandBody;
|
||||||
use imap_codec::types::core::Atom;
|
use imap_codec::types::core::Atom;
|
||||||
use imap_codec::types::flag::Flag;
|
use imap_codec::types::flag::Flag;
|
||||||
|
@ -12,11 +12,11 @@ use crate::imap::session::InnerContext;
|
||||||
use crate::mail::Mailbox;
|
use crate::mail::Mailbox;
|
||||||
|
|
||||||
const DEFAULT_FLAGS: [Flag; 5] = [
|
const DEFAULT_FLAGS: [Flag; 5] = [
|
||||||
Flag::Seen,
|
Flag::Seen,
|
||||||
Flag::Answered,
|
Flag::Answered,
|
||||||
Flag::Flagged,
|
Flag::Flagged,
|
||||||
Flag::Deleted,
|
Flag::Deleted,
|
||||||
Flag::Draft,
|
Flag::Draft,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub async fn dispatch<'a>(
|
pub async fn dispatch<'a>(
|
||||||
|
@ -52,10 +52,7 @@ impl<'a> StateContext<'a> {
|
||||||
reference: &MailboxCodec,
|
reference: &MailboxCodec,
|
||||||
mailbox_wildcard: &ListMailbox,
|
mailbox_wildcard: &ListMailbox,
|
||||||
) -> Result<(Response, flow::Transition)> {
|
) -> Result<(Response, flow::Transition)> {
|
||||||
Ok((
|
Ok((Response::bad("Not implemented")?, flow::Transition::No))
|
||||||
Response::bad("Not implemented")?,
|
|
||||||
flow::Transition::No,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list(
|
async fn list(
|
||||||
|
@ -63,10 +60,7 @@ impl<'a> StateContext<'a> {
|
||||||
reference: &MailboxCodec,
|
reference: &MailboxCodec,
|
||||||
mailbox_wildcard: &ListMailbox,
|
mailbox_wildcard: &ListMailbox,
|
||||||
) -> Result<(Response, flow::Transition)> {
|
) -> Result<(Response, flow::Transition)> {
|
||||||
Ok((
|
Ok((Response::bad("Not implemented")?, flow::Transition::No))
|
||||||
Response::bad("Not implemented")?,
|
|
||||||
flow::Transition::No,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -128,37 +122,25 @@ impl<'a> StateContext<'a> {
|
||||||
|
|
||||||
res.push(Body::Data(Data::Flags(flags.clone())));
|
res.push(Body::Data(Data::Flags(flags.clone())));
|
||||||
|
|
||||||
let uid_validity = Status::ok(
|
let uid_validity = Status::ok(None, Some(Code::UidValidity(sum.validity)), "UIDs valid")
|
||||||
None,
|
|
||||||
Some(Code::UidValidity(sum.validity)),
|
|
||||||
"UIDs valid"
|
|
||||||
)
|
|
||||||
.map_err(Error::msg)?;
|
.map_err(Error::msg)?;
|
||||||
res.push(Body::Status(uid_validity));
|
res.push(Body::Status(uid_validity));
|
||||||
|
|
||||||
let next_uid = Status::ok(
|
let next_uid = Status::ok(None, Some(Code::UidNext(sum.next)), "Predict next UID")
|
||||||
None,
|
.map_err(Error::msg)?;
|
||||||
Some(Code::UidNext(sum.next)),
|
|
||||||
"Predict next UID"
|
|
||||||
).map_err(Error::msg)?;
|
|
||||||
res.push(Body::Status(next_uid));
|
res.push(Body::Status(next_uid));
|
||||||
|
|
||||||
if let Some(unseen) = sum.unseen {
|
if let Some(unseen) = sum.unseen {
|
||||||
let status_unseen = Status::ok(
|
let status_unseen =
|
||||||
None,
|
Status::ok(None, Some(Code::Unseen(unseen.clone())), "First unseen UID")
|
||||||
Some(Code::Unseen(unseen.clone())),
|
.map_err(Error::msg)?;
|
||||||
"First unseen UID",
|
|
||||||
)
|
|
||||||
.map_err(Error::msg)?;
|
|
||||||
res.push(Body::Status(status_unseen));
|
res.push(Body::Status(status_unseen));
|
||||||
}
|
}
|
||||||
|
|
||||||
flags.push(Flag::Permanent);
|
flags.push(Flag::Permanent);
|
||||||
let permanent_flags = Status::ok(
|
let permanent_flags =
|
||||||
None,
|
Status::ok(None, Some(Code::PermanentFlags(flags)), "Flags permitted")
|
||||||
Some(Code::PermanentFlags(flags)),
|
.map_err(Error::msg)?;
|
||||||
"Flags permitted",
|
|
||||||
).map_err(Error::msg)?;
|
|
||||||
res.push(Body::Status(permanent_flags));
|
res.push(Body::Status(permanent_flags));
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
|
|
|
@ -47,9 +47,6 @@ impl<'a> StateContext<'a> {
|
||||||
attributes: &MacroOrFetchAttributes,
|
attributes: &MacroOrFetchAttributes,
|
||||||
uid: &bool,
|
uid: &bool,
|
||||||
) -> Result<(Response, flow::Transition)> {
|
) -> Result<(Response, flow::Transition)> {
|
||||||
Ok((
|
Ok((Response::bad("Not implemented")?, flow::Transition::No))
|
||||||
Response::bad("Not implemented")?,
|
|
||||||
flow::Transition::No,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,16 +49,10 @@ impl Manager {
|
||||||
match self.tx.try_send(msg) {
|
match self.tx.try_send(msg) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(TrySendError::Full(_)) => {
|
Err(TrySendError::Full(_)) => {
|
||||||
return async {
|
return async { Response::bad("Too fast! Send less pipelined requests.") }.boxed()
|
||||||
Response::bad("Too fast! Send less pipelined requests.")
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
Err(TrySendError::Closed(_)) => {
|
Err(TrySendError::Closed(_)) => {
|
||||||
return async {
|
return async { Response::bad("Session task has existed.") }.boxed()
|
||||||
Response::bad("Session task has existed.")
|
|
||||||
}
|
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,8 +124,11 @@ impl Instance {
|
||||||
// Process result
|
// Process result
|
||||||
let res = match ctrl {
|
let res = match ctrl {
|
||||||
Ok((res, tr)) => {
|
Ok((res, tr)) => {
|
||||||
//@FIXME unwrap
|
//@FIXME remove unwrap
|
||||||
self.state = self.state.apply(tr).unwrap();
|
self.state = self.state.apply(tr).unwrap();
|
||||||
|
|
||||||
|
//@FIXME enrich here the command with some status
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
// Cast from anyhow::Error to Bal::Error
|
// Cast from anyhow::Error to Bal::Error
|
||||||
|
|
|
@ -13,6 +13,10 @@ use crate::login::Credentials;
|
||||||
use crate::mail::mail_ident::*;
|
use crate::mail::mail_ident::*;
|
||||||
use crate::mail::uidindex::*;
|
use crate::mail::uidindex::*;
|
||||||
|
|
||||||
|
// Internet Message Format
|
||||||
|
// aka RFC 822 - RFC 2822 - RFC 5322
|
||||||
|
pub struct IMF(Vec<u8>);
|
||||||
|
|
||||||
pub struct Summary<'a> {
|
pub struct Summary<'a> {
|
||||||
pub validity: ImapUidvalidity,
|
pub validity: ImapUidvalidity,
|
||||||
pub next: ImapUid,
|
pub next: ImapUid,
|
||||||
|
@ -31,7 +35,6 @@ impl std::fmt::Display for Summary<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Non standard but common flags:
|
// Non standard but common flags:
|
||||||
// https://www.iana.org/assignments/imap-jmap-keywords/imap-jmap-keywords.xhtml
|
// https://www.iana.org/assignments/imap-jmap-keywords/imap-jmap-keywords.xhtml
|
||||||
pub struct Mailbox {
|
pub struct Mailbox {
|
||||||
|
@ -45,8 +48,6 @@ pub struct Mailbox {
|
||||||
uid_index: Bayou<UidIndex>,
|
uid_index: Bayou<UidIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDEA: We store a specific flag named $unseen.
|
|
||||||
// If it is not present, we add the virtual flag \Seen
|
|
||||||
impl Mailbox {
|
impl Mailbox {
|
||||||
pub fn new(creds: &Credentials, name: String) -> Result<Self> {
|
pub fn new(creds: &Credentials, name: String) -> Result<Self> {
|
||||||
let uid_index = Bayou::<UidIndex>::new(creds, name.clone())?;
|
let uid_index = Bayou::<UidIndex>::new(creds, name.clone())?;
|
||||||
|
@ -61,12 +62,20 @@ impl Mailbox {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a summary of the mailbox, useful for the SELECT command for example
|
||||||
pub async fn summary(&mut self) -> Result<Summary> {
|
pub async fn summary(&mut self) -> Result<Summary> {
|
||||||
self.uid_index.sync().await?;
|
self.uid_index.sync().await?;
|
||||||
let state = self.uid_index.state();
|
let state = self.uid_index.state();
|
||||||
|
|
||||||
let unseen = state.idx_by_flag.get(&"$unseen".to_string()).and_then(|os| os.get_min());
|
let unseen = state
|
||||||
let recent = state.idx_by_flag.get(&"\\Recent".to_string()).map(|os| os.len()).unwrap_or(0);
|
.idx_by_flag
|
||||||
|
.get(&"$unseen".to_string())
|
||||||
|
.and_then(|os| os.get_min());
|
||||||
|
let recent = state
|
||||||
|
.idx_by_flag
|
||||||
|
.get(&"\\Recent".to_string())
|
||||||
|
.map(|os| os.len())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
return Ok(Summary {
|
return Ok(Summary {
|
||||||
validity: state.uidvalidity,
|
validity: state.uidvalidity,
|
||||||
|
@ -78,6 +87,34 @@ impl Mailbox {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert an email in the mailbox
|
||||||
|
pub async fn append(&mut self, msg: IMF) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy an email from an external to this mailbox
|
||||||
|
// @FIXME is it needed or could we implement it with append?
|
||||||
|
pub async fn copy(&mut self, mailbox: String, uid: ImapUid) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all emails with the \Delete flag in the mailbox
|
||||||
|
// Can be called by CLOSE and EXPUNGE
|
||||||
|
// @FIXME do we want to implement this feature or a simpler "delete" command
|
||||||
|
// The controller could then "fetch \Delete" and call delete on each email?
|
||||||
|
pub async fn expunge(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update flags of a range of emails
|
||||||
|
pub async fn store(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn fetch(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn test(&mut self) -> Result<()> {
|
pub async fn test(&mut self) -> Result<()> {
|
||||||
self.uid_index.sync().await?;
|
self.uid_index.sync().await?;
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ impl FlagIndex {
|
||||||
|
|
||||||
pub fn get(&self, f: &Flag) -> Option<&OrdSet<ImapUid>> {
|
pub fn get(&self, f: &Flag) -> Option<&OrdSet<ImapUid>> {
|
||||||
self.0.get(f)
|
self.0.get(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flags(&self) -> FlagIter {
|
pub fn flags(&self) -> FlagIter {
|
||||||
self.0.keys()
|
self.0.keys()
|
||||||
|
|
Loading…
Reference in a new issue