aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/imap/command/anonymous.rs5
-rw-r--r--src/imap/command/authenticated.rs52
-rw-r--r--src/imap/command/selected.rs5
-rw-r--r--src/imap/session.rs15
-rw-r--r--src/mail/mod.rs47
-rw-r--r--src/mail/uidindex.rs2
6 files changed, 70 insertions, 56 deletions
diff --git a/src/imap/command/anonymous.rs b/src/imap/command/anonymous.rs
index a2f2260..8de27cb 100644
--- a/src/imap/command/anonymous.rs
+++ b/src/imap/command/anonymous.rs
@@ -11,11 +11,12 @@ use crate::imap::session::InnerContext;
pub async fn dispatch<'a>(ctx: InnerContext<'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::Login { username, password } => login(ctx, username, password).await,
_ => Ok((
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");
Ok((
Response::ok("Completed")?,
- flow::Transition::Authenticate(user)
+ flow::Transition::Authenticate(user),
))
}
diff --git a/src/imap/command/authenticated.rs b/src/imap/command/authenticated.rs
index 85c1c82..4ba4968 100644
--- a/src/imap/command/authenticated.rs
+++ b/src/imap/command/authenticated.rs
@@ -1,5 +1,5 @@
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::core::Atom;
use imap_codec::types::flag::Flag;
@@ -12,11 +12,11 @@ use crate::imap::session::InnerContext;
use crate::mail::Mailbox;
const DEFAULT_FLAGS: [Flag; 5] = [
- Flag::Seen,
- Flag::Answered,
- Flag::Flagged,
- Flag::Deleted,
- Flag::Draft,
+ Flag::Seen,
+ Flag::Answered,
+ Flag::Flagged,
+ Flag::Deleted,
+ Flag::Draft,
];
pub async fn dispatch<'a>(
@@ -52,10 +52,7 @@ impl<'a> StateContext<'a> {
reference: &MailboxCodec,
mailbox_wildcard: &ListMailbox,
) -> Result<(Response, flow::Transition)> {
- Ok((
- Response::bad("Not implemented")?,
- flow::Transition::No,
- ))
+ Ok((Response::bad("Not implemented")?, flow::Transition::No))
}
async fn list(
@@ -63,10 +60,7 @@ impl<'a> StateContext<'a> {
reference: &MailboxCodec,
mailbox_wildcard: &ListMailbox,
) -> Result<(Response, flow::Transition)> {
- Ok((
- Response::bad("Not implemented")?,
- flow::Transition::No,
- ))
+ Ok((Response::bad("Not implemented")?, flow::Transition::No))
}
/*
@@ -128,37 +122,25 @@ impl<'a> StateContext<'a> {
res.push(Body::Data(Data::Flags(flags.clone())));
- let uid_validity = Status::ok(
- None,
- Some(Code::UidValidity(sum.validity)),
- "UIDs valid"
- )
+ let uid_validity = Status::ok(None, Some(Code::UidValidity(sum.validity)), "UIDs valid")
.map_err(Error::msg)?;
res.push(Body::Status(uid_validity));
- let next_uid = Status::ok(
- None,
- Some(Code::UidNext(sum.next)),
- "Predict next UID"
- ).map_err(Error::msg)?;
+ let next_uid = Status::ok(None, Some(Code::UidNext(sum.next)), "Predict next UID")
+ .map_err(Error::msg)?;
res.push(Body::Status(next_uid));
if let Some(unseen) = sum.unseen {
- let status_unseen = Status::ok(
- None,
- Some(Code::Unseen(unseen.clone())),
- "First unseen UID",
- )
- .map_err(Error::msg)?;
+ let status_unseen =
+ Status::ok(None, Some(Code::Unseen(unseen.clone())), "First unseen UID")
+ .map_err(Error::msg)?;
res.push(Body::Status(status_unseen));
}
flags.push(Flag::Permanent);
- let permanent_flags = Status::ok(
- None,
- Some(Code::PermanentFlags(flags)),
- "Flags permitted",
- ).map_err(Error::msg)?;
+ let permanent_flags =
+ Status::ok(None, Some(Code::PermanentFlags(flags)), "Flags permitted")
+ .map_err(Error::msg)?;
res.push(Body::Status(permanent_flags));
Ok((
diff --git a/src/imap/command/selected.rs b/src/imap/command/selected.rs
index e013eaa..cf0b71b 100644
--- a/src/imap/command/selected.rs
+++ b/src/imap/command/selected.rs
@@ -47,9 +47,6 @@ impl<'a> StateContext<'a> {
attributes: &MacroOrFetchAttributes,
uid: &bool,
) -> Result<(Response, flow::Transition)> {
- Ok((
- Response::bad("Not implemented")?,
- flow::Transition::No,
- ))
+ Ok((Response::bad("Not implemented")?, flow::Transition::No))
}
}
diff --git a/src/imap/session.rs b/src/imap/session.rs
index dfef0f4..d45a989 100644
--- a/src/imap/session.rs
+++ b/src/imap/session.rs
@@ -49,16 +49,10 @@ impl Manager {
match self.tx.try_send(msg) {
Ok(()) => (),
Err(TrySendError::Full(_)) => {
- return async {
- Response::bad("Too fast! Send less pipelined requests.")
- }
- .boxed()
+ return async { Response::bad("Too fast! Send less pipelined requests.") }.boxed()
}
Err(TrySendError::Closed(_)) => {
- return async {
- Response::bad("Session task has existed.")
- }
- .boxed()
+ return async { Response::bad("Session task has existed.") }.boxed()
}
};
@@ -130,8 +124,11 @@ impl Instance {
// Process result
let res = match ctrl {
Ok((res, tr)) => {
- //@FIXME unwrap
+ //@FIXME remove unwrap
self.state = self.state.apply(tr).unwrap();
+
+ //@FIXME enrich here the command with some status
+
Ok(res)
}
// Cast from anyhow::Error to Bal::Error
diff --git a/src/mail/mod.rs b/src/mail/mod.rs
index 2edcaa7..7c62c59 100644
--- a/src/mail/mod.rs
+++ b/src/mail/mod.rs
@@ -13,6 +13,10 @@ use crate::login::Credentials;
use crate::mail::mail_ident::*;
use crate::mail::uidindex::*;
+// Internet Message Format
+// aka RFC 822 - RFC 2822 - RFC 5322
+pub struct IMF(Vec<u8>);
+
pub struct Summary<'a> {
pub validity: ImapUidvalidity,
pub next: ImapUid,
@@ -31,7 +35,6 @@ impl std::fmt::Display for Summary<'_> {
}
}
-
// Non standard but common flags:
// https://www.iana.org/assignments/imap-jmap-keywords/imap-jmap-keywords.xhtml
pub struct Mailbox {
@@ -45,8 +48,6 @@ pub struct Mailbox {
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 {
pub fn new(creds: &Credentials, name: String) -> Result<Self> {
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> {
self.uid_index.sync().await?;
let state = self.uid_index.state();
- let unseen = state.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);
+ let unseen = state
+ .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 {
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<()> {
self.uid_index.sync().await?;
diff --git a/src/mail/uidindex.rs b/src/mail/uidindex.rs
index 49dbba5..ad27c1b 100644
--- a/src/mail/uidindex.rs
+++ b/src/mail/uidindex.rs
@@ -186,7 +186,7 @@ impl FlagIndex {
pub fn get(&self, f: &Flag) -> Option<&OrdSet<ImapUid>> {
self.0.get(f)
- }
+ }
pub fn flags(&self) -> FlagIter {
self.0.keys()