Import upstream v0.16.22, stripped

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.
This commit is contained in:
2026-09-18 10:21:56 -07:00
commit 7dae9b29fd
1650 changed files with 485521 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use types::id::Id;
use crate::schema::prelude::{
Account, Credential, GroupAccount, PasswordCredential, SecondaryCredential, UserAccount,
};
impl Account {
pub fn into_user(self) -> Option<UserAccount> {
if let Account::User(user) = self {
Some(user)
} else {
None
}
}
pub fn into_group(self) -> Option<GroupAccount> {
if let Account::Group(group) = self {
Some(group)
} else {
None
}
}
}
impl UserAccount {
pub fn set_password(&mut self, password: String) {
if let Some(credential) = self.credentials.0.values_mut().find_map(|credential| {
if let Credential::Password(credential) = credential {
Some(credential)
} else {
None
}
}) {
credential.secret = password;
} else {
let credential_id = self.next_credential_id().into();
self.credentials
.push(Credential::Password(PasswordCredential {
credential_id,
secret: password,
..Default::default()
}));
}
}
pub fn password_credential(&self) -> Option<&PasswordCredential> {
self.credentials.iter().find_map(|credential| {
if let Credential::Password(credential) = credential {
Some(credential)
} else {
None
}
})
}
pub fn password_credential_mut(&mut self) -> Option<&mut PasswordCredential> {
self.credentials.values_mut().find_map(|credential| {
if let Credential::Password(credential) = credential {
Some(credential)
} else {
None
}
})
}
pub fn password(&self) -> Option<&str> {
self.password_credential()
.map(|credential| credential.secret.as_str())
}
pub fn into_password_credential(self) -> Option<PasswordCredential> {
self.credentials.into_iter().find_map(|credential| {
if let Credential::Password(credential) = credential {
Some(credential)
} else {
None
}
})
}
pub fn into_password(self) -> Option<String> {
self.into_password_credential()
.map(|credential| credential.secret)
}
pub fn next_credential_id(&self) -> u64 {
self.credentials
.0
.values()
.map(|credential| match credential {
Credential::Password(credential) => credential.credential_id.id() + 1,
Credential::AppPassword(credential_properties)
| Credential::ApiKey(credential_properties) => {
credential_properties.credential_id.id() + 1
}
})
.max()
.unwrap_or_default()
}
}
impl Credential {
pub fn credential_id(&self) -> Id {
match self {
Credential::Password(credential) => credential.credential_id,
Credential::AppPassword(credential_properties) => credential_properties.credential_id,
Credential::ApiKey(credential_properties) => credential_properties.credential_id,
}
}
pub fn set_credential_id(&mut self, credential_id: Id) {
match self {
Credential::Password(credential) => credential.credential_id = credential_id,
Credential::AppPassword(credential_properties) => {
credential_properties.credential_id = credential_id
}
Credential::ApiKey(credential_properties) => {
credential_properties.credential_id = credential_id
}
}
}
pub fn into_secondary_credential(self) -> Option<SecondaryCredential> {
match self {
Credential::AppPassword(credential_properties) => Some(credential_properties),
Credential::ApiKey(credential_properties) => Some(credential_properties),
Credential::Password(_) => None,
}
}
pub fn as_secondary_credential(&self) -> Option<&SecondaryCredential> {
match self {
Credential::AppPassword(credential_properties) => Some(credential_properties),
Credential::ApiKey(credential_properties) => Some(credential_properties),
Credential::Password(_) => None,
}
}
pub fn as_main_credential(&self) -> Option<&PasswordCredential> {
match self {
Credential::Password(credential) => Some(credential),
Credential::AppPassword(_) | Credential::ApiKey(_) => None,
}
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::prelude::{ArchivedItem, UTCDateTime};
use types::{blob::BlobId, id::Id};
impl ArchivedItem {
pub fn account_id(&self) -> Id {
match self {
ArchivedItem::Email(i) => i.account_id,
ArchivedItem::FileNode(i) => i.account_id,
ArchivedItem::CalendarEvent(i) => i.account_id,
ArchivedItem::ContactCard(i) => i.account_id,
ArchivedItem::SieveScript(i) => i.account_id,
}
}
pub fn blob_id(&self) -> &BlobId {
match self {
ArchivedItem::Email(i) => &i.blob_id,
ArchivedItem::FileNode(i) => &i.blob_id,
ArchivedItem::CalendarEvent(i) => &i.blob_id,
ArchivedItem::ContactCard(i) => &i.blob_id,
ArchivedItem::SieveScript(i) => &i.blob_id,
}
}
pub fn archived_until(&self) -> UTCDateTime {
match self {
ArchivedItem::Email(i) => i.archived_until,
ArchivedItem::FileNode(i) => i.archived_until,
ArchivedItem::CalendarEvent(i) => i.archived_until,
ArchivedItem::ContactCard(i) => i.archived_until,
ArchivedItem::SieveScript(i) => i.archived_until,
}
}
pub fn created_at(&self) -> UTCDateTime {
match self {
ArchivedItem::Email(i) => i.received_at,
ArchivedItem::FileNode(i) => i.created_at,
ArchivedItem::CalendarEvent(i) => i.created_at,
ArchivedItem::ContactCard(i) => i.created_at,
ArchivedItem::SieveScript(i) => i.created_at,
}
}
pub fn set_account_id(&mut self, value: Id) {
match self {
ArchivedItem::Email(i) => i.account_id = value,
ArchivedItem::FileNode(i) => i.account_id = value,
ArchivedItem::CalendarEvent(i) => i.account_id = value,
ArchivedItem::ContactCard(i) => i.account_id = value,
ArchivedItem::SieveScript(i) => i.account_id = value,
}
}
pub fn set_blob_id(&mut self, value: BlobId) {
match self {
ArchivedItem::Email(i) => i.blob_id = value,
ArchivedItem::FileNode(i) => i.blob_id = value,
ArchivedItem::CalendarEvent(i) => i.blob_id = value,
ArchivedItem::ContactCard(i) => i.blob_id = value,
ArchivedItem::SieveScript(i) => i.blob_id = value,
}
}
pub fn set_archived_until(&mut self, value: UTCDateTime) {
match self {
ArchivedItem::Email(i) => i.archived_until = value,
ArchivedItem::FileNode(i) => i.archived_until = value,
ArchivedItem::CalendarEvent(i) => i.archived_until = value,
ArchivedItem::ContactCard(i) => i.archived_until = value,
ArchivedItem::SieveScript(i) => i.archived_until = value,
}
}
pub fn account_id_mut(&mut self) -> &mut Id {
match self {
ArchivedItem::Email(i) => &mut i.account_id,
ArchivedItem::FileNode(i) => &mut i.account_id,
ArchivedItem::CalendarEvent(i) => &mut i.account_id,
ArchivedItem::ContactCard(i) => &mut i.account_id,
ArchivedItem::SieveScript(i) => &mut i.account_id,
}
}
pub fn blob_id_mut(&mut self) -> &mut BlobId {
match self {
ArchivedItem::Email(i) => &mut i.blob_id,
ArchivedItem::FileNode(i) => &mut i.blob_id,
ArchivedItem::CalendarEvent(i) => &mut i.blob_id,
ArchivedItem::ContactCard(i) => &mut i.blob_id,
ArchivedItem::SieveScript(i) => &mut i.blob_id,
}
}
pub fn archived_until_mut(&mut self) -> &mut UTCDateTime {
match self {
ArchivedItem::Email(i) => &mut i.archived_until,
ArchivedItem::FileNode(i) => &mut i.archived_until,
ArchivedItem::CalendarEvent(i) => &mut i.archived_until,
ArchivedItem::ContactCard(i) => &mut i.archived_until,
ArchivedItem::SieveScript(i) => &mut i.archived_until,
}
}
pub fn into_blob_id(self) -> BlobId {
match self {
ArchivedItem::Email(i) => i.blob_id,
ArchivedItem::FileNode(i) => i.blob_id,
ArchivedItem::CalendarEvent(i) => i.blob_id,
ArchivedItem::ContactCard(i) => i.blob_id,
ArchivedItem::SieveScript(i) => i.blob_id,
}
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::prelude::Cron;
use utils::cron::SimpleCron;
impl From<Cron> for SimpleCron {
fn from(value: Cron) -> Self {
match value {
Cron::Daily(cron) => SimpleCron::Day {
hour: cron.hour as u32,
minute: cron.minute as u32,
},
Cron::Weekly(cron) => SimpleCron::Week {
day: cron.day as u32,
hour: cron.hour as u32,
minute: cron.minute as u32,
},
Cron::Hourly(cron) => SimpleCron::Hour {
minute: cron.minute as u32,
},
}
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::{
enums::{DkimRotationStage, DkimSignatureType},
prelude::{DkimSignature, UTCDateTime},
};
use types::id::Id;
impl DkimSignature {
pub fn rotation_due(&self) -> Option<DkimRotationStage> {
let (stage, next_transition) = match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => (sign.stage, sign.next_transition_at),
DkimSignature::Dkim1RsaSha256(sign) => (sign.stage, sign.next_transition_at),
DkimSignature::Dkim2Ed25519Sha256(sign) => (sign.stage, sign.next_transition_at),
DkimSignature::Dkim2RsaSha256(sign) => (sign.stage, sign.next_transition_at),
};
next_transition.and_then(|next_transition| {
if next_transition <= UTCDateTime::now() {
Some(stage)
} else {
None
}
})
}
pub fn next_transition(&self) -> Option<UTCDateTime> {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.next_transition_at,
DkimSignature::Dkim1RsaSha256(sign) => sign.next_transition_at,
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.next_transition_at,
DkimSignature::Dkim2RsaSha256(sign) => sign.next_transition_at,
}
}
pub fn set_next_transition(&mut self, next_transition: UTCDateTime) {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => {
sign.next_transition_at = Some(next_transition)
}
DkimSignature::Dkim1RsaSha256(sign) => sign.next_transition_at = Some(next_transition),
DkimSignature::Dkim2Ed25519Sha256(sign) => {
sign.next_transition_at = Some(next_transition)
}
DkimSignature::Dkim2RsaSha256(sign) => sign.next_transition_at = Some(next_transition),
}
}
pub fn stage(&self) -> DkimRotationStage {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage,
DkimSignature::Dkim1RsaSha256(sign) => sign.stage,
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage,
DkimSignature::Dkim2RsaSha256(sign) => sign.stage,
}
}
pub fn set_stage(&mut self, stage: DkimRotationStage) {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage = stage,
DkimSignature::Dkim1RsaSha256(sign) => sign.stage = stage,
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage = stage,
DkimSignature::Dkim2RsaSha256(sign) => sign.stage = stage,
}
}
pub fn is_active(&self) -> bool {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage == DkimRotationStage::Active,
DkimSignature::Dkim1RsaSha256(sign) => sign.stage == DkimRotationStage::Active,
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage == DkimRotationStage::Active,
DkimSignature::Dkim2RsaSha256(sign) => sign.stage == DkimRotationStage::Active,
}
}
pub fn is_published(&self) -> bool {
!matches!(self.stage(), DkimRotationStage::Retired)
}
pub fn selector(&self) -> &str {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => &sign.selector,
DkimSignature::Dkim1RsaSha256(sign) => &sign.selector,
DkimSignature::Dkim2Ed25519Sha256(sign) => &sign.selector,
DkimSignature::Dkim2RsaSha256(sign) => &sign.selector,
}
}
pub fn domain_id(&self) -> Id {
match self {
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.domain_id,
DkimSignature::Dkim1RsaSha256(sign) => sign.domain_id,
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.domain_id,
DkimSignature::Dkim2RsaSha256(sign) => sign.domain_id,
}
}
}
impl DkimSignatureType {
pub const fn algorithm(self) -> &'static str {
match self {
Self::Dkim1Ed25519Sha256 | Self::Dkim2Ed25519Sha256 => "ed25519",
Self::Dkim1RsaSha256 | Self::Dkim2RsaSha256 => "rsa",
}
}
pub const fn hash(self) -> &'static str {
"sha256"
}
pub const fn version(self) -> &'static str {
match self {
Self::Dkim1Ed25519Sha256 | Self::Dkim1RsaSha256 => "1",
Self::Dkim2Ed25519Sha256 | Self::Dkim2RsaSha256 => "2",
}
}
}
+78
View File
@@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::prelude::{Duration, HttpAuth};
use utils::{
Client, HeaderMap,
http::{build_http_client, build_http_headers},
map::vec_map::VecMap,
};
impl HttpAuth {
pub async fn build_headers(
&self,
extra_headers: VecMap<String, String>,
content_type: Option<&str>,
) -> Result<HeaderMap, String> {
match self {
HttpAuth::Unauthenticated => {
build_http_headers(extra_headers, None, None, None, content_type)
}
HttpAuth::Basic(auth) => build_http_headers(
extra_headers,
auth.username.as_str().into(),
auth.secret.secret().await?.as_ref().into(),
None,
content_type,
),
HttpAuth::Bearer(auth) => build_http_headers(
extra_headers,
None,
None,
auth.bearer_token.secret().await?.as_ref().into(),
content_type,
),
}
}
pub async fn build_http_client(
&self,
extra_headers: VecMap<String, String>,
content_type: Option<&str>,
timeout: Duration,
allow_invalid_certs: bool,
) -> Result<Client, String> {
match self {
HttpAuth::Unauthenticated => build_http_client(
extra_headers,
None,
None,
None,
content_type,
timeout.into_inner(),
allow_invalid_certs,
),
HttpAuth::Basic(auth) => build_http_client(
extra_headers,
auth.username.as_str().into(),
auth.secret.secret().await?.as_ref().into(),
None,
content_type,
timeout.into_inner(),
allow_invalid_certs,
),
HttpAuth::Bearer(auth) => build_http_client(
extra_headers,
None,
None,
auth.bearer_token.secret().await?.as_ref().into(),
content_type,
timeout.into_inner(),
allow_invalid_certs,
),
}
}
}
+46
View File
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::prelude::{DkimSignature, Roles, SecretText};
use types::id::Id;
pub mod account;
pub mod archived_item;
pub mod cron;
pub mod dkim;
pub mod http;
pub mod report;
pub mod secret;
pub mod task;
impl Roles {
pub fn role_ids(&self) -> Option<&[Id]> {
match self {
Roles::Default => None,
Roles::Custom(custom_roles) => Some(custom_roles.role_ids.as_slice()),
}
}
}
impl DkimSignature {
pub fn private_key(&self) -> &SecretText {
match self {
DkimSignature::Dkim1Ed25519Sha256(signature) => &signature.private_key,
DkimSignature::Dkim1RsaSha256(signature) => &signature.private_key,
DkimSignature::Dkim2Ed25519Sha256(signature) => &signature.private_key,
DkimSignature::Dkim2RsaSha256(signature) => &signature.private_key,
}
}
pub fn private_key_mut(&mut self) -> &mut SecretText {
match self {
DkimSignature::Dkim1Ed25519Sha256(signature) => &mut signature.private_key,
DkimSignature::Dkim1RsaSha256(signature) => &mut signature.private_key,
DkimSignature::Dkim2Ed25519Sha256(signature) => &mut signature.private_key,
DkimSignature::Dkim2RsaSha256(signature) => &mut signature.private_key,
}
}
}
File diff suppressed because it is too large Load Diff
+152
View File
@@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::prelude::{
PublicStringOptional, PublicStringValue, PublicText, SecretKey, SecretKeyEnvironmentVariable,
SecretKeyFile, SecretKeyOptional, SecretKeyValue, SecretText, SecretTextOptional,
SecretTextValue,
};
use std::borrow::Cow;
impl SecretKey {
pub async fn secret(&self) -> Result<Cow<'_, str>, String> {
match self {
SecretKey::Value(value) => Ok(Cow::Borrowed(value.secret())),
SecretKey::File(file) => file.secret().await.map(Cow::Owned),
SecretKey::EnvironmentVariable(env_var) => env_var.secret().map(Cow::Owned),
}
}
}
impl SecretText {
pub async fn secret(&self) -> Result<Cow<'_, str>, String> {
match self {
SecretText::Text(value) => Ok(Cow::Borrowed(value.secret())),
SecretText::File(file) => file.secret().await.map(Cow::Owned),
SecretText::EnvironmentVariable(env_var) => env_var.secret().map(Cow::Owned),
}
}
}
impl PublicText {
pub async fn value(&self) -> Result<Cow<'_, str>, String> {
match self {
PublicText::Text(value) => Ok(Cow::Borrowed(value.value.as_str())),
PublicText::File(file) => file.secret().await.map(Cow::Owned),
PublicText::EnvironmentVariable(env_var) => env_var.secret().map(Cow::Owned),
}
}
}
impl SecretKeyOptional {
pub async fn secret(&self) -> Result<Option<Cow<'_, str>>, String> {
match self {
SecretKeyOptional::None => Ok(None),
SecretKeyOptional::Value(secret_key_value) => {
Ok(Some(Cow::Borrowed(secret_key_value.secret())))
}
SecretKeyOptional::EnvironmentVariable(secret_key_environment_variable) => {
secret_key_environment_variable
.secret()
.map(|s| Some(Cow::Owned(s)))
}
SecretKeyOptional::File(secret_key_file) => {
secret_key_file.secret().await.map(|s| Some(Cow::Owned(s)))
}
}
}
}
impl PublicStringOptional {
pub async fn value(&self) -> Result<Option<Cow<'_, str>>, String> {
match self {
PublicStringOptional::None => Ok(None),
PublicStringOptional::Value(public_string_value) => {
Ok(Some(Cow::Borrowed(public_string_value.value())))
}
PublicStringOptional::EnvironmentVariable(secret_key_environment_variable) => {
secret_key_environment_variable
.secret()
.map(|s| Some(Cow::Owned(s)))
}
PublicStringOptional::File(secret_key_file) => {
secret_key_file.secret().await.map(|s| Some(Cow::Owned(s)))
}
}
}
}
impl PublicStringValue {
pub fn value(&self) -> &str {
self.value.as_str()
}
}
impl SecretTextOptional {
pub async fn secret(&self) -> Result<Option<Cow<'_, str>>, String> {
match self {
SecretTextOptional::None => Ok(None),
SecretTextOptional::Text(secret_text_value) => {
Ok(Some(Cow::Borrowed(secret_text_value.secret())))
}
SecretTextOptional::EnvironmentVariable(secret_text_environment_variable) => {
secret_text_environment_variable
.secret()
.map(|s| Some(Cow::Owned(s)))
}
SecretTextOptional::File(secret_text_file) => {
secret_text_file.secret().await.map(|s| Some(Cow::Owned(s)))
}
}
}
}
impl SecretKeyValue {
pub fn secret(&self) -> &str {
self.secret.as_str()
}
}
impl SecretTextValue {
pub fn secret(&self) -> &str {
self.secret.as_str()
}
}
impl SecretKeyFile {
pub async fn secret(&self) -> Result<String, String> {
let path = self.file_path.trim();
if !path.is_empty() {
tokio::fs::read_to_string(path)
.await
.map_err(|err| format!("Failed to read secret from file '{}': {}", path, err))
.and_then(|content| {
let secret = content.trim_end();
if !secret.is_empty() {
Ok(secret.to_string())
} else {
Err(format!("Secret in file '{}' is empty", path))
}
})
} else {
Err("File path cannot be empty".to_string())
}
}
}
impl SecretKeyEnvironmentVariable {
pub fn secret(&self) -> Result<String, String> {
let var = self.variable_name.trim();
if !var.is_empty() {
std::env::var(var)
.ok()
.filter(|v| !v.is_empty())
.ok_or_else(|| format!("Environment variable '{}' not found", var))
} else {
Err("Variable name cannot be empty".to_string())
}
}
}
+132
View File
@@ -0,0 +1,132 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::schema::{
enums::Permission,
prelude::{Action, Task, TaskStatus, TaskStatusPending, UTCDateTime},
};
impl Task {
pub fn set_status(&mut self, status: TaskStatus) {
match self {
Task::IndexDocument(task) => task.status = status,
Task::UnindexDocument(task) => task.status = status,
Task::IndexTrace(task) => task.status = status,
Task::CalendarAlarmEmail(task) => task.status = status,
Task::CalendarAlarmNotification(task) => task.status = status,
Task::CalendarItipMessage(task) => task.status = status,
Task::MergeThreads(task) => task.status = status,
Task::DmarcReport(task) => task.status = status,
Task::TlsReport(task) => task.status = status,
Task::RestoreArchivedItem(task) => task.status = status,
Task::DestroyAccount(task) => task.status = status,
Task::AccountMaintenance(task) => task.status = status,
Task::StoreMaintenance(task) => task.status = status,
Task::SpamFilterMaintenance(task) => task.status = status,
Task::AcmeRenewal(task) => task.status = status,
Task::DkimManagement(task) => task.status = status,
Task::DnsManagement(task) => task.status = status,
Task::TenantMaintenance(task) => task.status = status,
}
}
pub fn status(&self) -> &TaskStatus {
match self {
Task::IndexDocument(task) => &task.status,
Task::UnindexDocument(task) => &task.status,
Task::IndexTrace(task) => &task.status,
Task::CalendarAlarmEmail(task) => &task.status,
Task::CalendarAlarmNotification(task) => &task.status,
Task::CalendarItipMessage(task) => &task.status,
Task::MergeThreads(task) => &task.status,
Task::DmarcReport(task) => &task.status,
Task::TlsReport(task) => &task.status,
Task::RestoreArchivedItem(task) => &task.status,
Task::DestroyAccount(task) => &task.status,
Task::AccountMaintenance(task) => &task.status,
Task::StoreMaintenance(task) => &task.status,
Task::SpamFilterMaintenance(task) => &task.status,
Task::AcmeRenewal(task) => &task.status,
Task::DkimManagement(task) => &task.status,
Task::DnsManagement(task) => &task.status,
Task::TenantMaintenance(task) => &task.status,
}
}
pub fn attempt_number(&self) -> u64 {
match self.status() {
TaskStatus::Pending(_) => 0,
TaskStatus::Retry(status) => status.attempt_number,
TaskStatus::Failed(status) => status.failed_attempt_number,
}
}
pub fn due_timestamp(&self) -> u64 {
match self.status() {
TaskStatus::Pending(status) => status.due.timestamp() as u64,
TaskStatus::Retry(status) => status.due.timestamp() as u64,
TaskStatus::Failed(_) => u64::MAX,
}
}
pub fn permission(&self) -> Permission {
match self {
Task::IndexDocument(_) => Permission::TaskIndexDocument,
Task::UnindexDocument(_) => Permission::TaskUnindexDocument,
Task::IndexTrace(_) => Permission::TaskIndexTrace,
Task::CalendarAlarmEmail(_) => Permission::TaskCalendarAlarmEmail,
Task::CalendarAlarmNotification(_) => Permission::TaskCalendarAlarmNotification,
Task::CalendarItipMessage(_) => Permission::TaskCalendarItipMessage,
Task::MergeThreads(_) => Permission::TaskMergeThreads,
Task::DmarcReport(_) => Permission::TaskDmarcReport,
Task::TlsReport(_) => Permission::TaskTlsReport,
Task::RestoreArchivedItem(_) => Permission::TaskRestoreArchivedItem,
Task::DestroyAccount(_) => Permission::TaskDestroyAccount,
Task::AccountMaintenance(_) => Permission::TaskAccountMaintenance,
Task::StoreMaintenance(_) => Permission::TaskStoreMaintenance,
Task::SpamFilterMaintenance(_) => Permission::TaskSpamFilterMaintenance,
Task::AcmeRenewal(_) => Permission::TaskAcmeRenewal,
Task::DkimManagement(_) => Permission::TaskDkimManagement,
Task::DnsManagement(_) => Permission::TaskDnsManagement,
Task::TenantMaintenance(_) => Permission::TaskTenantMaintenance,
}
}
}
impl Action {
pub fn permission(&self) -> Permission {
match self {
Action::ReloadSettings => Permission::ActionReloadSettings,
Action::ReloadTlsCertificates => Permission::ActionReloadTlsCertificates,
Action::ReloadLookupStores => Permission::ActionReloadLookupStores,
Action::ReloadBlockedIps => Permission::ActionReloadBlockedIps,
Action::TroubleshootDmarc(_) => Permission::ActionTroubleshootDmarc,
Action::ClassifySpam(_) => Permission::ActionClassifySpam,
Action::InvalidateCaches => Permission::ActionInvalidateCaches,
Action::InvalidateNegativeCaches => Permission::ActionInvalidateNegativeCaches,
Action::PauseMtaQueue => Permission::ActionPauseMtaQueue,
Action::ResumeMtaQueue => Permission::ActionResumeMtaQueue,
Action::UpdateApps => Permission::ActionUpdateApps,
}
}
}
impl TaskStatus {
pub fn now() -> Self {
let now = UTCDateTime::now();
TaskStatus::Pending(TaskStatusPending {
created_at: now,
due: now,
})
}
pub fn at(timestamp: i64) -> Self {
TaskStatus::Pending(TaskStatusPending {
due: UTCDateTime::from_timestamp(timestamp),
created_at: UTCDateTime::now(),
})
}
}