Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
211 lines
6.4 KiB
Rust
211 lines
6.4 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use crate::{
|
|
core::{Session, SessionData},
|
|
op::ImapContext,
|
|
spawn_op,
|
|
};
|
|
use common::network::SessionStream;
|
|
use imap_proto::{
|
|
Command, ResponseCode, StatusResponse,
|
|
protocol::{
|
|
ImapResponse,
|
|
capability::QuotaResourceName,
|
|
quota::{Arguments, QuotaItem, QuotaResource, Response},
|
|
},
|
|
receiver::Request,
|
|
};
|
|
use registry::schema::enums::Permission;
|
|
use std::time::Instant;
|
|
|
|
impl<T: SessionStream> Session<T> {
|
|
pub async fn handle_get_quota(&mut self, request: Request<Command>) -> trc::Result<()> {
|
|
// Validate access
|
|
self.assert_has_permission(Permission::ImapStatus)?;
|
|
|
|
let data = self.state.session_data();
|
|
|
|
spawn_op!(data, {
|
|
match request.parse_get_quota() {
|
|
Ok(argument) => match data.get_quota(argument).await {
|
|
Ok(response) => {
|
|
data.write_bytes(response).await?;
|
|
}
|
|
Err(error) => {
|
|
data.write_error(error).await?;
|
|
}
|
|
},
|
|
Err(err) => data.write_error(err).await?,
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
pub async fn handle_get_quota_root(&mut self, request: Request<Command>) -> trc::Result<()> {
|
|
// Validate access
|
|
self.assert_has_permission(Permission::ImapStatus)?;
|
|
|
|
let data = self.state.session_data();
|
|
let is_utf8 = self.is_utf8;
|
|
|
|
spawn_op!(data, {
|
|
match request.parse_get_quota_root(is_utf8) {
|
|
Ok(argument) => match data.get_quota_root(argument).await {
|
|
Ok(response) => {
|
|
data.write_bytes(response).await?;
|
|
}
|
|
Err(error) => {
|
|
data.write_error(error).await?;
|
|
}
|
|
},
|
|
Err(err) => data.write_error(err).await?,
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<T: SessionStream> SessionData<T> {
|
|
pub async fn get_quota(&self, arguments: Arguments) -> trc::Result<Vec<u8>> {
|
|
let op_start = Instant::now();
|
|
|
|
// Refresh mailboxes
|
|
self.synchronize_mailboxes(false)
|
|
.await
|
|
.imap_ctx(&arguments.tag, trc::location!())?;
|
|
|
|
// Validate quota root
|
|
let account_id: u32 = arguments
|
|
.name
|
|
.strip_prefix("#")
|
|
.and_then(|id| id.parse().ok())
|
|
.filter(|id| self.access_token.is_member(*id))
|
|
.ok_or_else(|| {
|
|
trc::ImapEvent::Error
|
|
.into_err()
|
|
.details("Invalid quota root parameter.")
|
|
.id(arguments.tag.to_string())
|
|
})?;
|
|
|
|
// Obtain access token for mailbox
|
|
let account = self
|
|
.server
|
|
.account(account_id)
|
|
.await
|
|
.imap_ctx(&arguments.tag, trc::location!())?;
|
|
let used_quota = self
|
|
.server
|
|
.get_used_quota_account(account_id)
|
|
.await
|
|
.imap_ctx(&arguments.tag, trc::location!())?;
|
|
|
|
trc::event!(
|
|
Imap(trc::ImapEvent::GetQuota),
|
|
SpanId = self.session_id,
|
|
Id = arguments.name.clone(),
|
|
Details = vec![
|
|
trc::Value::from(used_quota),
|
|
trc::Value::from(account.disk_quota())
|
|
],
|
|
Elapsed = op_start.elapsed()
|
|
);
|
|
|
|
// Build response
|
|
let response = Response {
|
|
quota_root_items: vec![],
|
|
quota_items: vec![QuotaItem {
|
|
name: arguments.name,
|
|
resources: if account.disk_quota() > 0 {
|
|
vec![QuotaResource {
|
|
resource: QuotaResourceName::Storage,
|
|
total: account.disk_quota(),
|
|
used: used_quota as u64,
|
|
}]
|
|
} else {
|
|
vec![]
|
|
},
|
|
}],
|
|
};
|
|
|
|
Ok(StatusResponse::ok("GETQUOTA successful.")
|
|
.with_tag(arguments.tag)
|
|
.serialize(response.serialize()))
|
|
}
|
|
|
|
pub async fn get_quota_root(&self, arguments: Arguments) -> trc::Result<Vec<u8>> {
|
|
let op_start = Instant::now();
|
|
|
|
// Refresh mailboxes
|
|
self.synchronize_mailboxes(false)
|
|
.await
|
|
.imap_ctx(&arguments.tag, trc::location!())?;
|
|
|
|
// Validate mailbox
|
|
let account_id = if let Some(mailbox) = self.get_mailbox_by_name(&arguments.name) {
|
|
mailbox.account_id
|
|
} else {
|
|
return Err(trc::ImapEvent::Error
|
|
.into_err()
|
|
.details("Mailbox does not exist.")
|
|
.code(ResponseCode::TryCreate)
|
|
.id(arguments.tag));
|
|
};
|
|
|
|
// Obtain access token for mailbox
|
|
let account = self
|
|
.server
|
|
.account(account_id)
|
|
.await
|
|
.imap_ctx(&arguments.tag, trc::location!())?;
|
|
let used_quota = self
|
|
.server
|
|
.get_used_quota_account(account_id)
|
|
.await
|
|
.imap_ctx(&arguments.tag, trc::location!())?;
|
|
|
|
trc::event!(
|
|
Imap(trc::ImapEvent::GetQuota),
|
|
SpanId = self.session_id,
|
|
MailboxName = arguments.name.clone(),
|
|
Details = vec![
|
|
trc::Value::from(used_quota),
|
|
trc::Value::from(account.disk_quota())
|
|
],
|
|
Elapsed = op_start.elapsed()
|
|
);
|
|
|
|
// Build response
|
|
let response = Response {
|
|
quota_root_items: vec![arguments.name, format!("#{account_id}")],
|
|
quota_items: vec![QuotaItem {
|
|
name: format!("#{account_id}"),
|
|
resources: if account.disk_quota() > 0 {
|
|
vec![QuotaResource {
|
|
resource: QuotaResourceName::Storage,
|
|
total: account.disk_quota(),
|
|
used: used_quota as u64,
|
|
}]
|
|
} else {
|
|
vec![]
|
|
},
|
|
}],
|
|
};
|
|
|
|
Ok(StatusResponse::ok("GETQUOTAROOT successful.")
|
|
.with_tag(arguments.tag)
|
|
.serialize(response.serialize()))
|
|
}
|
|
}
|