diff options
author | Alex Auvolat <alex@adnab.me> | 2022-07-12 16:35:11 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2022-07-12 16:35:11 +0200 |
commit | 46d952598474e851ee528515d7a9ffab88d3ad49 (patch) | |
tree | a062bc94e8a1841f8d017c97cccbebc1d44cf1a4 /src/imap/command/authenticated.rs | |
parent | d4e0e66581ff785e89edd15e2b8d68640f370a0e (diff) | |
download | aerogramme-46d952598474e851ee528515d7a9ffab88d3ad49.tar.gz aerogramme-46d952598474e851ee528515d7a9ffab88d3ad49.zip |
Implement APPEND
Diffstat (limited to 'src/imap/command/authenticated.rs')
-rw-r--r-- | src/imap/command/authenticated.rs | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/src/imap/command/authenticated.rs b/src/imap/command/authenticated.rs index 6208290..32a8e1e 100644 --- a/src/imap/command/authenticated.rs +++ b/src/imap/command/authenticated.rs @@ -1,11 +1,13 @@ use std::collections::BTreeMap; use std::sync::Arc; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use boitalettres::proto::res::body::Data as Body; use boitalettres::proto::{Request, Response}; use imap_codec::types::command::{CommandBody, StatusAttribute}; -use imap_codec::types::flag::FlagNameAttribute; +use imap_codec::types::core::NonZeroBytes; +use imap_codec::types::datetime::MyDateTime; +use imap_codec::types::flag::{Flag, FlagNameAttribute}; use imap_codec::types::mailbox::{ListMailbox, Mailbox as MailboxCodec}; use imap_codec::types::response::{Code, Data, StatusAttributeValue}; @@ -13,7 +15,10 @@ use crate::imap::command::anonymous; use crate::imap::flow; use crate::imap::mailbox_view::MailboxView; +use crate::mail::mailbox::Mailbox; +use crate::mail::uidindex::*; use crate::mail::user::{User, INBOX, MAILBOX_HIERARCHY_DELIMITER}; +use crate::mail::IMF; pub struct AuthenticatedContext<'a> { pub req: &'a Request, @@ -44,6 +49,12 @@ pub async fn dispatch<'a>(ctx: AuthenticatedContext<'a>) -> Result<(Response, fl CommandBody::Unsubscribe { mailbox } => ctx.unsubscribe(mailbox).await, CommandBody::Select { mailbox } => ctx.select(mailbox).await, CommandBody::Examine { mailbox } => ctx.examine(mailbox).await, + CommandBody::Append { + mailbox, + flags, + date, + message, + } => ctx.append(mailbox, flags, date, message).await, _ => { let ctx = anonymous::AnonymousContext { req: ctx.req, @@ -316,4 +327,52 @@ impl<'a> AuthenticatedContext<'a> { flow::Transition::Examine(mb), )) } + + async fn append( + self, + mailbox: &MailboxCodec, + flags: &[Flag], + date: &Option<MyDateTime>, + message: &NonZeroBytes, + ) -> Result<(Response, flow::Transition)> { + match self.append_internal(mailbox, flags, date, message).await { + Ok((_mb, uidvalidity, uid)) => Ok(( + Response::ok("APPEND completed")?.with_extra_code(Code::Other( + "APPENDUID".try_into().unwrap(), + Some(format!("{} {}", uidvalidity, uid)), + )), + flow::Transition::None, + )), + Err(e) => Ok((Response::no(&e.to_string())?, flow::Transition::None)), + } + } + + pub(crate) async fn append_internal( + self, + mailbox: &MailboxCodec, + flags: &[Flag], + date: &Option<MyDateTime>, + message: &NonZeroBytes, + ) -> Result<(Arc<Mailbox>, ImapUidvalidity, ImapUidvalidity)> { + let name = String::try_from(mailbox.clone())?; + + let mb_opt = self.user.open_mailbox(&name).await?; + let mb = match mb_opt { + Some(mb) => mb, + None => bail!("Mailbox does not exist"), + }; + + if date.is_some() { + bail!("Cannot set date when appending message"); + } + + let msg = IMF::try_from(message.as_slice()) + .map_err(|_| anyhow!("Could not parse e-mail message"))?; + let flags = flags.iter().map(|x| x.to_string()).collect::<Vec<_>>(); + // TODO: filter allowed flags? ping @Quentin + + let (uidvalidity, uid) = mb.append(msg, None, &flags[..]).await?; + + Ok((mb, uidvalidity, uid)) + } } |