mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2025-09-03 18:44:24 +08:00
This commit is contained in:
parent
dd0226b75a
commit
9310083222
43 changed files with 655 additions and 71 deletions
|
@ -62,12 +62,12 @@ impl Server {
|
|||
|
||||
// Apply principal permissions
|
||||
let mut permissions = role_permissions.finalize();
|
||||
let mut tenant = None;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
let mut tenant = None;
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.is_enterprise_edition() {
|
||||
if let Some(tenant_id) = principal.tenant {
|
||||
|
|
|
@ -189,8 +189,12 @@ impl Core {
|
|||
}
|
||||
|
||||
Self {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
enterprise,
|
||||
// SPDX-SnippetEnd
|
||||
sieve: Scripting::parse(config, &stores).await,
|
||||
network: Network::parse(config),
|
||||
smtp: SmtpConfig::parse(config).await,
|
||||
|
|
|
@ -40,8 +40,12 @@ pub enum TelemetrySubscriberType {
|
|||
Webhook(WebhookTracer),
|
||||
#[cfg(unix)]
|
||||
JournalTracer(crate::telemetry::tracers::journald::Subscriber),
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
StoreTracer(StoreTracer),
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -88,11 +92,15 @@ pub struct WebhookTracer {
|
|||
pub headers: HeaderMap,
|
||||
}
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[derive(Debug)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub struct StoreTracer {
|
||||
pub store: store::Store,
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RotationStrategy {
|
||||
|
@ -477,8 +485,12 @@ impl Tracers {
|
|||
TelemetrySubscriberType::JournalTracer(_) => {
|
||||
EventType::Telemetry(TelemetryEvent::JournalError).into()
|
||||
}
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
TelemetrySubscriberType::StoreTracer(_) => None,
|
||||
// SPDX-SnippetEnd
|
||||
};
|
||||
|
||||
// Parse disabled events
|
||||
|
@ -509,6 +521,10 @@ impl Tracers {
|
|||
}
|
||||
}
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Parse tracing history
|
||||
#[cfg(feature = "enterprise")]
|
||||
{
|
||||
|
@ -540,6 +556,7 @@ impl Tracers {
|
|||
}
|
||||
}
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
// Parse webhooks
|
||||
for id in config.sub_keys("webhook", ".url") {
|
||||
|
|
|
@ -51,8 +51,6 @@ pub mod auth;
|
|||
pub mod config;
|
||||
pub mod core;
|
||||
pub mod dns;
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod enterprise;
|
||||
pub mod expr;
|
||||
pub mod i18n;
|
||||
pub mod ipc;
|
||||
|
@ -63,6 +61,15 @@ pub mod sharing;
|
|||
pub mod storage;
|
||||
pub mod telemetry;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod enterprise;
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
pub use psl;
|
||||
|
||||
pub static VERSION_PRIVATE: &str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -338,8 +345,13 @@ pub struct Core {
|
|||
pub spam: SpamFilterConfig,
|
||||
pub imap: ImapConfig,
|
||||
pub metrics: Metrics,
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub enterprise: Option<enterprise::Enterprise>,
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
impl<T: CacheItemWeight> CacheItemWeight for CacheSwap<T> {
|
||||
|
|
|
@ -427,8 +427,14 @@ impl BootManager {
|
|||
let cache = Caches::parse(&mut config);
|
||||
|
||||
// Enable telemetry
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
telemetry.enable(core.is_enterprise_edition());
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
telemetry.enable(false);
|
||||
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use hyper::HeaderMap;
|
||||
use utils::HttpLimitResponse;
|
||||
|
||||
use crate::USER_AGENT;
|
||||
|
||||
use self::config::ConfigManager;
|
||||
use crate::USER_AGENT;
|
||||
use hyper::HeaderMap;
|
||||
use std::time::Duration;
|
||||
use utils::HttpLimitResponse;
|
||||
|
||||
pub mod backup;
|
||||
pub mod boot;
|
||||
|
@ -23,9 +20,19 @@ pub mod webadmin;
|
|||
|
||||
const DEFAULT_SPAMFILTER_URL: &str =
|
||||
"https://github.com/stalwartlabs/spam-filter/releases/latest/download/spam-filter.toml";
|
||||
pub const WEBADMIN_KEY: &[u8] = "STALWART_WEBADMIN".as_bytes();
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
const DEFAULT_WEBADMIN_URL: &str =
|
||||
"https://github.com/stalwartlabs/webadmin/releases/latest/download/webadmin.zip";
|
||||
pub const WEBADMIN_KEY: &[u8] = "STALWART_WEBADMIN".as_bytes();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
const DEFAULT_WEBADMIN_URL: &str =
|
||||
"https://github.com/stalwartlabs/webadmin/releases/latest/download/webadmin-oss.zip";
|
||||
|
||||
impl ConfigManager {
|
||||
pub async fn fetch_resource(&self, resource_id: &str) -> Result<Vec<u8>, String> {
|
||||
|
|
|
@ -7,5 +7,9 @@
|
|||
pub mod otel;
|
||||
pub mod prometheus;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod store;
|
||||
// SPDX-SnippetEnd
|
||||
|
|
|
@ -16,8 +16,12 @@ impl Server {
|
|||
pub async fn export_prometheus_metrics(&self) -> trc::Result<String> {
|
||||
let mut metrics = Vec::new();
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let is_enterprise = self.is_enterprise_edition();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let is_enterprise = false;
|
||||
|
|
|
@ -108,12 +108,15 @@ impl TelemetrySubscriberType {
|
|||
TelemetrySubscriberType::JournalTracer(subscriber) => {
|
||||
tracers::journald::spawn_journald_tracer(builder, subscriber)
|
||||
}
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
TelemetrySubscriberType::StoreTracer(subscriber) => {
|
||||
if is_enterprise {
|
||||
tracers::store::spawn_store_tracer(builder, subscriber)
|
||||
}
|
||||
}
|
||||
} // SPDX-SnippetEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,5 +10,9 @@ pub mod log;
|
|||
pub mod otel;
|
||||
pub mod stdout;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod store;
|
||||
// SPDX-SnippetEnd
|
||||
|
|
|
@ -646,12 +646,13 @@ impl ManageDirectory for Store {
|
|||
let mut batch = BatchBuilder::new();
|
||||
batch.with_account_id(u32::MAX);
|
||||
|
||||
let tenant = principal.tenant.as_ref().map(|t| t.to_native());
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Make sure tenant has no data
|
||||
let tenant = principal.tenant.as_ref().map(|t| t.to_native());
|
||||
#[cfg(feature = "enterprise")]
|
||||
match typ {
|
||||
Type::Individual | Type::Group => {
|
||||
|
|
|
@ -20,24 +20,20 @@ pub struct PrincipalInfo {
|
|||
pub tenant: Option<u32>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
impl PrincipalInfo {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub fn has_tenant_access(&self, tenant_id: Option<u32>) -> bool {
|
||||
tenant_id.is_none_or(|tenant_id| {
|
||||
self.tenant.is_some_and(|t| tenant_id == t)
|
||||
|| (self.typ == Type::Tenant && self.id == tenant_id)
|
||||
})
|
||||
}
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
impl PrincipalInfo {
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
pub fn has_tenant_access(&self, _tenant_id: Option<u32>) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
@ -91,6 +91,9 @@ impl Directories {
|
|||
|
||||
// Build directory
|
||||
if let Some(store) = store {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
if store.is_enterprise_directory() && !is_enterprise {
|
||||
let message =
|
||||
|
@ -98,6 +101,7 @@ impl Directories {
|
|||
config.new_parse_error(("directory", id, "type"), message);
|
||||
continue;
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
let directory = Arc::new(Directory {
|
||||
store,
|
||||
|
|
|
@ -75,11 +75,18 @@ impl Principal {
|
|||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub fn tenant(&self) -> Option<u32> {
|
||||
self.tenant
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
pub fn tenant(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
self.description.as_deref()
|
||||
}
|
||||
|
|
|
@ -507,6 +507,9 @@ enum Response {
|
|||
}
|
||||
|
||||
fn render_response(server: &Server, response: Response, language: &str) -> String {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let template = server
|
||||
.core
|
||||
|
@ -514,6 +517,8 @@ fn render_response(server: &Server, response: Response, language: &str) -> Strin
|
|||
.as_ref()
|
||||
.and_then(|e| e.template_scheduling_web.as_ref())
|
||||
.unwrap_or(&server.core.groupware.itip_template);
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let template = &server.core.groupware.itip_template;
|
||||
let locale = i18n::locale_or_default(language);
|
||||
|
|
|
@ -130,8 +130,13 @@ impl OAuthApiHandler for Server {
|
|||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let is_enterprise = false;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let is_enterprise = self.core.is_enterprise_edition();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
json!({
|
||||
"data": {
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
pub mod crypto;
|
||||
pub mod dkim;
|
||||
pub mod dns;
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod enterprise;
|
||||
pub mod log;
|
||||
pub mod principal;
|
||||
pub mod queue;
|
||||
|
@ -19,15 +17,23 @@ pub mod spam;
|
|||
pub mod stores;
|
||||
pub mod troubleshoot;
|
||||
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod enterprise;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use enterprise::telemetry::TelemetryApi;
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
use crate::auth::oauth::auth::OAuthApiHandler;
|
||||
use common::{Server, auth::AccessToken};
|
||||
use crypto::CryptoHandler;
|
||||
use directory::{Permission, backend::internal::manage};
|
||||
use dkim::DkimManagement;
|
||||
use dns::DnsManagement;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use enterprise::telemetry::TelemetryApi;
|
||||
use http_proto::{request::fetch_body, *};
|
||||
use hyper::{Method, StatusCode, header};
|
||||
use jmap::api::{ToJmapHttpResponse, ToRequestError};
|
||||
use jmap_proto::error::request::RequestError;
|
||||
|
@ -40,15 +46,12 @@ use report::ManageReports;
|
|||
use serde::Serialize;
|
||||
use settings::ManageSettings;
|
||||
use spam::ManageSpamHandler;
|
||||
use std::future::Future;
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
use store::write::now;
|
||||
use stores::ManageStore;
|
||||
use troubleshoot::TroubleshootApi;
|
||||
|
||||
use crate::auth::oauth::auth::OAuthApiHandler;
|
||||
|
||||
use http_proto::{request::fetch_body, *};
|
||||
use std::future::Future;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "error")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
|
@ -252,12 +252,11 @@ impl PrincipalManager for Server {
|
|||
})?;
|
||||
}
|
||||
|
||||
let mut tenant = access_token.tenant.map(|t| t.id);
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
let mut tenant = access_token.tenant.map(|t| t.id);
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.core.is_enterprise_edition() {
|
||||
if tenant.is_none() {
|
||||
|
@ -276,7 +275,6 @@ impl PrincipalManager for Server {
|
|||
} else if types.contains(&Type::Tenant) {
|
||||
return Err(manage::enterprise());
|
||||
}
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
let principals = self
|
||||
|
@ -347,6 +345,9 @@ impl PrincipalManager for Server {
|
|||
|
||||
let mut tenant = access_token.tenant.map(|t| t.id);
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.core.is_enterprise_edition() {
|
||||
if tenant.is_none() {
|
||||
|
@ -365,6 +366,7 @@ impl PrincipalManager for Server {
|
|||
} else if typ == Type::Tenant {
|
||||
return Err(manage::enterprise());
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
let principals = self
|
||||
.store()
|
||||
|
|
|
@ -137,13 +137,13 @@ impl QueueManagement for Server {
|
|||
access_token: &AccessToken,
|
||||
) -> trc::Result<HttpResponse> {
|
||||
let params = UrlParams::new(req.uri().query());
|
||||
let mut tenant_domains: Option<Vec<String>> = None;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Limit to tenant domains
|
||||
let mut tenant_domains: Option<Vec<String>> = None;
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.core.is_enterprise_edition() {
|
||||
if let Some(tenant) = access_token.tenant {
|
||||
|
|
|
@ -83,8 +83,13 @@ impl ManageReload for Server {
|
|||
|
||||
if let Some(tracers) = result.tracers {
|
||||
// Update tracers
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
tracers.update(self.inner.shared_core.load().is_enterprise_edition());
|
||||
// SPDX-SnippetEnd
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
tracers.update(false);
|
||||
}
|
||||
|
|
|
@ -46,12 +46,12 @@ impl ManageReports for Server {
|
|||
path: Vec<&str>,
|
||||
access_token: &AccessToken,
|
||||
) -> trc::Result<HttpResponse> {
|
||||
let mut tenant_domains: Option<Vec<String>> = None;
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Limit to tenant domains
|
||||
let mut tenant_domains: Option<Vec<String>> = None;
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.core.is_enterprise_edition() {
|
||||
if let Some(tenant) = access_token.tenant {
|
||||
|
|
|
@ -17,10 +17,12 @@ use directory::{
|
|||
backend::internal::manage::{self, ManageDirectory},
|
||||
};
|
||||
use email::message::{ingest::EmailIngest, metadata::MessageData};
|
||||
use http_proto::{request::decode_path_element, *};
|
||||
use hyper::Method;
|
||||
use jmap_proto::types::{collection::Collection, property::Property};
|
||||
use serde_json::json;
|
||||
use services::task_manager::fts::FtsIndexTask;
|
||||
use std::future::Future;
|
||||
use store::{
|
||||
Serialize, rand,
|
||||
write::{Archiver, BatchBuilder, ValueClass},
|
||||
|
@ -28,11 +30,12 @@ use store::{
|
|||
use trc::AddContext;
|
||||
use utils::url_params::UrlParams;
|
||||
|
||||
use http_proto::{request::decode_path_element, *};
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
use super::enterprise::undelete::UndeleteApi;
|
||||
use std::future::Future;
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
pub trait ManageStore: Sync + Send {
|
||||
fn handle_manage_store(
|
||||
|
|
|
@ -581,12 +581,11 @@ impl ParseHttp for Server {
|
|||
}
|
||||
_ => (),
|
||||
},
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
"logo.svg" if self.is_enterprise_edition() => {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
match self
|
||||
.logo_resource(
|
||||
req.headers()
|
||||
|
@ -611,9 +610,8 @@ impl ParseHttp for Server {
|
|||
if !resource.is_empty() {
|
||||
return Ok(resource.into_http_response());
|
||||
}
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
"form" => {
|
||||
if let Some(form) = &self.core.network.contact_form {
|
||||
match *req.method() {
|
||||
|
|
|
@ -65,4 +65,5 @@ enterprise = [ "jmap/enterprise",
|
|||
"http/enterprise",
|
||||
"dav/enterprise",
|
||||
"groupware/enterprise",
|
||||
"trc/enterprise",
|
||||
"services/enterprise" ]
|
||||
|
|
|
@ -50,9 +50,13 @@ async fn main() -> std::io::Result<()> {
|
|||
init.config.log_errors();
|
||||
init.config.log_warnings();
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
// Log licensing information
|
||||
#[cfg(feature = "enterprise")]
|
||||
init.inner.build_server().log_license_details();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
// Spawn servers
|
||||
let (shutdown_tx, shutdown_rx) = init.servers.spawn(|server, acceptor, shutdown_rx| {
|
||||
|
|
|
@ -4,31 +4,33 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::{
|
||||
collections::BinaryHeap,
|
||||
future::Future,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant, SystemTime},
|
||||
};
|
||||
|
||||
use common::{
|
||||
Inner, KV_LOCK_HOUSEKEEPER, LONG_1D_SLUMBER, Server,
|
||||
config::telemetry::OtelMetrics,
|
||||
core::BuildServer,
|
||||
ipc::{BroadcastEvent, HousekeeperEvent, PurgeType},
|
||||
};
|
||||
use email::message::delete::EmailDeletion;
|
||||
use smtp::reporting::SmtpReporting;
|
||||
use std::{
|
||||
collections::BinaryHeap,
|
||||
future::Future,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant, SystemTime},
|
||||
};
|
||||
use store::{PurgeStore, write::now};
|
||||
use tokio::sync::mpsc;
|
||||
use trc::{Collector, MetricType, PurgeEvent};
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
use common::telemetry::{
|
||||
metrics::store::{MetricsStore, SharedMetricHistory},
|
||||
tracers::store::TracingStore,
|
||||
};
|
||||
|
||||
use email::message::delete::EmailDeletion;
|
||||
use smtp::reporting::SmtpReporting;
|
||||
use store::{PurgeStore, write::now};
|
||||
use tokio::sync::mpsc;
|
||||
use trc::{Collector, MetricType, PurgeEvent};
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct Action {
|
||||
|
@ -42,13 +44,17 @@ enum ActionClass {
|
|||
Store(usize),
|
||||
Acme(String),
|
||||
OtelMetrics,
|
||||
CalculateMetrics,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InternalMetrics,
|
||||
CalculateMetrics,
|
||||
#[cfg(feature = "enterprise")]
|
||||
AlertMetrics,
|
||||
#[cfg(feature = "enterprise")]
|
||||
RenewLicense,
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -56,8 +62,12 @@ struct Queue {
|
|||
heap: BinaryHeap<Action>,
|
||||
}
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
const METRIC_ALERTS_INTERVAL: Duration = Duration::from_secs(5 * 60);
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
pub fn spawn_housekeeper(inner: Arc<Inner>, mut rx: mpsc::Receiver<HousekeeperEvent>) {
|
||||
tokio::spawn(async move {
|
||||
|
@ -143,12 +153,18 @@ pub fn spawn_housekeeper(inner: Arc<Inner>, mut rx: mpsc::Receiver<HousekeeperEv
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
// Metrics history
|
||||
#[cfg(feature = "enterprise")]
|
||||
let metrics_history = SharedMetricHistory::default();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
let mut next_metric_update = Instant::now();
|
||||
|
||||
loop {
|
||||
|
@ -383,8 +399,12 @@ pub fn spawn_housekeeper(inner: Arc<Inner>, mut rx: mpsc::Receiver<HousekeeperEv
|
|||
|
||||
let otel = otel.clone();
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let is_enterprise = server.is_enterprise_edition();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let is_enterprise = false;
|
||||
|
@ -417,6 +437,9 @@ pub fn spawn_housekeeper(inner: Arc<Inner>, mut rx: mpsc::Receiver<HousekeeperEv
|
|||
let server = server.clone();
|
||||
tokio::spawn(async move {
|
||||
if server.core.network.roles.calculate_metrics {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
if server.is_enterprise_edition() {
|
||||
// Obtain queue size
|
||||
|
@ -434,6 +457,7 @@ pub fn spawn_housekeeper(inner: Arc<Inner>, mut rx: mpsc::Receiver<HousekeeperEv
|
|||
}
|
||||
}
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
if update_other_metrics {
|
||||
match server.total_accounts().await {
|
||||
|
|
|
@ -431,6 +431,9 @@ async fn build_template(
|
|||
access_token.emails.first().unwrap().to_string()
|
||||
};
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let template = server
|
||||
.core
|
||||
|
@ -438,6 +441,8 @@ async fn build_template(
|
|||
.as_ref()
|
||||
.and_then(|e| e.template_calendar_alarm.as_ref())
|
||||
.unwrap_or(&server.core.groupware.alarms_template);
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let template = &server.core.groupware.alarms_template;
|
||||
let locale = i18n::locale_or_default(access_token.locale.as_deref().unwrap_or("en"));
|
||||
|
|
|
@ -310,6 +310,9 @@ pub async fn build_itip_template(
|
|||
summary: &ArchivedItipSummary,
|
||||
logo_cid: &str,
|
||||
) -> Details {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let template = server
|
||||
.core
|
||||
|
@ -317,6 +320,7 @@ pub async fn build_itip_template(
|
|||
.as_ref()
|
||||
.and_then(|e| e.template_scheduling_email.as_ref())
|
||||
.unwrap_or(&server.core.groupware.itip_template);
|
||||
// SPDX-SnippetEnd
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let template = &server.core.groupware.itip_template;
|
||||
let locale = i18n::locale_or_default(access_token.locale.as_deref().unwrap_or("en"));
|
||||
|
|
|
@ -27,8 +27,6 @@ pub mod headers;
|
|||
pub mod html;
|
||||
pub mod init;
|
||||
pub mod ip;
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod llm;
|
||||
pub mod messageid;
|
||||
pub mod mime;
|
||||
pub mod pyzor;
|
||||
|
@ -42,6 +40,13 @@ pub mod subject;
|
|||
pub mod trusted_reply;
|
||||
pub mod url;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod llm;
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
impl SpamFilterInput<'_> {
|
||||
pub fn header_as_address(&self, header: &Header<'_>) -> Option<Cow<'_, str>> {
|
||||
self.message
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use common::{Server, config::spamfilter::SpamFilterAction};
|
||||
use std::{fmt::Write, future::Future, vec};
|
||||
|
||||
use crate::{
|
||||
SpamFilterContext,
|
||||
analysis::{
|
||||
|
@ -22,9 +19,15 @@ use crate::{
|
|||
},
|
||||
modules::bayes::BayesClassifier,
|
||||
};
|
||||
use common::{Server, config::spamfilter::SpamFilterAction};
|
||||
use std::{fmt::Write, future::Future, vec};
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::analysis::llm::SpamFilterAnalyzeLlm;
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
pub trait SpamFilterAnalyzeScore: Sync + Send {
|
||||
fn spam_filter_score(
|
||||
|
@ -190,10 +193,16 @@ impl SpamFilterAnalyzeScore for Server {
|
|||
// HTML content analysis
|
||||
self.spam_filter_analyze_html(ctx).await;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// LLM classification
|
||||
#[cfg(feature = "enterprise")]
|
||||
self.spam_filter_analyze_llm(ctx).await;
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
// Trusted reply analysis
|
||||
self.spam_filter_analyze_reply_in(ctx).await;
|
||||
|
||||
|
|
|
@ -71,11 +71,15 @@ impl ShardedBlob {
|
|||
Store::MySQL(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Store::RocksDb(store) => store.get_blob(key, read_range).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(
|
||||
feature = "enterprise",
|
||||
any(feature = "postgres", feature = "mysql")
|
||||
))]
|
||||
Store::SQLReadReplica(store) => store.get_blob(key, read_range).await,
|
||||
// SPDX-SnippetEnd
|
||||
Store::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
},
|
||||
BlobBackend::Fs(store) => store.get_blob(key, read_range).await,
|
||||
|
@ -103,10 +107,14 @@ impl ShardedBlob {
|
|||
Store::MySQL(store) => store.put_blob(key, data).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Store::RocksDb(store) => store.put_blob(key, data).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(
|
||||
feature = "enterprise",
|
||||
any(feature = "postgres", feature = "mysql")
|
||||
))]
|
||||
// SPDX-SnippetEnd
|
||||
Store::SQLReadReplica(store) => store.put_blob(key, data).await,
|
||||
Store::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
},
|
||||
|
@ -135,11 +143,15 @@ impl ShardedBlob {
|
|||
Store::MySQL(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Store::RocksDb(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(
|
||||
feature = "enterprise",
|
||||
any(feature = "postgres", feature = "mysql")
|
||||
))]
|
||||
Store::SQLReadReplica(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
Store::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
},
|
||||
BlobBackend::Fs(store) => store.delete_blob(key).await,
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#[cfg(feature = "azure")]
|
||||
pub mod azure;
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod composite;
|
||||
#[cfg(feature = "elastic")]
|
||||
pub mod elastic;
|
||||
#[cfg(feature = "foundation")]
|
||||
|
@ -34,6 +32,13 @@ pub mod sqlite;
|
|||
#[cfg(feature = "zenoh")]
|
||||
pub mod zenoh;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod composite;
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
pub const MAX_TOKEN_LENGTH: usize = (u8::MAX >> 1) as usize;
|
||||
pub const MAX_TOKEN_MASK: usize = MAX_TOKEN_LENGTH - 1;
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ use crate::{
|
|||
};
|
||||
use utils::config::{Config, cron::SimpleCron, utils::ParseValue};
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
enum CompositeStore {
|
||||
#[cfg(any(feature = "postgres", feature = "mysql"))]
|
||||
|
@ -17,6 +20,7 @@ enum CompositeStore {
|
|||
ShardedBlob(String),
|
||||
ShardedInMemory(String),
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
impl Stores {
|
||||
pub async fn parse_all(config: &mut Config, is_reload: bool) -> Self {
|
||||
|
@ -33,8 +37,13 @@ impl Stores {
|
|||
|
||||
pub async fn parse_stores(&mut self, config: &mut Config) {
|
||||
let is_reload = !self.stores.is_empty();
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
let mut composite_stores = Vec::new();
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
for store_id in config.sub_keys("store", ".type") {
|
||||
let id = store_id.as_str();
|
||||
|
@ -239,6 +248,9 @@ impl Stores {
|
|||
.insert(store_id, crate::PubSubStore::Kafka(db));
|
||||
}
|
||||
}
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
"sql-read-replica" => {
|
||||
#[cfg(any(feature = "postgres", feature = "mysql"))]
|
||||
|
@ -252,6 +264,7 @@ impl Stores {
|
|||
"sharded-in-memory" => {
|
||||
composite_stores.push(CompositeStore::ShardedInMemory(store_id));
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
#[cfg(feature = "azure")]
|
||||
"azure" => {
|
||||
if let Some(db) = crate::backend::azure::AzureStore::open(config, prefix)
|
||||
|
@ -271,6 +284,9 @@ impl Stores {
|
|||
}
|
||||
}
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
for composite_store in composite_stores {
|
||||
match composite_store {
|
||||
|
@ -332,6 +348,8 @@ impl Stores {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
pub async fn parse_in_memory(&mut self, config: &mut Config, is_reload: bool) {
|
||||
|
|
|
@ -30,8 +30,12 @@ impl BlobStore {
|
|||
Store::MySQL(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Store::RocksDb(store) => store.get_blob(key, read_range).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Store::SQLReadReplica(store) => store.get_blob(key, read_range).await,
|
||||
// SPDX-SnippetEnd
|
||||
Store::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
},
|
||||
BlobBackend::Fs(store) => store.get_blob(key, read_range).await,
|
||||
|
@ -39,8 +43,12 @@ impl BlobStore {
|
|||
BlobBackend::S3(store) => store.get_blob(key, read_range).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.get_blob(key, read_range).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
BlobBackend::Sharded(store) => store.get_blob(key, read_range).await,
|
||||
// SPDX-SnippetEnd
|
||||
};
|
||||
|
||||
trc::event!(
|
||||
|
@ -112,8 +120,12 @@ impl BlobStore {
|
|||
Store::MySQL(store) => store.put_blob(key, data.as_ref()).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Store::RocksDb(store) => store.put_blob(key, data.as_ref()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Store::SQLReadReplica(store) => store.put_blob(key, data.as_ref()).await,
|
||||
// SPDX-SnippetEnd
|
||||
Store::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
},
|
||||
BlobBackend::Fs(store) => store.put_blob(key, data.as_ref()).await,
|
||||
|
@ -121,8 +133,12 @@ impl BlobStore {
|
|||
BlobBackend::S3(store) => store.put_blob(key, data.as_ref()).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.put_blob(key, data.as_ref()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
BlobBackend::Sharded(store) => store.put_blob(key, data.as_ref()).await,
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
.caused_by(trc::location!());
|
||||
|
||||
|
@ -150,8 +166,12 @@ impl BlobStore {
|
|||
Store::MySQL(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Store::RocksDb(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Store::SQLReadReplica(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
Store::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
},
|
||||
BlobBackend::Fs(store) => store.delete_blob(key).await,
|
||||
|
@ -159,8 +179,12 @@ impl BlobStore {
|
|||
BlobBackend::S3(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "azure")]
|
||||
BlobBackend::Azure(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
BlobBackend::Sharded(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
.caused_by(trc::location!());
|
||||
|
||||
|
|
|
@ -49,8 +49,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_set(&kv.key, &kv.value, kv.expires).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.key_set(kv).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -97,8 +101,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_incr(&kv.key, kv.value, kv.expires).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.counter_incr(kv).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -118,8 +126,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_delete(key.into().as_bytes()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.key_delete(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -139,8 +151,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_delete(key.into().as_bytes()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.counter_delete(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -180,8 +196,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_delete_prefix(prefix).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.key_delete_prefix(prefix).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -202,8 +222,12 @@ impl InMemoryStore {
|
|||
.map(|value| value.and_then(|v| v.into())),
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_get(key.into().as_bytes()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.key_get(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(store) => Ok(store
|
||||
.get(key.into().as_str())
|
||||
.map(|value| T::from(value.clone()))),
|
||||
|
@ -225,8 +249,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.counter_get(key.into().as_bytes()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.counter_get(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -244,8 +272,12 @@ impl InMemoryStore {
|
|||
.map(|value| matches!(value, Some(LookupValue::Value(())))),
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(store) => store.key_exists(key.into().as_bytes()).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store.key_exists(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(store) => Ok(store.get(key.into().as_str()).is_some()),
|
||||
InMemoryStore::Http(store) => Ok(store.contains(key.into().as_str())),
|
||||
}
|
||||
|
@ -345,11 +377,15 @@ impl InMemoryStore {
|
|||
.key_incr(&KeyValue::<()>::build_key(prefix, key), 1, duration.into())
|
||||
.await
|
||||
.map(|count| count == 1),
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(store) => store
|
||||
.counter_incr(KeyValue::with_prefix(prefix, key, 1).expires(duration))
|
||||
.await
|
||||
.map(|count| count == 1),
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {
|
||||
Err(trc::StoreEvent::NotSupported.into_err())
|
||||
}
|
||||
|
@ -443,8 +479,12 @@ impl InMemoryStore {
|
|||
}
|
||||
#[cfg(feature = "redis")]
|
||||
InMemoryStore::Redis(_) => {}
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
InMemoryStore::Sharded(_) => {}
|
||||
// SPDX-SnippetEnd
|
||||
InMemoryStore::Static(_) | InMemoryStore::Http(_) => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,12 @@ impl Store {
|
|||
Self::MySQL(_) => "mysql",
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(_) => "rocksdb",
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(_) => "read_replica",
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => "none",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,8 +53,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.get_value(key).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.get_value(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.get_value(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -75,8 +79,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.get_bitmap(key).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.get_bitmap(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.get_bitmap(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -121,8 +129,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.iterate(params, cb).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.iterate(params, cb).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.iterate(params, cb).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!());
|
||||
|
@ -150,8 +162,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.get_counter(key).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.get_counter(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.get_counter(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -199,8 +215,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.write(batch).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.write(batch).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.write(batch).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
};
|
||||
|
||||
|
@ -275,8 +295,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.purge_store().await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.purge_store().await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.purge_store().await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -294,8 +318,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.delete_range(from, to).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.delete_range(from, to).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.delete_range(from, to).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -450,8 +478,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.get_blob(key, range).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.get_blob(key, range).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.get_blob(key, range).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -469,8 +501,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.put_blob(key, data).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.put_blob(key, data).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.put_blob(key, data).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
@ -488,8 +524,12 @@ impl Store {
|
|||
Self::MySQL(store) => store.delete_blob(key).await,
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(store) => store.delete_blob(key).await,
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => Err(trc::StoreEvent::NotConfigured.into()),
|
||||
}
|
||||
.caused_by(trc::location!())
|
||||
|
|
|
@ -173,8 +173,12 @@ pub enum Store {
|
|||
MySQL(Arc<backend::mysql::MysqlStore>),
|
||||
#[cfg(feature = "rocks")]
|
||||
RocksDb(Arc<backend::rocksdb::RocksDbStore>),
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
SQLReadReplica(Arc<backend::composite::read_replica::SQLReadReplica>),
|
||||
// SPDX-SnippetEnd
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
@ -199,8 +203,12 @@ pub enum BlobBackend {
|
|||
S3(Arc<backend::s3::S3Store>),
|
||||
#[cfg(feature = "azure")]
|
||||
Azure(Arc<backend::azure::AzureStore>),
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
Sharded(Arc<backend::composite::sharded_blob::ShardedBlob>),
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -217,8 +225,12 @@ pub enum InMemoryStore {
|
|||
Redis(Arc<backend::redis::RedisStore>),
|
||||
Http(Arc<HttpStore>),
|
||||
Static(Arc<StaticMemoryStore>),
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
Sharded(Arc<backend::composite::sharded_lookup::ShardedInMemory>),
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -706,8 +718,12 @@ impl Store {
|
|||
Store::PostgreSQL(_) => true,
|
||||
#[cfg(feature = "mysql")]
|
||||
Store::MySQL(_) => true,
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Store::SQLReadReplica(_) => true,
|
||||
// SPDX-SnippetEnd
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -722,6 +738,9 @@ impl Store {
|
|||
}
|
||||
}
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub fn is_enterprise_store(&self) -> bool {
|
||||
match self {
|
||||
|
@ -730,6 +749,7 @@ impl Store {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
pub fn is_enterprise_store(&self) -> bool {
|
||||
|
@ -750,8 +770,13 @@ impl std::fmt::Debug for Store {
|
|||
Self::MySQL(_) => f.debug_tuple("MySQL").finish(),
|
||||
#[cfg(feature = "rocks")]
|
||||
Self::RocksDb(_) => f.debug_tuple("RocksDb").finish(),
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(all(feature = "enterprise", any(feature = "postgres", feature = "mysql")))]
|
||||
Self::SQLReadReplica(_) => f.debug_tuple("SQLReadReplica").finish(),
|
||||
// SPDX-SnippetEnd
|
||||
Self::None => f.debug_tuple("None").finish(),
|
||||
}
|
||||
}
|
||||
|
@ -781,6 +806,9 @@ impl From<Value<'static>> for () {
|
|||
|
||||
impl Stores {
|
||||
pub fn disable_enterprise_only(&mut self) {
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
{
|
||||
#[cfg(any(feature = "postgres", feature = "mysql"))]
|
||||
|
@ -789,5 +817,6 @@ impl Stores {
|
|||
self.blob_stores
|
||||
.retain(|_, store| !matches!(store.backend, BlobBackend::Sharded(_)));
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@ compact_str = "0.9.0"
|
|||
|
||||
[features]
|
||||
test_mode = []
|
||||
enterprise = []
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use compact_str::format_compact;
|
||||
|
||||
use crate::*;
|
||||
use compact_str::format_compact;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
const VERSION: u8 = 1;
|
||||
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
pub mod binary;
|
||||
pub mod json;
|
||||
pub mod text;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod binary;
|
||||
// SPDX-SnippetEnd
|
||||
|
|
265
resources/scripts/ossify.py
Normal file
265
resources/scripts/ossify.py
Normal file
|
@ -0,0 +1,265 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Stalwart SEL code remover
|
||||
|
||||
This script removes SEL code from the Stalwart codebase by:
|
||||
1. Removing entire .rs files that contain "SPDX-License-Identifier: LicenseRef-SEL" in their first comment
|
||||
2. Removing SEL snippets marked with SPDX-SnippetBegin/End from mixed files
|
||||
|
||||
Usage: python ossify.py <stalwart_repository>/crates
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
|
||||
def find_first_comment_block(content: str) -> Optional[str]:
|
||||
"""
|
||||
Find the first comment block in a Rust file.
|
||||
Returns the comment content or None if no comment block is found.
|
||||
"""
|
||||
# Remove leading whitespace and find the first comment
|
||||
lines = content.strip().split('\n')
|
||||
|
||||
if not lines:
|
||||
return None
|
||||
|
||||
first_line = lines[0].strip()
|
||||
|
||||
# Check for block comment starting with /*
|
||||
if first_line.startswith('/*'):
|
||||
comment_lines = []
|
||||
in_comment = True
|
||||
|
||||
for line in lines:
|
||||
if in_comment:
|
||||
comment_lines.append(line)
|
||||
if '*/' in line:
|
||||
break
|
||||
|
||||
return '\n'.join(comment_lines)
|
||||
|
||||
# Check for line comments starting with //
|
||||
elif first_line.startswith('//'):
|
||||
comment_lines = []
|
||||
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('//'):
|
||||
comment_lines.append(line)
|
||||
elif stripped == '':
|
||||
comment_lines.append(line) # Keep empty lines within comment block
|
||||
else:
|
||||
break # Stop at first non-comment, non-empty line
|
||||
|
||||
return '\n'.join(comment_lines)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def should_remove_file(file_path: str) -> bool:
|
||||
"""
|
||||
Check if a .rs file should be completely removed based on its first comment.
|
||||
Returns True if the file contains "SPDX-License-Identifier: LicenseRef-SEL" in the first comment.
|
||||
"""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
first_comment = find_first_comment_block(content)
|
||||
if first_comment and 'SPDX-License-Identifier: LicenseRef-SEL' in first_comment:
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error reading file {file_path}: {e}")
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def remove_proprietary_snippets(content: str) -> Tuple[str, int]:
|
||||
"""
|
||||
Remove proprietary snippets from file content.
|
||||
Returns tuple of (modified_content, number_of_snippets_removed)
|
||||
"""
|
||||
snippets_removed = 0
|
||||
|
||||
# Pattern to match SPDX snippets that contain LicenseRef-SEL
|
||||
# We look for SPDX-SnippetBegin, then check if the snippet contains LicenseRef-SEL,
|
||||
# and if so, remove everything until SPDX-SnippetEnd
|
||||
|
||||
lines = content.split('\n')
|
||||
result_lines = []
|
||||
i = 0
|
||||
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
|
||||
# Check if this line starts a snippet
|
||||
if '// SPDX-SnippetBegin' in line:
|
||||
# Look ahead to see if this snippet contains LicenseRef-SEL
|
||||
snippet_start = i
|
||||
snippet_lines = []
|
||||
j = i
|
||||
|
||||
# Collect the snippet lines until we find SnippetEnd or reach end of file
|
||||
while j < len(lines):
|
||||
snippet_lines.append(lines[j])
|
||||
if '// SPDX-SnippetEnd' in lines[j]:
|
||||
break
|
||||
j += 1
|
||||
|
||||
# Check if this snippet contains LicenseRef-SEL
|
||||
snippet_content = '\n'.join(snippet_lines)
|
||||
if 'SPDX-License-Identifier: LicenseRef-SEL' in snippet_content:
|
||||
# Remove this snippet
|
||||
snippets_removed += 1
|
||||
i = j + 1 # Skip past the SnippetEnd line
|
||||
continue
|
||||
else:
|
||||
# Keep this snippet as it's not proprietary
|
||||
result_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
result_lines.append(line)
|
||||
i += 1
|
||||
|
||||
return '\n'.join(result_lines), snippets_removed
|
||||
|
||||
|
||||
def process_rust_file(file_path: str, dry_run: bool = False) -> dict:
|
||||
"""
|
||||
Process a single Rust file, removing proprietary content.
|
||||
Returns a dictionary with processing results.
|
||||
"""
|
||||
result = {
|
||||
'file': file_path,
|
||||
'action': 'none',
|
||||
'snippets_removed': 0,
|
||||
'error': None
|
||||
}
|
||||
|
||||
try:
|
||||
# Check if the entire file should be removed
|
||||
if should_remove_file(file_path):
|
||||
result['action'] = 'file_removed'
|
||||
if not dry_run:
|
||||
os.remove(file_path)
|
||||
return result
|
||||
|
||||
# Process snippets in the file
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
original_content = f.read()
|
||||
|
||||
modified_content, snippets_removed = remove_proprietary_snippets(original_content)
|
||||
|
||||
if snippets_removed > 0:
|
||||
result['action'] = 'snippets_removed'
|
||||
result['snippets_removed'] = snippets_removed
|
||||
|
||||
if not dry_run:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(modified_content)
|
||||
|
||||
except Exception as e:
|
||||
result['error'] = str(e)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def find_rust_files(directory: str) -> List[str]:
|
||||
"""Find all .rs files in the given directory recursively."""
|
||||
rust_files = []
|
||||
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for file in files:
|
||||
if file.endswith('.rs'):
|
||||
rust_files.append(os.path.join(root, file))
|
||||
|
||||
return rust_files
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Remove Enterprise licensed code from Stalwart codebase'
|
||||
)
|
||||
parser.add_argument(
|
||||
'directory',
|
||||
help='Directory containing Stalwart code to process'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--dry-run',
|
||||
action='store_true',
|
||||
help='Show what would be done without making changes'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
help='Show detailed output for each file'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.isdir(args.directory):
|
||||
print(f"Error: {args.directory} is not a valid directory")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Processing Rust files in: {args.directory}")
|
||||
if args.dry_run:
|
||||
print("DRY RUN MODE - No changes will be made")
|
||||
print()
|
||||
|
||||
rust_files = find_rust_files(args.directory)
|
||||
|
||||
if not rust_files:
|
||||
print("No .rs files found in the specified directory")
|
||||
return
|
||||
|
||||
print(f"Found {len(rust_files)} Rust files")
|
||||
print()
|
||||
|
||||
files_removed = 0
|
||||
files_with_snippets_removed = 0
|
||||
total_snippets_removed = 0
|
||||
errors = []
|
||||
|
||||
for file_path in rust_files:
|
||||
result = process_rust_file(file_path, args.dry_run)
|
||||
|
||||
if result['error']:
|
||||
errors.append(f"{file_path}: {result['error']}")
|
||||
continue
|
||||
|
||||
if result['action'] == 'file_removed':
|
||||
files_removed += 1
|
||||
if args.verbose or args.dry_run:
|
||||
action_text = "Would remove" if args.dry_run else "Removed"
|
||||
print(f"{action_text} file: {file_path}")
|
||||
|
||||
elif result['action'] == 'snippets_removed':
|
||||
files_with_snippets_removed += 1
|
||||
total_snippets_removed += result['snippets_removed']
|
||||
if args.verbose or args.dry_run:
|
||||
action_text = "Would remove" if args.dry_run else "Removed"
|
||||
print(f"{action_text} {result['snippets_removed']} snippet(s) from: {file_path}")
|
||||
|
||||
# Summary
|
||||
print("\nSummary:")
|
||||
action_text = "Would be" if args.dry_run else "Were"
|
||||
print(f"- {files_removed} files {action_text.lower()} completely removed")
|
||||
print(f"- {total_snippets_removed} proprietary snippets {action_text.lower()} removed from {files_with_snippets_removed} files")
|
||||
|
||||
if errors:
|
||||
print(f"- {len(errors)} errors occurred:")
|
||||
for error in errors:
|
||||
print(f" {error}")
|
||||
|
||||
if args.dry_run:
|
||||
print("\nRun without --dry-run to apply changes")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -40,7 +40,7 @@ common = { path = "../crates/common", features = ["test_mode", "enterprise"] }
|
|||
email = { path = "../crates/email", features = ["test_mode", "enterprise"] }
|
||||
spam-filter = { path = "../crates/spam-filter", features = ["test_mode", "enterprise"] }
|
||||
migration = { path = "../crates/migration", features = ["test_mode", "enterprise"] }
|
||||
trc = { path = "../crates/trc" }
|
||||
trc = { path = "../crates/trc", features = ["enterprise"] }
|
||||
managesieve = { path = "../crates/managesieve", features = ["test_mode", "enterprise"] }
|
||||
smtp-proto = { version = "0.1" }
|
||||
mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
|
||||
|
|
Loading…
Add table
Reference in a new issue