mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2025-09-14 16:04:48 +08:00
Allow STATUS and ACL operations on virtual mailboxes
This commit is contained in:
parent
3fa5c769bd
commit
9860631691
4 changed files with 97 additions and 18 deletions
|
@ -37,7 +37,8 @@ use super::{SelectedMailbox, Session, SessionData, State, IMAP};
|
|||
impl<T: AsyncRead> Session<T> {
|
||||
pub async fn ingest(&mut self, bytes: &[u8]) -> crate::Result<bool> {
|
||||
/*for line in String::from_utf8_lossy(bytes).split("\r\n") {
|
||||
let c = println!("<- {:?}", &line[..std::cmp::min(line.len(), 100)]);
|
||||
//let c = println!("<- {:?}", &line[..std::cmp::min(line.len(), 100)]);
|
||||
let c = println!("{}", line);
|
||||
}*/
|
||||
|
||||
tracing::trace!(parent: &self.span,
|
||||
|
|
|
@ -57,12 +57,8 @@ pub fn spawn_writer(mut stream: Event, span: tracing::Span) -> mpsc::Sender<Even
|
|||
data = std::str::from_utf8(bytes.as_ref()).unwrap_or_default(),
|
||||
size = bytes.len()
|
||||
);
|
||||
/*let c = println!(
|
||||
"<- {:?}",
|
||||
String::from_utf8_lossy(
|
||||
&bytes[..std::cmp::min(bytes.len(), 100)]
|
||||
)
|
||||
);*/
|
||||
|
||||
//let c = print!("{}", String::from_utf8_lossy(&bytes));
|
||||
|
||||
match stream_tx.write_all(bytes.as_ref()).await {
|
||||
Ok(_) => {
|
||||
|
@ -105,6 +101,8 @@ pub fn spawn_writer(mut stream: Event, span: tracing::Span) -> mpsc::Sender<Even
|
|||
size = bytes.len()
|
||||
);
|
||||
|
||||
//let c = print!("{}", String::from_utf8_lossy(&bytes));
|
||||
|
||||
match stream_tx.write_all(bytes.as_ref()).await {
|
||||
Ok(_) => {
|
||||
let _ = stream_tx.flush().await;
|
||||
|
|
|
@ -58,7 +58,7 @@ impl<T: AsyncRead> Session<T> {
|
|||
|
||||
tokio::spawn(async move {
|
||||
match data.get_acl_mailbox(&arguments, true).await {
|
||||
Ok((_, values, _)) => {
|
||||
Ok(Some((_, values, _))) => {
|
||||
let mut permissions = Vec::new();
|
||||
if let Some(acls) = values
|
||||
.inner
|
||||
|
@ -137,6 +137,21 @@ impl<T: AsyncRead> Session<T> {
|
|||
)
|
||||
.await;
|
||||
}
|
||||
Ok(None) => {
|
||||
// Response for "All Mail" folder
|
||||
data.write_bytes(
|
||||
StatusResponse::completed(Command::GetAcl)
|
||||
.with_tag(arguments.tag)
|
||||
.serialize(
|
||||
GetAclResponse {
|
||||
mailbox_name: arguments.mailbox_name,
|
||||
permissions: vec![],
|
||||
}
|
||||
.into_bytes(is_rev2),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(response) => {
|
||||
data.write_bytes(response.with_tag(arguments.tag).into_bytes())
|
||||
.await;
|
||||
|
@ -157,7 +172,7 @@ impl<T: AsyncRead> Session<T> {
|
|||
|
||||
tokio::spawn(async move {
|
||||
match data.get_acl_mailbox(&arguments, false).await {
|
||||
Ok((mailbox, values, access_token)) => {
|
||||
Ok(Some((mailbox, values, access_token))) => {
|
||||
data.write_bytes(
|
||||
StatusResponse::completed(Command::MyRights)
|
||||
.with_tag(arguments.tag)
|
||||
|
@ -212,6 +227,30 @@ impl<T: AsyncRead> Session<T> {
|
|||
)
|
||||
.await;
|
||||
}
|
||||
Ok(None) => {
|
||||
// Response for All mail folder
|
||||
data.write_bytes(
|
||||
StatusResponse::completed(Command::MyRights)
|
||||
.with_tag(arguments.tag)
|
||||
.serialize(
|
||||
MyRightsResponse {
|
||||
mailbox_name: arguments.mailbox_name,
|
||||
rights: vec![
|
||||
Rights::Read,
|
||||
Rights::Lookup,
|
||||
Rights::Insert,
|
||||
Rights::DeleteMessages,
|
||||
Rights::Expunge,
|
||||
Rights::Seen,
|
||||
Rights::Write,
|
||||
Rights::Post,
|
||||
],
|
||||
}
|
||||
.into_bytes(is_rev2),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(response) => {
|
||||
data.write_bytes(response.with_tag(arguments.tag).into_bytes())
|
||||
.await;
|
||||
|
@ -233,7 +272,18 @@ impl<T: AsyncRead> Session<T> {
|
|||
tokio::spawn(async move {
|
||||
// Validate mailbox
|
||||
let (mailbox, values, _) = match data.get_acl_mailbox(&arguments, true).await {
|
||||
Ok(result) => result,
|
||||
Ok(Some(result)) => result,
|
||||
Ok(None) => {
|
||||
data.write_bytes(
|
||||
StatusResponse::no(
|
||||
"ACL operations are not permitted on this mailbox.",
|
||||
)
|
||||
.with_tag(arguments.tag)
|
||||
.into_bytes(),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
Err(response) => {
|
||||
data.write_bytes(response.with_tag(arguments.tag).into_bytes())
|
||||
.await;
|
||||
|
@ -475,7 +525,7 @@ impl SessionData {
|
|||
&self,
|
||||
arguments: &Arguments,
|
||||
validate: bool,
|
||||
) -> crate::op::Result<(MailboxId, HashedValue<Object<Value>>, Arc<AccessToken>)> {
|
||||
) -> crate::op::Result<Option<(MailboxId, HashedValue<Object<Value>>, Arc<AccessToken>)>> {
|
||||
if let Some(mailbox) = self.get_mailbox_by_name(&arguments.mailbox_name) {
|
||||
if let Some(mailbox_id) = mailbox.mailbox_id {
|
||||
match (
|
||||
|
@ -497,7 +547,7 @@ impl SessionData {
|
|||
.effective_acl(&access_token)
|
||||
.contains(Acl::Administer)
|
||||
{
|
||||
Ok((mailbox, values, access_token))
|
||||
Ok(Some((mailbox, values, access_token)))
|
||||
} else {
|
||||
Err(StatusResponse::no(
|
||||
"You do not have enough permissions to perform this operation.",
|
||||
|
@ -509,9 +559,7 @@ impl SessionData {
|
|||
_ => Err(StatusResponse::database_failure()),
|
||||
}
|
||||
} else {
|
||||
Err(StatusResponse::no(
|
||||
"ACL operations are not permitted on this mailbox.",
|
||||
))
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Err(StatusResponse::no("Mailbox does not exist."))
|
||||
|
|
|
@ -87,9 +87,41 @@ impl SessionData {
|
|||
let mailbox = if let Some(mailbox) = self.get_mailbox_by_name(&mailbox_name) {
|
||||
mailbox
|
||||
} else {
|
||||
return Err(
|
||||
StatusResponse::no("Mailbox does not exist.").with_code(ResponseCode::NonExistent)
|
||||
);
|
||||
// Some IMAP clients will try to get the status of a mailbox with the NoSelect flag
|
||||
return if mailbox_name == self.imap.name_shared
|
||||
|| mailbox_name
|
||||
.split_once('/')
|
||||
.map_or(false, |(base_name, path)| {
|
||||
base_name == self.imap.name_shared && !path.contains('/')
|
||||
})
|
||||
{
|
||||
Ok(StatusItem {
|
||||
mailbox_name,
|
||||
items: items
|
||||
.iter()
|
||||
.map(|item| {
|
||||
(
|
||||
*item,
|
||||
match item {
|
||||
Status::Messages
|
||||
| Status::Size
|
||||
| Status::Unseen
|
||||
| Status::Recent
|
||||
| Status::Deleted
|
||||
| Status::HighestModSeq => StatusItemType::Number(0),
|
||||
Status::UidNext | Status::UidValidity => {
|
||||
StatusItemType::Number(1)
|
||||
}
|
||||
Status::MailboxId => StatusItemType::String("none".to_string()),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
} else {
|
||||
Err(StatusResponse::no("Mailbox does not exist.")
|
||||
.with_code(ResponseCode::NonExistent))
|
||||
};
|
||||
};
|
||||
|
||||
// Make sure all requested fields are up to date
|
||||
|
|
Loading…
Add table
Reference in a new issue