mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2025-12-09 12:55:57 +08:00
Partial rollback of CompactString after benchmarking (or 'premature optimization is the root of all evil')
This commit is contained in:
parent
d6dc6ee8c5
commit
c5596fb656
189 changed files with 1318 additions and 1332 deletions
|
|
@ -4,10 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use compact_str::CompactString;
|
||||
use directory::{Directory, backend::RcptType};
|
||||
use std::borrow::Cow;
|
||||
use utils::config::{Config, utils::AsKey};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -100,7 +98,7 @@ impl Server {
|
|||
directory: &Directory,
|
||||
address: &str,
|
||||
session_id: u64,
|
||||
) -> trc::Result<Vec<CompactString>> {
|
||||
) -> trc::Result<Vec<String>> {
|
||||
directory
|
||||
.vrfy(
|
||||
self.core
|
||||
|
|
@ -120,7 +118,7 @@ impl Server {
|
|||
directory: &Directory,
|
||||
address: &str,
|
||||
session_id: u64,
|
||||
) -> trc::Result<Vec<CompactString>> {
|
||||
) -> trc::Result<Vec<String>> {
|
||||
directory
|
||||
.expn(
|
||||
self.core
|
||||
|
|
@ -196,7 +194,7 @@ impl AddressMapping {
|
|||
}
|
||||
AddressMapping::Custom(if_block) => {
|
||||
if let Some(result) = core
|
||||
.eval_if::<CompactString, _>(if_block, &Address(address), session_id)
|
||||
.eval_if::<String, _>(if_block, &Address(address), session_id)
|
||||
.await
|
||||
{
|
||||
return result.into();
|
||||
|
|
@ -220,9 +218,9 @@ impl AddressMapping {
|
|||
.map(|(_, domain_part)| format!("@{}", domain_part))
|
||||
.map(Cow::Owned),
|
||||
AddressMapping::Custom(if_block) => core
|
||||
.eval_if::<CompactString, _>(if_block, &Address(address), session_id)
|
||||
.eval_if::<String, _>(if_block, &Address(address), session_id)
|
||||
.await
|
||||
.map(|s| Cow::Owned(s.into())),
|
||||
.map(Cow::Owned),
|
||||
AddressMapping::Disable => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use std::{net::IpAddr, sync::Arc};
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::{
|
||||
Directory, Permission, Permissions, Principal, QueryBy, core::secret::verify_secret_hash,
|
||||
};
|
||||
|
|
@ -31,9 +31,9 @@ pub struct AccessToken {
|
|||
pub primary_id: u32,
|
||||
pub member_of: Vec<u32>,
|
||||
pub access_to: VecMap<u32, Bitmap<Collection>>,
|
||||
pub name: CompactString,
|
||||
pub description: Option<CompactString>,
|
||||
pub emails: Vec<CompactString>,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub emails: Vec<String>,
|
||||
pub quota: u64,
|
||||
pub permissions: Permissions,
|
||||
pub tenant: Option<TenantInfo>,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use trc::{AddContext, AuthEvent, EventType};
|
||||
|
||||
|
|
@ -17,19 +17,19 @@ pub struct OAuthIntrospect {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub scope: Option<CompactString>,
|
||||
pub scope: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_id: Option<CompactString>,
|
||||
pub client_id: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub username: Option<CompactString>,
|
||||
pub username: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub token_type: Option<CompactString>,
|
||||
pub token_type: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -45,7 +45,7 @@ pub struct OAuthIntrospect {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sub: Option<CompactString>,
|
||||
pub sub: Option<String>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use biscuit::{ClaimsSet, JWT, RegisteredClaims, SingleOrMultiple, jws::RegisteredHeader};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize,
|
||||
de::{self, Visitor},
|
||||
|
|
@ -20,47 +20,47 @@ use crate::Server;
|
|||
pub struct Userinfo {
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sub: Option<CompactString>,
|
||||
pub sub: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<CompactString>,
|
||||
pub name: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub given_name: Option<CompactString>,
|
||||
pub given_name: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub family_name: Option<CompactString>,
|
||||
pub family_name: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub middle_name: Option<CompactString>,
|
||||
pub middle_name: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub nickname: Option<CompactString>,
|
||||
pub nickname: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preferred_username: Option<CompactString>,
|
||||
pub preferred_username: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub profile: Option<CompactString>,
|
||||
pub profile: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub picture: Option<CompactString>,
|
||||
pub picture: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub website: Option<CompactString>,
|
||||
pub website: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub email: Option<CompactString>,
|
||||
pub email: Option<String>,
|
||||
|
||||
#[serde(default, deserialize_with = "any_bool")]
|
||||
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
||||
|
|
@ -68,11 +68,11 @@ pub struct Userinfo {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub zoneinfo: Option<CompactString>,
|
||||
pub zoneinfo: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub locale: Option<CompactString>,
|
||||
pub locale: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -83,15 +83,15 @@ pub struct Userinfo {
|
|||
pub struct StandardClaims {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub nonce: Option<CompactString>,
|
||||
pub nonce: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub preferred_username: Option<CompactString>,
|
||||
pub preferred_username: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub email: Option<CompactString>,
|
||||
pub email: Option<String>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
|
|
|
|||
|
|
@ -4,22 +4,22 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct ClientRegistrationRequest {
|
||||
pub redirect_uris: Vec<CompactString>,
|
||||
pub redirect_uris: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub response_types: Vec<CompactString>,
|
||||
pub response_types: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub grant_types: Vec<CompactString>,
|
||||
pub grant_types: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -27,31 +27,31 @@ pub struct ClientRegistrationRequest {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub contacts: Vec<CompactString>,
|
||||
pub contacts: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_name: Option<CompactString>,
|
||||
pub client_name: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub logo_uri: Option<CompactString>,
|
||||
pub logo_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_uri: Option<CompactString>,
|
||||
pub client_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub policy_uri: Option<CompactString>,
|
||||
pub policy_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tos_uri: Option<CompactString>,
|
||||
pub tos_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub jwks_uri: Option<CompactString>,
|
||||
pub jwks_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -59,7 +59,7 @@ pub struct ClientRegistrationRequest {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sector_identifier_uri: Option<CompactString>,
|
||||
pub sector_identifier_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -67,39 +67,39 @@ pub struct ClientRegistrationRequest {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id_token_signed_response_alg: Option<CompactString>,
|
||||
pub id_token_signed_response_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id_token_encrypted_response_alg: Option<CompactString>,
|
||||
pub id_token_encrypted_response_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id_token_encrypted_response_enc: Option<CompactString>,
|
||||
pub id_token_encrypted_response_enc: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub userinfo_signed_response_alg: Option<CompactString>,
|
||||
pub userinfo_signed_response_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub userinfo_encrypted_response_alg: Option<CompactString>,
|
||||
pub userinfo_encrypted_response_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub userinfo_encrypted_response_enc: Option<CompactString>,
|
||||
pub userinfo_encrypted_response_enc: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub request_object_signing_alg: Option<CompactString>,
|
||||
pub request_object_signing_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub request_object_encryption_alg: Option<CompactString>,
|
||||
pub request_object_encryption_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub request_object_encryption_enc: Option<CompactString>,
|
||||
pub request_object_encryption_enc: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -107,7 +107,7 @@ pub struct ClientRegistrationRequest {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub token_endpoint_auth_signing_alg: Option<CompactString>,
|
||||
pub token_endpoint_auth_signing_alg: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -119,34 +119,34 @@ pub struct ClientRegistrationRequest {
|
|||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub default_acr_values: Vec<CompactString>,
|
||||
pub default_acr_values: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub initiate_login_uri: Option<CompactString>,
|
||||
pub initiate_login_uri: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub request_uris: Vec<CompactString>,
|
||||
pub request_uris: Vec<String>,
|
||||
|
||||
#[serde(flatten)]
|
||||
#[serde(skip_serializing_if = "HashMap::is_empty")]
|
||||
pub additional_fields: HashMap<CompactString, serde_json::Value>,
|
||||
pub additional_fields: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct ClientRegistrationResponse {
|
||||
// Required fields
|
||||
pub client_id: CompactString,
|
||||
pub client_id: String,
|
||||
|
||||
// Optional fields specific to the response
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_secret: Option<CompactString>,
|
||||
pub client_secret: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub registration_access_token: Option<CompactString>,
|
||||
pub registration_access_token: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub registration_client_uri: Option<CompactString>,
|
||||
pub registration_client_uri: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_id_issued_at: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use std::time::SystemTime;
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::QueryBy;
|
||||
use mail_builder::encoders::base64::base64_encode;
|
||||
use mail_parser::decoders::base64::base64_decode;
|
||||
|
|
@ -24,7 +24,7 @@ use super::{CLIENT_ID_MAX_LEN, GrantType, RANDOM_CODE_LEN, crypto::SymmetricEncr
|
|||
pub struct TokenInfo {
|
||||
pub grant_type: GrantType,
|
||||
pub account_id: u32,
|
||||
pub client_id: CompactString,
|
||||
pub client_id: String,
|
||||
pub expiry: u64,
|
||||
pub issued_at: u64,
|
||||
pub expires_in: u64,
|
||||
|
|
@ -128,7 +128,7 @@ impl Server {
|
|||
GrantType::from_id(bytes.next().copied()?)?,
|
||||
bytes.next_leb128::<u64>()?,
|
||||
bytes.next_leb128::<u64>()?,
|
||||
bytes.copied().map(char::from).collect::<CompactString>(),
|
||||
bytes.copied().map(char::from).collect::<String>(),
|
||||
)
|
||||
.into()
|
||||
})
|
||||
|
|
@ -216,7 +216,7 @@ impl Server {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn password_hash(&self, account_id: u32) -> trc::Result<CompactString> {
|
||||
pub async fn password_hash(&self, account_id: u32) -> trc::Result<String> {
|
||||
if account_id != u32::MAX {
|
||||
self.core
|
||||
.storage
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::time::Duration;
|
|||
|
||||
use crate::expr::{if_block::IfBlock, tokenizer::TokenMap};
|
||||
use ahash::AHashSet;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use utils::config::{Config, Rate};
|
||||
|
||||
use super::*;
|
||||
|
|
@ -17,8 +17,8 @@ use super::*;
|
|||
pub struct Network {
|
||||
pub node_id: u64,
|
||||
pub roles: ClusterRoles,
|
||||
pub server_name: CompactString,
|
||||
pub report_domain: CompactString,
|
||||
pub server_name: String,
|
||||
pub report_domain: String,
|
||||
pub security: Security,
|
||||
pub contact_form: Option<ContactForm>,
|
||||
pub http_response_url: IfBlock,
|
||||
|
|
@ -28,14 +28,14 @@ pub struct Network {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct ContactForm {
|
||||
pub rcpt_to: Vec<CompactString>,
|
||||
pub rcpt_to: Vec<String>,
|
||||
pub max_size: usize,
|
||||
pub rate: Option<Rate>,
|
||||
pub validate_domain: bool,
|
||||
pub from_email: FieldOrDefault,
|
||||
pub from_subject: FieldOrDefault,
|
||||
pub from_name: FieldOrDefault,
|
||||
pub field_honey_pot: Option<CompactString>,
|
||||
pub field_honey_pot: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -129,7 +129,7 @@ impl ContactForm {
|
|||
.values("form.deliver-to")
|
||||
.filter_map(|(_, addr)| {
|
||||
if addr.contains('@') && addr.contains('.') {
|
||||
Some(CompactString::from_str_to_lowercase(addr.trim()))
|
||||
Some(addr.trim().to_lowercase())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -200,8 +200,8 @@ impl Network {
|
|||
|
||||
let mut network = Network {
|
||||
node_id: config.property("cluster.node-id").unwrap_or(1),
|
||||
report_domain: report_domain.into(),
|
||||
server_name: server_name.into(),
|
||||
report_domain,
|
||||
server_name,
|
||||
security: Security::parse(config),
|
||||
contact_form: ContactForm::parse(config),
|
||||
asn_geo_lookup: AsnGeoLookupConfig::parse(config).unwrap_or_default(),
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use std::{
|
|||
|
||||
use ahash::AHashSet;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use hyper::{
|
||||
HeaderMap,
|
||||
header::{AUTHORIZATION, CONTENT_TYPE, HeaderName, HeaderValue},
|
||||
|
|
@ -143,9 +143,9 @@ pub struct Data {
|
|||
#[derive(Clone)]
|
||||
pub struct Milter {
|
||||
pub enable: IfBlock,
|
||||
pub id: Arc<CompactString>,
|
||||
pub id: Arc<String>,
|
||||
pub addrs: Vec<SocketAddr>,
|
||||
pub hostname: CompactString,
|
||||
pub hostname: String,
|
||||
pub port: u16,
|
||||
pub timeout_connect: Duration,
|
||||
pub timeout_command: Duration,
|
||||
|
|
@ -473,7 +473,7 @@ fn parse_milter(config: &mut Config, id: &str, token_map: &TokenMap) -> Option<M
|
|||
})
|
||||
.ok()?
|
||||
.collect(),
|
||||
hostname: hostname.into(),
|
||||
hostname,
|
||||
port,
|
||||
timeout_connect: config
|
||||
.property_or_default(("session.milter", id, "timeout.connect"), "30s")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub mod undelete;
|
|||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::{QueryBy, Type, backend::internal::lookup::DirectoryStore};
|
||||
use license::LicenseKey;
|
||||
use llm::AiApiConfig;
|
||||
|
|
@ -233,7 +233,7 @@ impl Server {
|
|||
}
|
||||
}
|
||||
|
||||
fn default_logo_url(&self) -> Option<CompactString> {
|
||||
fn default_logo_url(&self) -> Option<String> {
|
||||
self.core
|
||||
.enterprise
|
||||
.as_ref()
|
||||
|
|
|
|||
|
|
@ -701,6 +701,21 @@ impl<'x> TryFrom<Variable<'x>> for CompactString {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'x> TryFrom<Variable<'x>> for String {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
|
||||
if let Variable::String(s) = value {
|
||||
Ok(match s {
|
||||
StringCow::Borrowed(v) => v.to_string(),
|
||||
StringCow::Owned(v) => v.into_string(),
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'x> From<Variable<'x>> for bool {
|
||||
fn from(val: Variable<'x>) -> Self {
|
||||
val.to_bool()
|
||||
|
|
|
|||
|
|
@ -23,14 +23,14 @@ pub struct IfThen {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IfBlock {
|
||||
pub key: CompactString,
|
||||
pub key: String,
|
||||
pub if_then: Vec<IfThen>,
|
||||
pub default: Expression,
|
||||
}
|
||||
|
||||
impl IfBlock {
|
||||
pub fn new<T: ConstantValue>(
|
||||
key: impl Into<CompactString>,
|
||||
key: impl Into<String>,
|
||||
if_thens: impl IntoIterator<Item = (&'static str, &'static str)>,
|
||||
default: impl AsRef<str>,
|
||||
) -> Self {
|
||||
|
|
@ -51,7 +51,7 @@ impl IfBlock {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn empty(key: impl Into<CompactString>) -> Self {
|
||||
pub fn empty(key: impl Into<String>) -> Self {
|
||||
Self {
|
||||
key: key.into(),
|
||||
if_then: Default::default(),
|
||||
|
|
@ -102,7 +102,7 @@ impl IfBlock {
|
|||
|
||||
// Parse conditions
|
||||
let mut if_block = IfBlock {
|
||||
key: key.into(),
|
||||
key,
|
||||
if_then: Default::default(),
|
||||
default: Expression {
|
||||
items: Default::default(),
|
||||
|
|
@ -214,7 +214,7 @@ impl IfBlock {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn into_default(self, key: impl Into<CompactString>) -> IfBlock {
|
||||
pub fn into_default(self, key: impl Into<String>) -> IfBlock {
|
||||
IfBlock {
|
||||
key: key.into(),
|
||||
if_then: Default::default(),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
use ahash::RandomState;
|
||||
use compact_str::CompactString;
|
||||
use jmap_proto::types::{state::StateChange, type_state::DataType};
|
||||
use mail_auth::{
|
||||
dmarc::Dmarc,
|
||||
|
|
@ -70,8 +69,8 @@ pub enum StateEvent {
|
|||
pub enum UpdateSubscription {
|
||||
Unverified {
|
||||
id: u32,
|
||||
url: CompactString,
|
||||
code: CompactString,
|
||||
url: String,
|
||||
code: String,
|
||||
keys: Option<EncryptionKeys>,
|
||||
},
|
||||
Verified(PushSubscription),
|
||||
|
|
@ -80,7 +79,7 @@ pub enum UpdateSubscription {
|
|||
#[derive(Debug)]
|
||||
pub struct PushSubscription {
|
||||
pub id: u32,
|
||||
pub url: CompactString,
|
||||
pub url: String,
|
||||
pub expires: u64,
|
||||
pub types: Bitmap<DataType>,
|
||||
pub keys: Option<EncryptionKeys>,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use std::{
|
|||
use ahash::{AHashMap, AHashSet};
|
||||
use arc_swap::ArcSwap;
|
||||
use auth::{AccessToken, oauth::config::OAuthConfig, roles::RolePermissions};
|
||||
use compact_str::CompactString;
|
||||
use config::{
|
||||
dav::DavConfig,
|
||||
imap::ImapConfig,
|
||||
|
|
@ -180,7 +179,7 @@ pub struct MessageStoreCache {
|
|||
pub change_id: u64,
|
||||
pub items: Vec<MessageCache>,
|
||||
pub index: AHashMap<u32, u32>,
|
||||
pub keywords: Vec<CompactString>,
|
||||
pub keywords: Vec<String>,
|
||||
pub update_lock: Arc<Semaphore>,
|
||||
pub size: u64,
|
||||
}
|
||||
|
|
@ -203,8 +202,8 @@ pub struct MessageUidCache {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct MailboxCache {
|
||||
pub document_id: u32,
|
||||
pub name: CompactString,
|
||||
pub path: CompactString,
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
pub role: SpecialUse,
|
||||
pub parent_id: u32,
|
||||
pub sort_order: u32,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Adapted from rustls-acme (https://github.com/FlorianUekermann/rustls-acme), licensed under MIT/Apache-2.0.
|
||||
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use dns_update::DnsRecord;
|
||||
use futures::future::try_join_all;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use sieve::{Envelope, runtime::Variable};
|
||||
use store::Value;
|
||||
use unicode_security::mixed_script::AugmentedScriptSet;
|
||||
|
|
@ -22,7 +22,7 @@ pub mod plugins;
|
|||
pub enum ScriptModification {
|
||||
SetEnvelope {
|
||||
name: Envelope,
|
||||
value: CompactString,
|
||||
value: String,
|
||||
},
|
||||
AddHeader {
|
||||
name: Arc<String>,
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ impl Server {
|
|||
.unwrap_or_default()
|
||||
{
|
||||
acl_obj.append(
|
||||
Property::_T(name.into()),
|
||||
Property::_T(name),
|
||||
item.grants
|
||||
.map(|acl_item| Value::Text(acl_item.to_string()))
|
||||
.collect::<Vec<_>>(),
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ impl DavAclHandler for Server {
|
|||
.get_principal_name(grant_account_id)
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
.unwrap_or_else(|| format_compact!("_{grant_account_id}"));
|
||||
.unwrap_or_else(|| format!("_{grant_account_id}"));
|
||||
|
||||
aces.push(Ace::new(
|
||||
Principal::Href(Href(format!(
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ impl PrincipalPropFind for Server {
|
|||
.get_principal_name(account_id)
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
.unwrap_or_else(|| format_compact!("_{account_id}"));
|
||||
.unwrap_or_else(|| format!("_{account_id}"));
|
||||
Ok(Href(format!(
|
||||
"{}/{}",
|
||||
DavResource::Principal.base_path(),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_send::Credentials;
|
||||
use smtp_proto::{AUTH_CRAM_MD5, AUTH_LOGIN, AUTH_OAUTHBEARER, AUTH_PLAIN, AUTH_XOAUTH2};
|
||||
|
||||
|
|
@ -69,11 +69,11 @@ impl ImapDirectory {
|
|||
Err(trc::StoreEvent::NotSupported.caused_by(trc::location!()))
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, _address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, _address: &str) -> trc::Result<Vec<String>> {
|
||||
Err(trc::StoreEvent::NotSupported.caused_by(trc::location!()))
|
||||
}
|
||||
|
||||
pub async fn expn(&self, _address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, _address: &str) -> trc::Result<Vec<String>> {
|
||||
Err(trc::StoreEvent::NotSupported.caused_by(trc::location!()))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use super::{PrincipalInfo, manage::ManageDirectory};
|
||||
use crate::{Principal, PrincipalData, QueryBy, Type, backend::RcptType};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_send::Credentials;
|
||||
use store::{
|
||||
Deserialize, IterateParams, Store, ValueKey,
|
||||
|
|
@ -24,9 +24,9 @@ pub trait DirectoryStore: Sync + Send {
|
|||
async fn email_to_id(&self, address: &str) -> trc::Result<Option<u32>>;
|
||||
async fn is_local_domain(&self, domain: &str) -> trc::Result<bool>;
|
||||
async fn rcpt(&self, address: &str) -> trc::Result<RcptType>;
|
||||
async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>>;
|
||||
async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>>;
|
||||
async fn expn_by_id(&self, id: u32) -> trc::Result<Vec<CompactString>>;
|
||||
async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>>;
|
||||
async fn expn(&self, address: &str) -> trc::Result<Vec<String>>;
|
||||
async fn expn_by_id(&self, id: u32) -> trc::Result<Vec<String>>;
|
||||
}
|
||||
|
||||
impl DirectoryStore for Store {
|
||||
|
|
@ -123,7 +123,7 @@ impl DirectoryStore for Store {
|
|||
}
|
||||
}
|
||||
|
||||
async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
let mut results = Vec::new();
|
||||
let address = address.split('@').next().unwrap_or(address);
|
||||
if address.len() > 3 {
|
||||
|
|
@ -155,7 +155,7 @@ impl DirectoryStore for Store {
|
|||
Ok(results)
|
||||
}
|
||||
|
||||
async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
if let Some(ptype) = self
|
||||
.get_value::<PrincipalInfo>(ValueKey::from(ValueClass::Directory(
|
||||
DirectoryClass::EmailToId(address.as_bytes().to_vec()),
|
||||
|
|
@ -169,7 +169,7 @@ impl DirectoryStore for Store {
|
|||
}
|
||||
}
|
||||
|
||||
async fn expn_by_id(&self, list_id: u32) -> trc::Result<Vec<CompactString>> {
|
||||
async fn expn_by_id(&self, list_id: u32) -> trc::Result<Vec<String>> {
|
||||
let mut results = Vec::new();
|
||||
for account_id in self.get_members(list_id).await? {
|
||||
if let Some(email) = self
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use crate::{
|
|||
QueryBy, ROLE_ADMIN, ROLE_TENANT_ADMIN, ROLE_USER, Type, backend::RcptType,
|
||||
};
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use jmap_proto::types::collection::Collection;
|
||||
use store::{
|
||||
|
|
@ -61,7 +62,7 @@ pub trait ManageDirectory: Sized {
|
|||
async fn get_principal_info(&self, name: &str) -> trc::Result<Option<PrincipalInfo>>;
|
||||
async fn get_or_create_principal_id(&self, name: &str, typ: Type) -> trc::Result<u32>;
|
||||
async fn get_principal(&self, principal_id: u32) -> trc::Result<Option<Principal>>;
|
||||
async fn get_principal_name(&self, principal_id: u32) -> trc::Result<Option<CompactString>>;
|
||||
async fn get_principal_name(&self, principal_id: u32) -> trc::Result<Option<String>>;
|
||||
async fn get_member_of(&self, principal_id: u32) -> trc::Result<Vec<MemberOf>>;
|
||||
async fn get_members(&self, principal_id: u32) -> trc::Result<Vec<u32>>;
|
||||
async fn create_principal(
|
||||
|
|
@ -125,7 +126,7 @@ impl ManageDirectory for Store {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_principal_name(&self, principal_id: u32) -> trc::Result<Option<CompactString>> {
|
||||
async fn get_principal_name(&self, principal_id: u32) -> trc::Result<Option<String>> {
|
||||
let archive = self
|
||||
.get_value::<Archive<AlignedBytes>>(ValueKey::from(ValueClass::Directory(
|
||||
DirectoryClass::Principal(principal_id),
|
||||
|
|
@ -248,11 +249,11 @@ impl ManageDirectory for Store {
|
|||
allowed_permissions: Option<&Permissions>,
|
||||
) -> trc::Result<CreatedPrincipal> {
|
||||
// Make sure the principal has a name
|
||||
let name = CompactString::from_str_to_lowercase(principal_set.name());
|
||||
let name = principal_set.name().to_lowercase();
|
||||
if name.is_empty() {
|
||||
return Err(err_missing(PrincipalField::Name));
|
||||
}
|
||||
let mut valid_domains: AHashSet<CompactString> = AHashSet::new();
|
||||
let mut valid_domains: AHashSet<String> = AHashSet::new();
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
|
||||
|
|
@ -1271,7 +1272,7 @@ impl ManageDirectory for Store {
|
|||
PrincipalValue::String(email),
|
||||
) => {
|
||||
let email = email.to_lowercase();
|
||||
if let Some(idx) = principal.emails.iter().position(|v| v == email) {
|
||||
if let Some(idx) = principal.emails.iter().position(|v| v == &email) {
|
||||
principal.emails.remove(idx);
|
||||
batch.clear(ValueClass::Directory(DirectoryClass::EmailToId(
|
||||
email.as_bytes().to_vec(),
|
||||
|
|
@ -1899,7 +1900,7 @@ impl ManageDirectory for Store {
|
|||
{
|
||||
let mut principal = Principal::new(pt.id, pt.typ);
|
||||
principal.name =
|
||||
CompactString::from_utf8_lossy(key.get(1..).unwrap_or_default());
|
||||
String::from_utf8_lossy(key.get(1..).unwrap_or_default()).into_owned();
|
||||
results.push(principal);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ pub mod manage;
|
|||
|
||||
use crate::Type;
|
||||
use ahash::AHashMap;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use std::fmt::Display;
|
||||
use store::{Deserialize, SerializeInfallible, U32_LEN, write::key::KeySerializer};
|
||||
use utils::codec::leb128::Leb128Iterator;
|
||||
|
|
@ -140,8 +140,8 @@ pub enum PrincipalAction {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum PrincipalValue {
|
||||
String(CompactString),
|
||||
StringList(Vec<CompactString>),
|
||||
String(String),
|
||||
StringList(Vec<String>),
|
||||
Integer(u64),
|
||||
IntegerList(Vec<u64>),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
use ldap3::{Ldap, LdapConnAsync, ResultEntry, Scope, SearchEntry};
|
||||
use mail_send::Credentials;
|
||||
use store::xxhash_rust;
|
||||
|
|
@ -298,11 +297,11 @@ impl LdapDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.data_store.vrfy(address).await
|
||||
}
|
||||
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.data_store.expn(address).await
|
||||
}
|
||||
|
||||
|
|
@ -351,44 +350,39 @@ impl LdapMappings {
|
|||
for (attr, value) in entry.attrs {
|
||||
if self.attr_name.contains(&attr) {
|
||||
if !self.attr_email_address.contains(&attr) {
|
||||
principal.name = value.into_iter().next().unwrap_or_default().into();
|
||||
principal.name = value.into_iter().next().unwrap_or_default();
|
||||
} else {
|
||||
for (idx, item) in value.into_iter().enumerate() {
|
||||
principal
|
||||
.emails
|
||||
.insert(0, CompactString::from_str_to_lowercase(&item));
|
||||
principal.emails.insert(0, item.to_lowercase());
|
||||
if idx == 0 {
|
||||
principal.name = item.into();
|
||||
principal.name = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if self.attr_secret.contains(&attr) {
|
||||
for item in value {
|
||||
principal.secrets.push(item.into());
|
||||
principal.secrets.push(item);
|
||||
}
|
||||
} else if self.attr_secret_changed.contains(&attr) {
|
||||
// Create a disabled AppPassword, used to indicate that the password has been changed
|
||||
// but cannot be used for authentication.
|
||||
for item in value {
|
||||
principal.secrets.push(
|
||||
format!("$app${}$", xxhash_rust::xxh3::xxh3_64(item.as_bytes())).into(),
|
||||
);
|
||||
principal.secrets.push(format!(
|
||||
"$app${}$",
|
||||
xxhash_rust::xxh3::xxh3_64(item.as_bytes())
|
||||
));
|
||||
}
|
||||
} else if self.attr_email_address.contains(&attr) {
|
||||
for item in value {
|
||||
principal
|
||||
.emails
|
||||
.insert(0, CompactString::from_str_to_lowercase(&item));
|
||||
principal.emails.insert(0, item.to_lowercase());
|
||||
}
|
||||
} else if self.attr_email_alias.contains(&attr) {
|
||||
for item in value {
|
||||
principal
|
||||
.emails
|
||||
.push(CompactString::from_str_to_lowercase(&item));
|
||||
principal.emails.push(item.to_lowercase());
|
||||
}
|
||||
} else if let Some(idx) = self.attr_description.iter().position(|a| a == &attr) {
|
||||
if principal.description.is_none() || idx == 0 {
|
||||
principal.description = value.into_iter().next().map(Into::into);
|
||||
principal.description = value.into_iter().next();
|
||||
}
|
||||
} else if self.attr_groups.contains(&attr) {
|
||||
member_of.extend(value);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use store::Store;
|
||||
use utils::config::{Config, utils::AsKey};
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ impl MemoryDirectory {
|
|||
|
||||
principal
|
||||
.emails
|
||||
.push(CompactString::from_str_to_lowercase(email));
|
||||
.push(email.to_lowercase());
|
||||
}
|
||||
|
||||
// Parse mailing lists
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use super::{EmailType, MemoryDirectory};
|
||||
use crate::{Principal, QueryBy, backend::RcptType};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_send::Credentials;
|
||||
|
||||
impl MemoryDirectory {
|
||||
|
|
@ -62,7 +62,7 @@ impl MemoryDirectory {
|
|||
Ok(self.emails_to_ids.contains_key(address).into())
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
let mut result = Vec::new();
|
||||
for (key, value) in &self.emails_to_ids {
|
||||
if key.contains(address) && value.iter().any(|t| matches!(t, EmailType::Primary(_))) {
|
||||
|
|
@ -72,7 +72,7 @@ impl MemoryDirectory {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
let mut result = Vec::new();
|
||||
for (key, value) in &self.emails_to_ids {
|
||||
if key == address {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
pub mod imap;
|
||||
pub mod internal;
|
||||
|
|
@ -17,7 +17,7 @@ pub mod sql;
|
|||
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum RcptType {
|
||||
Mailbox,
|
||||
List(Vec<CompactString>),
|
||||
List(Vec<String>),
|
||||
#[default]
|
||||
Invalid,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
use ahash::HashMap;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_send::Credentials;
|
||||
use reqwest::{StatusCode, header::AUTHORIZATION};
|
||||
use trc::{AddContext, AuthEvent};
|
||||
|
|
@ -145,11 +145,11 @@ impl OpenIdDirectory {
|
|||
self.data_store.rcpt(address).await
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.data_store.vrfy(address).await
|
||||
}
|
||||
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.data_store.expn(address).await
|
||||
}
|
||||
|
||||
|
|
@ -188,10 +188,10 @@ impl BuildPrincipal for OpenIdResponse {
|
|||
Ok(Principal {
|
||||
id: u32::MAX,
|
||||
typ: Type::Individual,
|
||||
name: username.into(),
|
||||
description: full_name.map(Into::into),
|
||||
name: username,
|
||||
description: full_name,
|
||||
secrets: Default::default(),
|
||||
emails: vec![email.into()],
|
||||
emails: vec![email],
|
||||
quota: Default::default(),
|
||||
tenant: Default::default(),
|
||||
data: vec![PrincipalData::Roles(vec![ROLE_USER])],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_send::{Credentials, smtp::AssertReply};
|
||||
use smtp_proto::Severity;
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ impl SmtpDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.pool
|
||||
.get()
|
||||
.await
|
||||
|
|
@ -76,7 +76,7 @@ impl SmtpDirectory {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.pool
|
||||
.get()
|
||||
.await
|
||||
|
|
@ -111,7 +111,7 @@ impl SmtpClient {
|
|||
}
|
||||
}
|
||||
|
||||
async fn expand(&mut self, command: &str) -> trc::Result<Vec<CompactString>> {
|
||||
async fn expand(&mut self, command: &str) -> trc::Result<Vec<String>> {
|
||||
let reply = self
|
||||
.client
|
||||
.cmd(command.as_bytes())
|
||||
|
|
@ -122,7 +122,7 @@ impl SmtpClient {
|
|||
.message()
|
||||
.split('\n')
|
||||
.map(|p| p.into())
|
||||
.collect::<Vec<CompactString>>()),
|
||||
.collect::<Vec<String>>()),
|
||||
code @ (550 | 551 | 553 | 500 | 502) => {
|
||||
Err(trc::StoreEvent::NotSupported.ctx(trc::Key::Code, code))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
},
|
||||
},
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_send::Credentials;
|
||||
use store::{NamedRows, Rows, Value};
|
||||
use trc::AddContext;
|
||||
|
|
@ -250,11 +250,11 @@ impl SqlDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.data_store.vrfy(address).await
|
||||
}
|
||||
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
self.data_store.expn(address).await
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ impl SqlMappings {
|
|||
if let Value::Text(text) = value {
|
||||
principal
|
||||
.emails
|
||||
.push(CompactString::from_str_to_lowercase(text.as_ref()));
|
||||
.push(text.to_lowercase());
|
||||
}
|
||||
} else if name.eq_ignore_ascii_case(&self.column_quota) {
|
||||
if let Value::Integer(quota) = value {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use trc::AddContext;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -97,7 +97,7 @@ impl Directory {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
match &self.store {
|
||||
DirectoryInner::Internal(store) => store.vrfy(address).await,
|
||||
DirectoryInner::Ldap(store) => store.vrfy(address).await,
|
||||
|
|
@ -110,7 +110,7 @@ impl Directory {
|
|||
.caused_by(trc::location!())
|
||||
}
|
||||
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<CompactString>> {
|
||||
pub async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
|
||||
match &self.store {
|
||||
DirectoryInner::Internal(store) => store.expn(address).await,
|
||||
DirectoryInner::Ldap(store) => store.expn(address).await,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
use std::{collections::hash_map::Entry, fmt, str::FromStr};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use serde::{
|
||||
Deserializer, Serializer,
|
||||
de::{self, IgnoredAny, Visitor},
|
||||
|
|
@ -76,7 +75,7 @@ impl Principal {
|
|||
// SPDX-SnippetEnd
|
||||
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
self.description.as_ref().map(|d| d.as_str())
|
||||
self.description.as_deref()
|
||||
}
|
||||
|
||||
pub fn member_of(&self) -> &[u32] {
|
||||
|
|
@ -128,7 +127,7 @@ impl Principal {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn urls(&self) -> &[CompactString] {
|
||||
pub fn urls(&self) -> &[String] {
|
||||
self.data
|
||||
.iter()
|
||||
.find_map(|item| {
|
||||
|
|
@ -164,7 +163,7 @@ impl Principal {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn picture(&self) -> Option<&CompactString> {
|
||||
pub fn picture(&self) -> Option<&String> {
|
||||
self.data.iter().find_map(|item| {
|
||||
if let PrincipalData::Picture(picture) = item {
|
||||
picture.into()
|
||||
|
|
@ -174,7 +173,7 @@ impl Principal {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn picture_mut(&mut self) -> Option<&mut CompactString> {
|
||||
pub fn picture_mut(&mut self) -> Option<&mut String> {
|
||||
self.data.iter_mut().find_map(|item| {
|
||||
if let PrincipalData::Picture(picture) = item {
|
||||
picture.into()
|
||||
|
|
@ -299,7 +298,7 @@ impl Principal {
|
|||
updates
|
||||
}
|
||||
|
||||
pub fn fallback_admin(fallback_pass: impl Into<CompactString>) -> Self {
|
||||
pub fn fallback_admin(fallback_pass: impl Into<String>) -> Self {
|
||||
Principal {
|
||||
id: u32::MAX,
|
||||
typ: Type::Individual,
|
||||
|
|
@ -363,7 +362,7 @@ impl PrincipalSet {
|
|||
self.fields.get(&key).and_then(|v| v.as_int())
|
||||
}
|
||||
|
||||
pub fn get_str_array(&self, key: PrincipalField) -> Option<&[CompactString]> {
|
||||
pub fn get_str_array(&self, key: PrincipalField) -> Option<&[String]> {
|
||||
self.fields.get(&key).and_then(|v| match v {
|
||||
PrincipalValue::StringList(v) => Some(v.as_slice()),
|
||||
PrincipalValue::String(v) => Some(std::slice::from_ref(v)),
|
||||
|
|
@ -383,12 +382,12 @@ impl PrincipalSet {
|
|||
self.fields.remove(&key)
|
||||
}
|
||||
|
||||
pub fn take_str(&mut self, key: PrincipalField) -> Option<CompactString> {
|
||||
pub fn take_str(&mut self, key: PrincipalField) -> Option<String> {
|
||||
self.take(key).and_then(|v| match v {
|
||||
PrincipalValue::String(s) => Some(s),
|
||||
PrincipalValue::StringList(l) => l.into_iter().next(),
|
||||
PrincipalValue::Integer(i) => Some(i.to_string().into()),
|
||||
PrincipalValue::IntegerList(l) => l.into_iter().next().map(|i| i.to_string().into()),
|
||||
PrincipalValue::Integer(i) => Some(i.to_string()),
|
||||
PrincipalValue::IntegerList(l) => l.into_iter().next().map(|i| i.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +400,7 @@ impl PrincipalSet {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn take_str_array(&mut self, key: PrincipalField) -> Option<Vec<CompactString>> {
|
||||
pub fn take_str_array(&mut self, key: PrincipalField) -> Option<Vec<String>> {
|
||||
self.take(key).map(|v| v.into_str_array())
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +411,7 @@ impl PrincipalSet {
|
|||
pub fn iter_str(
|
||||
&self,
|
||||
key: PrincipalField,
|
||||
) -> Box<dyn Iterator<Item = &CompactString> + Sync + Send + '_> {
|
||||
) -> Box<dyn Iterator<Item = &String> + Sync + Send + '_> {
|
||||
self.fields
|
||||
.get(&key)
|
||||
.map(|v| v.iter_str())
|
||||
|
|
@ -422,7 +421,7 @@ impl PrincipalSet {
|
|||
pub fn iter_mut_str(
|
||||
&mut self,
|
||||
key: PrincipalField,
|
||||
) -> Box<dyn Iterator<Item = &mut CompactString> + Sync + Send + '_> {
|
||||
) -> Box<dyn Iterator<Item = &mut String> + Sync + Send + '_> {
|
||||
self.fields
|
||||
.get_mut(&key)
|
||||
.map(|v| v.iter_mut_str())
|
||||
|
|
@ -488,11 +487,7 @@ impl PrincipalSet {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn append_str(
|
||||
&mut self,
|
||||
key: PrincipalField,
|
||||
value: impl Into<CompactString>,
|
||||
) -> &mut Self {
|
||||
pub fn append_str(&mut self, key: PrincipalField, value: impl Into<String>) -> &mut Self {
|
||||
let value = value.into();
|
||||
match self.fields.entry(key) {
|
||||
Entry::Occupied(v) => {
|
||||
|
|
@ -510,12 +505,12 @@ impl PrincipalSet {
|
|||
}
|
||||
}
|
||||
PrincipalValue::Integer(i) => {
|
||||
*v = PrincipalValue::StringList(vec![i.to_string().into(), value]);
|
||||
*v = PrincipalValue::StringList(vec![i.to_string(), value]);
|
||||
}
|
||||
PrincipalValue::IntegerList(l) => {
|
||||
*v = PrincipalValue::StringList(
|
||||
l.iter()
|
||||
.map(|i| i.to_string().into())
|
||||
.map(|i| i.to_string())
|
||||
.chain(std::iter::once(value))
|
||||
.collect(),
|
||||
);
|
||||
|
|
@ -529,11 +524,7 @@ impl PrincipalSet {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn prepend_str(
|
||||
&mut self,
|
||||
key: PrincipalField,
|
||||
value: impl Into<CompactString>,
|
||||
) -> &mut Self {
|
||||
pub fn prepend_str(&mut self, key: PrincipalField, value: impl Into<String>) -> &mut Self {
|
||||
let value = value.into();
|
||||
match self.fields.entry(key) {
|
||||
Entry::Occupied(v) => {
|
||||
|
|
@ -551,12 +542,12 @@ impl PrincipalSet {
|
|||
}
|
||||
}
|
||||
PrincipalValue::Integer(i) => {
|
||||
*v = PrincipalValue::StringList(vec![value, i.to_string().into()]);
|
||||
*v = PrincipalValue::StringList(vec![value, i.to_string()]);
|
||||
}
|
||||
PrincipalValue::IntegerList(l) => {
|
||||
*v = PrincipalValue::StringList(
|
||||
std::iter::once(value)
|
||||
.chain(l.iter().map(|i| i.to_string().into()))
|
||||
.chain(l.iter().map(|i| i.to_string()))
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
|
@ -629,7 +620,7 @@ impl PrincipalSet {
|
|||
|
||||
pub fn retain_str<F>(&mut self, key: PrincipalField, mut f: F)
|
||||
where
|
||||
F: FnMut(&CompactString) -> bool,
|
||||
F: FnMut(&String) -> bool,
|
||||
{
|
||||
if let Some(value) = self.fields.get_mut(&key) {
|
||||
match value {
|
||||
|
|
@ -689,7 +680,7 @@ impl PrincipalValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn iter_str(&self) -> Box<dyn Iterator<Item = &CompactString> + Sync + Send + '_> {
|
||||
pub fn iter_str(&self) -> Box<dyn Iterator<Item = &String> + Sync + Send + '_> {
|
||||
match self {
|
||||
PrincipalValue::String(v) => Box::new(std::iter::once(v)),
|
||||
PrincipalValue::StringList(v) => Box::new(v.iter()),
|
||||
|
|
@ -697,9 +688,7 @@ impl PrincipalValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn iter_mut_str(
|
||||
&mut self,
|
||||
) -> Box<dyn Iterator<Item = &mut CompactString> + Sync + Send + '_> {
|
||||
pub fn iter_mut_str(&mut self) -> Box<dyn Iterator<Item = &mut String> + Sync + Send + '_> {
|
||||
match self {
|
||||
PrincipalValue::String(v) => Box::new(std::iter::once(v)),
|
||||
PrincipalValue::StringList(v) => Box::new(v.iter_mut()),
|
||||
|
|
@ -731,12 +720,12 @@ impl PrincipalValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn into_str_array(self) -> Vec<CompactString> {
|
||||
pub fn into_str_array(self) -> Vec<String> {
|
||||
match self {
|
||||
PrincipalValue::StringList(v) => v,
|
||||
PrincipalValue::String(v) => vec![v],
|
||||
PrincipalValue::Integer(v) => vec![v.to_string().into()],
|
||||
PrincipalValue::IntegerList(v) => v.into_iter().map(|v| v.to_string().into()).collect(),
|
||||
PrincipalValue::Integer(v) => vec![v.to_string()],
|
||||
PrincipalValue::IntegerList(v) => v.into_iter().map(|v| v.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -776,8 +765,8 @@ impl From<u64> for PrincipalValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CompactString> for PrincipalValue {
|
||||
fn from(v: CompactString) -> Self {
|
||||
impl From<String> for PrincipalValue {
|
||||
fn from(v: String) -> Self {
|
||||
Self::String(v)
|
||||
}
|
||||
}
|
||||
|
|
@ -788,8 +777,8 @@ impl From<&str> for PrincipalValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Vec<CompactString>> for PrincipalValue {
|
||||
fn from(v: Vec<CompactString>) -> Self {
|
||||
impl From<Vec<String>> for PrincipalValue {
|
||||
fn from(v: Vec<String>) -> Self {
|
||||
Self::StringList(v)
|
||||
}
|
||||
}
|
||||
|
|
@ -956,7 +945,7 @@ impl<'de> serde::Deserialize<'de> for PrincipalValue {
|
|||
E: de::Error,
|
||||
{
|
||||
if value.len() <= MAX_STRING_LEN {
|
||||
Ok(PrincipalValue::String(value.into()))
|
||||
Ok(PrincipalValue::String(value))
|
||||
} else {
|
||||
Err(serde::de::Error::custom("string too long"))
|
||||
}
|
||||
|
|
@ -984,7 +973,7 @@ impl<'de> serde::Deserialize<'de> for PrincipalValue {
|
|||
match value {
|
||||
StringOrU64::String(s) => {
|
||||
if s.len() <= MAX_STRING_LEN {
|
||||
vec_string.push(s.into());
|
||||
vec_string.push(s);
|
||||
} else {
|
||||
return Err(serde::de::Error::custom("string too long"));
|
||||
}
|
||||
|
|
@ -1042,19 +1031,19 @@ impl<'de> serde::Deserialize<'de> for PrincipalSet {
|
|||
})?;
|
||||
|
||||
let value = match key {
|
||||
PrincipalField::Name => PrincipalValue::String(
|
||||
map.next_value::<CompactString>().and_then(|v| {
|
||||
PrincipalField::Name => {
|
||||
PrincipalValue::String(map.next_value::<String>().and_then(|v| {
|
||||
if v.len() <= MAX_STRING_LEN {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(serde::de::Error::custom("string too long"))
|
||||
}
|
||||
})?,
|
||||
),
|
||||
})?)
|
||||
}
|
||||
PrincipalField::Description
|
||||
| PrincipalField::Tenant
|
||||
| PrincipalField::Picture => {
|
||||
if let Some(v) = map.next_value::<Option<CompactString>>()? {
|
||||
if let Some(v) = map.next_value::<Option<String>>()? {
|
||||
if v.len() <= MAX_STRING_LEN {
|
||||
PrincipalValue::String(v)
|
||||
} else {
|
||||
|
|
@ -1166,8 +1155,8 @@ impl<'de> serde::Deserialize<'de> for StringOrU64 {
|
|||
|
||||
#[derive(Debug)]
|
||||
enum StringOrMany {
|
||||
One(CompactString),
|
||||
Many(Vec<CompactString>),
|
||||
One(String),
|
||||
Many(Vec<String>),
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for StringOrMany {
|
||||
|
|
@ -1200,7 +1189,7 @@ impl<'de> serde::Deserialize<'de> for StringOrMany {
|
|||
E: de::Error,
|
||||
{
|
||||
if v.len() <= MAX_STRING_LEN {
|
||||
Ok(StringOrMany::One(v.into()))
|
||||
Ok(StringOrMany::One(v))
|
||||
} else {
|
||||
Err(serde::de::Error::custom("string too long"))
|
||||
}
|
||||
|
|
@ -1212,7 +1201,7 @@ impl<'de> serde::Deserialize<'de> for StringOrMany {
|
|||
{
|
||||
let mut vec = Vec::new();
|
||||
|
||||
while let Some(value) = seq.next_element::<CompactString>()? {
|
||||
while let Some(value) = seq.next_element::<String>()? {
|
||||
vec.push(value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
use argon2::Argon2;
|
||||
use compact_str::ToCompactString;
|
||||
use mail_builder::encoders::base64::base64_encode;
|
||||
use mail_parser::decoders::base64::base64_decode;
|
||||
use password_hash::PasswordHash;
|
||||
|
|
@ -57,7 +58,7 @@ impl Principal {
|
|||
.map_err(|err| {
|
||||
trc::AuthEvent::Error
|
||||
.reason(err)
|
||||
.details(secret.to_string())
|
||||
.details(secret.to_compact_string())
|
||||
})?
|
||||
.check_current(totp_token)
|
||||
.unwrap_or(false);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use backend::{
|
|||
smtp::SmtpDirectory,
|
||||
sql::SqlDirectory,
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use deadpool::managed::PoolError;
|
||||
use ldap3::LdapError;
|
||||
use mail_send::Credentials;
|
||||
|
|
@ -37,10 +37,10 @@ pub struct Directory {
|
|||
pub struct Principal {
|
||||
pub id: u32,
|
||||
pub typ: Type,
|
||||
pub name: CompactString,
|
||||
pub description: Option<CompactString>,
|
||||
pub secrets: Vec<CompactString>,
|
||||
pub emails: Vec<CompactString>,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub secrets: Vec<String>,
|
||||
pub emails: Vec<String>,
|
||||
pub quota: Option<u64>,
|
||||
pub tenant: Option<u32>,
|
||||
pub data: Vec<PrincipalData>,
|
||||
|
|
@ -58,9 +58,9 @@ pub enum PrincipalData {
|
|||
Roles(Vec<u32>),
|
||||
Lists(Vec<u32>),
|
||||
Permissions(Vec<PermissionGrant>),
|
||||
Picture(CompactString),
|
||||
ExternalMembers(Vec<CompactString>),
|
||||
Urls(Vec<CompactString>),
|
||||
Picture(String),
|
||||
ExternalMembers(Vec<String>),
|
||||
Urls(Vec<String>),
|
||||
PrincipalQuota(Vec<PrincipalQuota>),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,25 +6,25 @@
|
|||
|
||||
pub mod index;
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use store::{SERIALIZE_IDENTITY_V1, SerializedVersion};
|
||||
|
||||
#[derive(
|
||||
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
|
||||
)]
|
||||
pub struct Identity {
|
||||
pub name: CompactString,
|
||||
pub email: CompactString,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub reply_to: Option<Vec<EmailAddress>>,
|
||||
pub bcc: Option<Vec<EmailAddress>>,
|
||||
pub text_signature: CompactString,
|
||||
pub html_signature: CompactString,
|
||||
pub text_signature: String,
|
||||
pub html_signature: String,
|
||||
}
|
||||
|
||||
#[derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EmailAddress {
|
||||
pub name: Option<CompactString>,
|
||||
pub email: CompactString,
|
||||
pub name: Option<String>,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
impl SerializedVersion for Identity {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use common::{
|
|||
CacheSwap, MailboxCache, MailboxStoreCache, Server, auth::AccessToken,
|
||||
config::jmap::settings::SpecialUse, sharing::EffectiveAcl,
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use jmap_proto::types::{acl::Acl, collection::Collection, value::AclGrant};
|
||||
use std::future::Future;
|
||||
use store::{
|
||||
|
|
@ -242,7 +242,7 @@ fn build_tree(cache: &mut MailboxStoreCache) {
|
|||
mailbox.path = if matches!(mailbox.role, SpecialUse::Inbox) {
|
||||
"INBOX".into()
|
||||
} else if mailbox.is_root() && mailbox.name.as_str().eq_ignore_ascii_case("inbox") {
|
||||
format!("INBOX {}", idx + 1).into()
|
||||
format!("INBOX {}", idx + 1)
|
||||
} else {
|
||||
mailbox.name.clone()
|
||||
};
|
||||
|
|
@ -264,7 +264,7 @@ fn build_tree(cache: &mut MailboxStoreCache) {
|
|||
cache.by_id(&parent_id).map(|folder| (path, &folder.path))
|
||||
})
|
||||
{
|
||||
let mut new_path = CompactString::with_capacity(parent_path.len() + path.len() + 1);
|
||||
let mut new_path = String::with_capacity(parent_path.len() + path.len() + 1);
|
||||
new_path.push_str(parent_path.as_str());
|
||||
new_path.push('/');
|
||||
new_path.push_str(path.as_str());
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
use common::config::jmap::settings::SpecialUse;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use jmap_proto::types::value::AclGrant;
|
||||
use store::{SERIALIZE_MAILBOX_V1, SerializedVersion};
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ pub const TOMBSTONE_ID: u32 = u32::MAX - 1;
|
|||
#[derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[rkyv(derive(Debug))]
|
||||
pub struct Mailbox {
|
||||
pub name: CompactString,
|
||||
pub name: String,
|
||||
pub role: SpecialUse,
|
||||
pub parent_id: u32,
|
||||
pub sort_order: Option<u32>,
|
||||
|
|
@ -48,7 +48,7 @@ impl SerializedVersion for Mailbox {
|
|||
}
|
||||
|
||||
impl Mailbox {
|
||||
pub fn new(name: impl Into<CompactString>) -> Self {
|
||||
pub fn new(name: impl Into<String>) -> Self {
|
||||
Mailbox {
|
||||
name: name.into(),
|
||||
role: SpecialUse::None,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use common::{
|
|||
CacheSwap, MailboxStoreCache, MessageCache, MessageStoreCache, MessageUidCache, Server,
|
||||
auth::AccessToken, sharing::EffectiveAcl,
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use jmap_proto::types::{
|
||||
acl::Acl,
|
||||
collection::Collection,
|
||||
|
|
@ -227,7 +227,7 @@ fn insert_item(cache: &mut MessageStoreCache, document_id: u32, message: &Archiv
|
|||
if let Some(idx) = cache.keywords.iter().position(|k| k == custom) {
|
||||
item.keywords |= 1 << (OTHER + idx);
|
||||
} else if cache.keywords.len() < (128 - OTHER) {
|
||||
cache.keywords.push(CompactString::from(custom));
|
||||
cache.keywords.push(String::from(custom));
|
||||
item.keywords |= 1 << (OTHER + cache.keywords.len() - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
use common::Server;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::Permission;
|
||||
use jmap_proto::types::{state::StateChange, type_state::DataType};
|
||||
use mail_parser::MessageParser;
|
||||
|
|
@ -19,8 +19,8 @@ use super::ingest::{EmailIngest, IngestEmail, IngestSource};
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct IngestMessage {
|
||||
pub sender_address: CompactString,
|
||||
pub recipients: Vec<CompactString>,
|
||||
pub sender_address: String,
|
||||
pub recipients: Vec<String>,
|
||||
pub message_blob: BlobHash,
|
||||
pub message_size: u64,
|
||||
pub session_id: u64,
|
||||
|
|
@ -44,8 +44,8 @@ pub struct LocalDeliveryResult {
|
|||
}
|
||||
|
||||
pub struct AutogeneratedMessage {
|
||||
pub sender_address: CompactString,
|
||||
pub recipients: Vec<CompactString>,
|
||||
pub sender_address: String,
|
||||
pub recipients: Vec<String>,
|
||||
pub message: Vec<u8>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
use jmap_proto::types::type_state::DataType;
|
||||
use store::{SERIALIZE_PUSH_V1, SerializedVersion};
|
||||
use utils::map::bitmap::Bitmap;
|
||||
|
|
@ -13,10 +12,10 @@ use utils::map::bitmap::Bitmap;
|
|||
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Default, Debug, Clone, PartialEq, Eq,
|
||||
)]
|
||||
pub struct PushSubscription {
|
||||
pub url: CompactString,
|
||||
pub device_client_id: CompactString,
|
||||
pub url: String,
|
||||
pub device_client_id: String,
|
||||
pub expires: u64,
|
||||
pub verification_code: CompactString,
|
||||
pub verification_code: String,
|
||||
pub verified: bool,
|
||||
pub types: Bitmap<DataType>,
|
||||
pub keys: Option<Keys>,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
use common::{
|
||||
Server, auth::AccessToken, config::jmap::settings::SpecialUse, scripts::plugins::PluginContext,
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::{Permission, QueryBy};
|
||||
use jmap_proto::types::{collection::Collection, id::Id, keyword::Keyword, property::Property};
|
||||
use mail_parser::MessageParser;
|
||||
|
|
@ -377,11 +377,9 @@ impl SieveScriptIngest for Server {
|
|||
} => {
|
||||
input = true.into();
|
||||
if let Some(message) = messages.get(message_id) {
|
||||
let recipients: Vec<CompactString> = match recipient {
|
||||
Recipient::Address(rcpt) => vec![rcpt.into()],
|
||||
Recipient::Group(rcpts) => {
|
||||
rcpts.into_iter().map(CompactString::from).collect()
|
||||
}
|
||||
let recipients: Vec<String> = match recipient {
|
||||
Recipient::Address(rcpt) => vec![rcpt],
|
||||
Recipient::Group(rcpts) => rcpts,
|
||||
Recipient::List(_) => {
|
||||
// Not yet implemented
|
||||
continue;
|
||||
|
|
@ -394,7 +392,7 @@ impl SieveScriptIngest for Server {
|
|||
From = mail_from.clone(),
|
||||
To = recipients
|
||||
.iter()
|
||||
.map(|r| trc::Value::String(r.clone()))
|
||||
.map(|r| trc::Value::String(r.as_str().into()))
|
||||
.collect::<Vec<_>>(),
|
||||
Size = message.raw_message.len(),
|
||||
SpanId = session_id
|
||||
|
|
@ -411,7 +409,7 @@ impl SieveScriptIngest for Server {
|
|||
From = mail_from.clone(),
|
||||
To = recipients
|
||||
.iter()
|
||||
.map(|r| trc::Value::String(r.clone()))
|
||||
.map(|r| trc::Value::String(r.as_str().into()))
|
||||
.collect::<Vec<_>>(),
|
||||
Size = message.raw_message.len(),
|
||||
Limit = self.core.jmap.mail_max_size,
|
||||
|
|
@ -722,6 +720,6 @@ impl SieveScriptIngest for Server {
|
|||
|
||||
pub struct CompiledScript {
|
||||
pub script: Sieve,
|
||||
pub name: CompactString,
|
||||
pub name: String,
|
||||
pub hash: u32,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use common::KV_SIEVE_ID;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use sieve::Sieve;
|
||||
use store::{SERIALIZE_SIEVE_V1, SerializedVersion, blake3};
|
||||
use utils::BlobHash;
|
||||
|
|
@ -21,7 +21,7 @@ pub mod ingest;
|
|||
pub struct ActiveScript {
|
||||
pub document_id: u32,
|
||||
pub hash: u32,
|
||||
pub script_name: CompactString,
|
||||
pub script_name: String,
|
||||
pub script: Arc<Sieve>,
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ pub struct ActiveScript {
|
|||
)]
|
||||
#[rkyv(derive(Debug))]
|
||||
pub struct SieveScript {
|
||||
pub name: CompactString,
|
||||
pub name: String,
|
||||
pub is_active: bool,
|
||||
pub blob_hash: BlobHash,
|
||||
pub size: u32,
|
||||
|
|
@ -50,13 +50,13 @@ impl SerializedVersion for SieveScript {
|
|||
pub struct VacationResponse {
|
||||
pub from_date: Option<u64>,
|
||||
pub to_date: Option<u64>,
|
||||
pub subject: Option<CompactString>,
|
||||
pub text_body: Option<CompactString>,
|
||||
pub html_body: Option<CompactString>,
|
||||
pub subject: Option<String>,
|
||||
pub text_body: Option<String>,
|
||||
pub html_body: Option<String>,
|
||||
}
|
||||
|
||||
impl SieveScript {
|
||||
pub fn new(name: impl Into<CompactString>, blob_hash: BlobHash) -> Self {
|
||||
pub fn new(name: impl Into<String>, blob_hash: BlobHash) -> Self {
|
||||
SieveScript {
|
||||
name: name.into(),
|
||||
is_active: false,
|
||||
|
|
@ -66,7 +66,7 @@ impl SieveScript {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn with_name(mut self, name: impl Into<CompactString>) -> Self {
|
||||
pub fn with_name(mut self, name: impl Into<String>) -> Self {
|
||||
self.name = name.into();
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use calcard::icalendar::ICalendar;
|
||||
use compact_str::CompactString;
|
||||
|
||||
use dav_proto::schema::request::DeadProperty;
|
||||
use jmap_proto::types::{acl::Acl, value::AclGrant};
|
||||
use store::{SERIALIZE_CALENDAR_V1, SERIALIZE_CALENDAREVENT_V1, SerializedVersion, ahash};
|
||||
|
|
@ -19,7 +19,7 @@ use crate::DavName;
|
|||
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
|
||||
)]
|
||||
pub struct Calendar {
|
||||
pub name: CompactString,
|
||||
pub name: String,
|
||||
pub preferences: HashMap<u32, CalendarPreferences, ahash::RandomState>,
|
||||
pub acls: Vec<AclGrant>,
|
||||
pub dead_properties: DeadProperty,
|
||||
|
|
@ -31,16 +31,16 @@ pub struct Calendar {
|
|||
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
|
||||
)]
|
||||
pub struct CalendarPreferences {
|
||||
pub name: CompactString,
|
||||
pub description: Option<CompactString>,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub sort_order: u32,
|
||||
pub color: Option<CompactString>,
|
||||
pub color: Option<String>,
|
||||
pub is_subscribed: bool,
|
||||
pub is_default: bool,
|
||||
pub is_visible: bool,
|
||||
pub include_in_availability: IncludeInAvailability,
|
||||
pub default_alerts_with_time: HashMap<CompactString, ICalendar, ahash::RandomState>,
|
||||
pub default_alerts_without_time: HashMap<CompactString, ICalendar, ahash::RandomState>,
|
||||
pub default_alerts_with_time: HashMap<String, ICalendar, ahash::RandomState>,
|
||||
pub default_alerts_without_time: HashMap<String, ICalendar, ahash::RandomState>,
|
||||
pub time_zone: Timezone,
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ pub struct CalendarPreferences {
|
|||
)]
|
||||
pub struct CalendarEvent {
|
||||
pub names: Vec<DavName>,
|
||||
pub display_name: Option<CompactString>,
|
||||
pub display_name: Option<String>,
|
||||
pub event: ICalendar,
|
||||
pub user_properties: VecMap<u32, ICalendar>,
|
||||
pub may_invite_self: bool,
|
||||
|
|
@ -66,7 +66,7 @@ pub struct CalendarEvent {
|
|||
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
|
||||
)]
|
||||
pub enum Timezone {
|
||||
IANA(CompactString),
|
||||
IANA(String),
|
||||
Custom(ICalendar),
|
||||
#[default]
|
||||
Default,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
pub mod index;
|
||||
|
||||
use calcard::vcard::VCard;
|
||||
|
||||
use dav_proto::schema::request::DeadProperty;
|
||||
use jmap_proto::types::{acl::Acl, value::AclGrant};
|
||||
use store::{SERIALIZE_ADDRESSBOOK_V1, SERIALIZE_CALENDAREVENT_V1, SerializedVersion};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
pub mod index;
|
||||
|
||||
|
||||
use dav_proto::schema::request::DeadProperty;
|
||||
use jmap_proto::types::value::AclGrant;
|
||||
use store::{SERIALIZE_FILENODE_V1, SerializedVersion};
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ impl Deserialize for DavName {
|
|||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Value, bytes)
|
||||
})?
|
||||
.to_string();
|
||||
.into();
|
||||
|
||||
Ok(DavName { name, parent_id })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use common::{
|
|||
Server,
|
||||
expr::{functions::ResolveVariable, *},
|
||||
};
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
use compact_str::{ToCompactString, format_compact};
|
||||
use hyper::StatusCode;
|
||||
|
||||
use crate::{HttpContext, HttpRequest, HttpSessionData};
|
||||
|
|
@ -18,7 +18,7 @@ impl<'x> HttpContext<'x> {
|
|||
Self { session, req }
|
||||
}
|
||||
|
||||
pub async fn resolve_response_url(&self, server: &Server) -> CompactString {
|
||||
pub async fn resolve_response_url(&self, server: &Server) -> String {
|
||||
server
|
||||
.eval_if(
|
||||
&server.core.network.http_response_url,
|
||||
|
|
@ -27,7 +27,7 @@ impl<'x> HttpContext<'x> {
|
|||
)
|
||||
.await
|
||||
.unwrap_or_else(|| {
|
||||
format_compact!(
|
||||
format!(
|
||||
"http{}://{}:{}",
|
||||
if self.session.is_tls { "s" } else { "" },
|
||||
self.session.local_ip,
|
||||
|
|
@ -67,12 +67,8 @@ impl ResolveVariable for HttpContext<'_> {
|
|||
.iter()
|
||||
.map(|(h, v)| {
|
||||
Variable::String(
|
||||
CompactString::new(format_compact!(
|
||||
"{}: {}",
|
||||
h.as_str(),
|
||||
v.to_str().unwrap_or_default()
|
||||
))
|
||||
.into(),
|
||||
format_compact!("{}: {}", h.as_str(), v.to_str().unwrap_or_default())
|
||||
.into(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
|
|
|
|||
|
|
@ -10,25 +10,24 @@ use common::{
|
|||
Server,
|
||||
auth::{AccessToken, oauth::oidc::Userinfo},
|
||||
};
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use http_proto::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct OpenIdMetadata {
|
||||
pub issuer: CompactString,
|
||||
pub authorization_endpoint: CompactString,
|
||||
pub token_endpoint: CompactString,
|
||||
pub userinfo_endpoint: CompactString,
|
||||
pub jwks_uri: CompactString,
|
||||
pub registration_endpoint: CompactString,
|
||||
pub scopes_supported: Vec<CompactString>,
|
||||
pub response_types_supported: Vec<CompactString>,
|
||||
pub subject_types_supported: Vec<CompactString>,
|
||||
pub grant_types_supported: Vec<CompactString>,
|
||||
pub id_token_signing_alg_values_supported: Vec<CompactString>,
|
||||
pub claims_supported: Vec<CompactString>,
|
||||
pub issuer: String,
|
||||
pub authorization_endpoint: String,
|
||||
pub token_endpoint: String,
|
||||
pub userinfo_endpoint: String,
|
||||
pub jwks_uri: String,
|
||||
pub registration_endpoint: String,
|
||||
pub scopes_supported: Vec<String>,
|
||||
pub response_types_supported: Vec<String>,
|
||||
pub subject_types_supported: Vec<String>,
|
||||
pub grant_types_supported: Vec<String>,
|
||||
pub id_token_signing_alg_values_supported: Vec<String>,
|
||||
pub claims_supported: Vec<String>,
|
||||
}
|
||||
|
||||
pub trait OpenIdHandler: Sync + Send {
|
||||
|
|
@ -50,7 +49,7 @@ impl OpenIdHandler for Server {
|
|||
access_token: &AccessToken,
|
||||
) -> trc::Result<HttpResponse> {
|
||||
Ok(JsonResponse::new(Userinfo {
|
||||
sub: Some(access_token.primary_id.to_compact_string()),
|
||||
sub: Some(access_token.primary_id.to_string()),
|
||||
name: access_token.description.clone(),
|
||||
preferred_username: Some(access_token.name.clone()),
|
||||
email: access_token.emails.first().cloned(),
|
||||
|
|
@ -71,11 +70,11 @@ impl OpenIdHandler for Server {
|
|||
.await;
|
||||
|
||||
Ok(JsonResponse::new(OpenIdMetadata {
|
||||
authorization_endpoint: format_compact!("{base_url}/authorize/code",),
|
||||
token_endpoint: format_compact!("{base_url}/auth/token"),
|
||||
userinfo_endpoint: format_compact!("{base_url}/auth/userinfo"),
|
||||
jwks_uri: format_compact!("{base_url}/auth/jwks.json"),
|
||||
registration_endpoint: format_compact!("{base_url}/auth/register"),
|
||||
authorization_endpoint: format!("{base_url}/authorize/code",),
|
||||
token_endpoint: format!("{base_url}/auth/token"),
|
||||
userinfo_endpoint: format!("{base_url}/auth/userinfo"),
|
||||
jwks_uri: format!("{base_url}/auth/jwks.json"),
|
||||
registration_endpoint: format!("{base_url}/auth/register"),
|
||||
response_types_supported: vec![
|
||||
"code".into(),
|
||||
"id_token".into(),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use common::{
|
|||
Server,
|
||||
auth::oauth::registration::{ClientRegistrationRequest, ClientRegistrationResponse},
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::{
|
||||
Permission, QueryBy, Type,
|
||||
backend::internal::{
|
||||
|
|
@ -70,7 +70,7 @@ impl ClientRegistrationHandler for Server {
|
|||
.sample_iter(Alphanumeric)
|
||||
.take(20)
|
||||
.map(|ch| char::from(ch.to_ascii_lowercase()))
|
||||
.collect::<CompactString>();
|
||||
.collect::<String>();
|
||||
self.store()
|
||||
.create_principal(
|
||||
PrincipalSet::new(u32::MAX, Type::OauthClient)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use common::{
|
|||
oauth::{GrantType, oidc::StandardClaims},
|
||||
},
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use hyper::StatusCode;
|
||||
use std::future::Future;
|
||||
use store::{
|
||||
|
|
@ -45,8 +45,8 @@ pub trait TokenHandler: Sync + Send {
|
|||
&self,
|
||||
account_id: u32,
|
||||
client_id: &str,
|
||||
issuer: CompactString,
|
||||
nonce: Option<CompactString>,
|
||||
issuer: String,
|
||||
nonce: Option<String>,
|
||||
with_refresh_token: bool,
|
||||
with_id_token: bool,
|
||||
) -> impl Future<Output = trc::Result<OAuthResponse>> + Send;
|
||||
|
|
@ -289,8 +289,8 @@ impl TokenHandler for Server {
|
|||
&self,
|
||||
account_id: u32,
|
||||
client_id: &str,
|
||||
issuer: CompactString,
|
||||
nonce: Option<CompactString>,
|
||||
issuer: String,
|
||||
nonce: Option<String>,
|
||||
with_refresh_token: bool,
|
||||
with_id_token: bool,
|
||||
) -> trc::Result<OAuthResponse> {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use common::{Server, manager::webadmin::Resource};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::QueryBy;
|
||||
use quick_xml::Reader;
|
||||
use quick_xml::events::Event;
|
||||
|
|
@ -29,7 +29,7 @@ pub trait Autoconfig: Sync + Send {
|
|||
fn autoconfig_parameters<'x>(
|
||||
&self,
|
||||
emailaddress: &'x str,
|
||||
) -> impl Future<Output = trc::Result<(CompactString, CompactString, &'x str)>> + Send;
|
||||
) -> impl Future<Output = trc::Result<(String, String, &'x str)>> + Send;
|
||||
}
|
||||
|
||||
impl Autoconfig for Server {
|
||||
|
|
@ -177,7 +177,7 @@ impl Autoconfig for Server {
|
|||
async fn autoconfig_parameters<'x>(
|
||||
&self,
|
||||
emailaddress: &'x str,
|
||||
) -> trc::Result<(CompactString, CompactString, &'x str)> {
|
||||
) -> trc::Result<(String, String, &'x str)> {
|
||||
let (_, domain) = emailaddress.rsplit_once('@').ok_or_else(|| {
|
||||
trc::ResourceEvent::BadParameters
|
||||
.into_err()
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use common::{
|
|||
config::network::{ContactForm, FieldOrDefault},
|
||||
ip_to_bytes, psl,
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use email::message::delivery::{IngestMessage, LocalDeliveryStatus, MailDelivery};
|
||||
use hyper::StatusCode;
|
||||
use mail_auth::common::cache::NoCache;
|
||||
|
|
@ -86,8 +86,10 @@ impl FormHandler for Server {
|
|||
}
|
||||
|
||||
// Obtain fields
|
||||
let from_email =
|
||||
CompactString::from_str_to_lowercase(form_data.get_or_default(&form.from_email).trim());
|
||||
let from_email = form_data
|
||||
.get_or_default(&form.from_email)
|
||||
.trim()
|
||||
.to_lowercase();
|
||||
let from_subject = form_data.get_or_default(&form.from_subject).trim();
|
||||
let from_name = form_data.get_or_default(&form.from_name).trim();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use common::{KV_BAYES_MODEL_USER, Server, auth::AccessToken};
|
||||
use compact_str::{CompactString, format_compact};
|
||||
use directory::{
|
||||
DirectoryInner, Permission, QueryBy, Type,
|
||||
backend::internal::{
|
||||
|
|
@ -19,35 +16,23 @@ use directory::{
|
|||
},
|
||||
},
|
||||
};
|
||||
|
||||
use http_proto::{request::decode_path_element, *};
|
||||
use hyper::{Method, header};
|
||||
use serde_json::json;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use trc::AddContext;
|
||||
use utils::url_params::UrlParams;
|
||||
|
||||
use http_proto::{request::decode_path_element, *};
|
||||
use std::future::Future;
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum AccountAuthRequest {
|
||||
SetPassword {
|
||||
password: CompactString,
|
||||
},
|
||||
EnableOtpAuth {
|
||||
url: CompactString,
|
||||
},
|
||||
DisableOtpAuth {
|
||||
url: Option<CompactString>,
|
||||
},
|
||||
AddAppPassword {
|
||||
name: CompactString,
|
||||
password: CompactString,
|
||||
},
|
||||
RemoveAppPassword {
|
||||
name: Option<CompactString>,
|
||||
},
|
||||
SetPassword { password: String },
|
||||
EnableOtpAuth { url: String },
|
||||
DisableOtpAuth { url: Option<String> },
|
||||
AddAppPassword { name: String, password: String },
|
||||
RemoveAppPassword { name: Option<String> },
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
|
|
@ -55,7 +40,7 @@ pub struct AccountAuthResponse {
|
|||
#[serde(rename = "otpEnabled")]
|
||||
pub otp_auth: bool,
|
||||
#[serde(rename = "appPasswords")]
|
||||
pub app_passwords: Vec<CompactString>,
|
||||
pub app_passwords: Vec<String>,
|
||||
}
|
||||
|
||||
pub trait PrincipalManager: Sync + Send {
|
||||
|
|
@ -818,7 +803,7 @@ impl PrincipalManager for Server {
|
|||
actions.push(PrincipalUpdate {
|
||||
action: PrincipalAction::RemoveItem,
|
||||
field: PrincipalField::Secrets,
|
||||
value: PrincipalValue::String(CompactString::new("")),
|
||||
value: PrincipalValue::String(String::new()),
|
||||
});
|
||||
|
||||
(PrincipalAction::AddItem, password)
|
||||
|
|
@ -828,13 +813,12 @@ impl PrincipalManager for Server {
|
|||
PrincipalAction::RemoveItem,
|
||||
url.unwrap_or_else(|| "otpauth://".into()),
|
||||
),
|
||||
AccountAuthRequest::AddAppPassword { name, password } => (
|
||||
PrincipalAction::AddItem,
|
||||
format_compact!("$app${name}${password}"),
|
||||
),
|
||||
AccountAuthRequest::AddAppPassword { name, password } => {
|
||||
(PrincipalAction::AddItem, format!("$app${name}${password}"))
|
||||
}
|
||||
AccountAuthRequest::RemoveAppPassword { name } => (
|
||||
PrincipalAction::RemoveItem,
|
||||
format_compact!("$app${}", name.unwrap_or_default()),
|
||||
format!("$app${}", name.unwrap_or_default()),
|
||||
),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{future::Future, sync::atomic::Ordering};
|
|||
|
||||
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use common::{Server, auth::AccessToken, ipc::QueueEvent};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::{Permission, Type, backend::internal::manage::ManageDirectory};
|
||||
use hyper::Method;
|
||||
use mail_auth::{
|
||||
|
|
@ -134,7 +134,7 @@ impl QueueManagement for Server {
|
|||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Limit to tenant domains
|
||||
let mut tenant_domains: Option<Vec<CompactString>> = None;
|
||||
let mut tenant_domains: Option<Vec<String>> = None;
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.core.is_enterprise_edition() {
|
||||
if let Some(tenant) = access_token.tenant {
|
||||
|
|
@ -466,7 +466,7 @@ impl QueueManagement for Server {
|
|||
match report_id {
|
||||
QueueClass::DmarcReportHeader(event)
|
||||
if tenant_domains.as_ref().is_none_or(|domains| {
|
||||
domains.iter().any(|dd| dd == event.domain)
|
||||
domains.iter().any(|dd| dd == &event.domain)
|
||||
}) =>
|
||||
{
|
||||
let mut rua = Vec::new();
|
||||
|
|
@ -479,7 +479,7 @@ impl QueueManagement for Server {
|
|||
}
|
||||
QueueClass::TlsReportHeader(event)
|
||||
if tenant_domains.as_ref().is_none_or(|domains| {
|
||||
domains.iter().any(|dd| dd == event.domain)
|
||||
domains.iter().any(|dd| dd == &event.domain)
|
||||
}) =>
|
||||
{
|
||||
let mut rua = Vec::new();
|
||||
|
|
@ -539,7 +539,7 @@ impl QueueManagement for Server {
|
|||
let result = match report_id {
|
||||
QueueClass::DmarcReportHeader(event)
|
||||
if tenant_domains.as_ref().is_none_or(|domains| {
|
||||
domains.iter().any(|dd| dd == event.domain)
|
||||
domains.iter().any(|dd| dd == &event.domain)
|
||||
}) =>
|
||||
{
|
||||
self.delete_dmarc_report(event).await;
|
||||
|
|
@ -547,7 +547,7 @@ impl QueueManagement for Server {
|
|||
}
|
||||
QueueClass::TlsReportHeader(event)
|
||||
if tenant_domains.as_ref().is_none_or(|domains| {
|
||||
domains.iter().any(|dd| dd == event.domain)
|
||||
domains.iter().any(|dd| dd == &event.domain)
|
||||
}) =>
|
||||
{
|
||||
self.delete_tls_report(vec![event]).await;
|
||||
|
|
@ -668,7 +668,7 @@ struct QueuedMessages {
|
|||
async fn fetch_queued_messages(
|
||||
server: &Server,
|
||||
params: &UrlParams<'_>,
|
||||
tenant_domains: &Option<Vec<CompactString>>,
|
||||
tenant_domains: &Option<Vec<String>>,
|
||||
) -> trc::Result<QueuedMessages> {
|
||||
let text = params.get("text");
|
||||
let from = params.get("from");
|
||||
|
|
@ -774,7 +774,7 @@ struct QueuedReports {
|
|||
async fn fetch_queued_reports(
|
||||
server: &Server,
|
||||
params: &UrlParams<'_>,
|
||||
tenant_domains: &Option<Vec<CompactString>>,
|
||||
tenant_domains: &Option<Vec<String>>,
|
||||
) -> trc::Result<QueuedReports> {
|
||||
let domain = params.get("domain").map(|d| d.to_lowercase());
|
||||
let type_ = params.get("type").and_then(|t| match t {
|
||||
|
|
@ -823,7 +823,7 @@ async fn fetch_queued_reports(
|
|||
let event = ReportEvent::deserialize(key)?;
|
||||
if tenant_domains
|
||||
.as_ref()
|
||||
.is_none_or(|domains| domains.iter().any(|dd| dd == event.domain))
|
||||
.is_none_or(|domains| domains.iter().any(|dd| dd == &event.domain))
|
||||
&& event.seq_id != 0
|
||||
&& domain.as_ref().is_none_or(|d| event.domain.contains(d))
|
||||
{
|
||||
|
|
@ -964,10 +964,10 @@ fn is_zero(num: &i16) -> bool {
|
|||
}
|
||||
|
||||
trait IsTenantDomain {
|
||||
fn is_tenant_domain(&self, tenant_domains: &Option<Vec<CompactString>>) -> bool;
|
||||
fn is_tenant_domain(&self, tenant_domains: &Option<Vec<String>>) -> bool;
|
||||
}
|
||||
impl IsTenantDomain for ArchivedMessage {
|
||||
fn is_tenant_domain(&self, tenant_domains: &Option<Vec<CompactString>>) -> bool {
|
||||
fn is_tenant_domain(&self, tenant_domains: &Option<Vec<String>>) -> bool {
|
||||
tenant_domains
|
||||
.as_ref()
|
||||
.is_none_or(|domains| self.has_domain(domains))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
use std::future::Future;
|
||||
|
||||
use common::{Server, auth::AccessToken};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::{Permission, Type, backend::internal::manage::ManageDirectory};
|
||||
use hyper::Method;
|
||||
use mail_auth::report::{
|
||||
|
|
@ -52,7 +52,7 @@ impl ManageReports for Server {
|
|||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Limit to tenant domains
|
||||
let mut tenant_domains: Option<Vec<CompactString>> = None;
|
||||
let mut tenant_domains: Option<Vec<String>> = None;
|
||||
#[cfg(feature = "enterprise")]
|
||||
if self.core.is_enterprise_edition() {
|
||||
if let Some(tenant) = access_token.tenant {
|
||||
|
|
@ -297,7 +297,7 @@ async fn fetch_incoming_reports(
|
|||
server: &Server,
|
||||
class: &str,
|
||||
params: &UrlParams<'_>,
|
||||
tenant_domains: &Option<Vec<CompactString>>,
|
||||
tenant_domains: &Option<Vec<String>>,
|
||||
) -> trc::Result<IncomingReports> {
|
||||
let filter = params.get("text");
|
||||
let page: usize = params.parse::<usize>("page").unwrap_or_default();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
use std::net::IpAddr;
|
||||
|
||||
use common::{Server, auth::AccessToken, config::spamfilter::SpamFilterAction, psl};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use directory::{
|
||||
Permission,
|
||||
|
|
|
|||
|
|
@ -233,10 +233,7 @@ impl ParseHttp for Server {
|
|||
self.authenticate_headers(&req, &session, false).await?;
|
||||
|
||||
return self
|
||||
.handle_session_resource(
|
||||
ctx.resolve_response_url(self).await.into(),
|
||||
access_token,
|
||||
)
|
||||
.handle_session_resource(ctx.resolve_response_url(self).await, access_token)
|
||||
.await
|
||||
.map(|s| s.into_http_response());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
|
|
@ -43,17 +45,17 @@ impl Request<Command> {
|
|||
let mailbox_name = utf7_maybe_decode(
|
||||
tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing mailbox name."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing mailbox name."))?
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
);
|
||||
let identifier = if has_identifier {
|
||||
tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing identifier."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing identifier."))?
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
.into()
|
||||
} else {
|
||||
None
|
||||
|
|
@ -62,10 +64,10 @@ impl Request<Command> {
|
|||
ModRights::parse(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing rights."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing rights."))?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
.into()
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
|
|
@ -35,7 +37,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
);
|
||||
let mut messages = Vec::new();
|
||||
|
|
@ -61,7 +63,7 @@ impl Request<Command> {
|
|||
State::UTF8 => State::UTF8Data,
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid opening parenthesis found.",
|
||||
));
|
||||
}
|
||||
|
|
@ -70,7 +72,7 @@ impl Request<Command> {
|
|||
Token::ParenthesisClose => match state {
|
||||
State::None | State::UTF8 => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid closing parenthesis found.",
|
||||
));
|
||||
}
|
||||
|
|
@ -93,7 +95,7 @@ impl Request<Command> {
|
|||
message.received_at = Some(date_time);
|
||||
} else {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Failed to parse received time.",
|
||||
));
|
||||
}
|
||||
|
|
@ -105,12 +107,12 @@ impl Request<Command> {
|
|||
State::Flags => {
|
||||
message.flags.push(
|
||||
Flag::parse_imap(value)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
State::UTF8 => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Expected parenthesis after UTF8.",
|
||||
));
|
||||
}
|
||||
|
|
@ -119,13 +121,13 @@ impl Request<Command> {
|
|||
message.message = value;
|
||||
} else {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid parameter after message literal.",
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => return Err(bad(self.tag.to_string(), "Invalid arguments.")),
|
||||
_ => return Err(bad(self.tag.to_compact_string(), "Invalid arguments.")),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::authenticate::{self, Mechanism},
|
||||
|
|
@ -16,7 +18,7 @@ impl Request<Command> {
|
|||
let mut tokens = self.tokens.into_iter();
|
||||
Ok(authenticate::Arguments {
|
||||
mechanism: Mechanism::parse(&tokens.next().unwrap().unwrap_bytes())
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
params: tokens
|
||||
.filter_map(|token| token.unwrap_string().ok())
|
||||
.collect(),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{ProtocolVersion, copy_move},
|
||||
|
|
@ -22,16 +24,16 @@ impl Request<Command> {
|
|||
sequence_set: parse_sequence_set(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing sequence set."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing sequence set."))?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
mailbox_name: utf7_maybe_decode(
|
||||
tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing mailbox name."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing mailbox name."))?
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
tag: self.tag,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{ProtocolVersion, create, list::Attribute},
|
||||
|
|
@ -20,21 +22,27 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
);
|
||||
let mailbox_role = if let Some(Token::ParenthesisOpen) = tokens.next() {
|
||||
match tokens.next() {
|
||||
Some(Token::Argument(param)) if param.eq_ignore_ascii_case(b"USE") => (),
|
||||
_ => {
|
||||
return Err(bad(self.tag, "Failed to parse, expected 'USE'."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Failed to parse, expected 'USE'.",
|
||||
));
|
||||
}
|
||||
}
|
||||
if tokens
|
||||
.next()
|
||||
.is_none_or(|token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(self.tag, "Expected '(' after 'USE'."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected '(' after 'USE'.",
|
||||
));
|
||||
}
|
||||
match tokens.next() {
|
||||
Some(Token::Argument(value)) => {
|
||||
|
|
@ -52,14 +60,14 @@ impl Request<Command> {
|
|||
Some(Some(tag)) => Some(tag),
|
||||
Some(None) => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"A mailbox with the \"\\All\" attribute already exists.",
|
||||
));
|
||||
}
|
||||
None => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!(
|
||||
"Special use attribute {:?} is not supported.",
|
||||
String::from_utf8_lossy(&value)
|
||||
),
|
||||
|
|
@ -68,7 +76,10 @@ impl Request<Command> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(self.tag, "Invalid SPECIAL-USE attribute."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Invalid SPECIAL-USE attribute.",
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{ProtocolVersion, delete},
|
||||
|
|
@ -21,7 +23,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
tag: self.tag,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{capability::Capability, enable},
|
||||
|
|
@ -18,7 +20,7 @@ impl Request<Command> {
|
|||
for capability in self.tokens {
|
||||
capabilities.push(
|
||||
Capability::parse(&capability.unwrap_bytes())
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
Ok(enable::Arguments {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::borrow::Cow;
|
|||
use std::iter::Peekable;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use compact_str::CompactString;
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
|
|
@ -30,10 +30,10 @@ impl Request<Command> {
|
|||
let sequence_set = parse_sequence_set(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing sequence set."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing sequence set."))?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
|
||||
let mut in_parentheses = false;
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ impl Request<Command> {
|
|||
let rfc822 = tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(self.tag.to_string(), "Missing RFC822 parameter.")
|
||||
bad(self.tag.to_compact_string(), "Missing RFC822 parameter.")
|
||||
})?
|
||||
.unwrap_bytes();
|
||||
if rfc822.eq_ignore_ascii_case(b"HEADER") {
|
||||
|
|
@ -101,8 +101,8 @@ impl Request<Command> {
|
|||
Attribute::Rfc822Text
|
||||
} else {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!(
|
||||
"Invalid RFC822 parameter {:?}.",
|
||||
String::from_utf8_lossy(&rfc822)
|
||||
),
|
||||
|
|
@ -126,13 +126,13 @@ impl Request<Command> {
|
|||
.is_none_or( |token| !token.eq_ignore_ascii_case(b"PEEK"))
|
||||
{
|
||||
return Err(bad(
|
||||
self.tag.clone(),
|
||||
self.tag.to_compact_string(),
|
||||
"Expected 'PEEK' after '.'.",
|
||||
));
|
||||
}
|
||||
if tokens.next().is_none_or( |token| !token.is_bracket_open()) {
|
||||
return Err(bad(
|
||||
self.tag.clone(),
|
||||
self.tag.to_compact_string(),
|
||||
"Expected '[' after 'BODY.PEEK'",
|
||||
));
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ impl Request<Command> {
|
|||
!token.eq_ignore_ascii_case(b"FIELDS")
|
||||
}) {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected 'FIELDS' after 'HEADER.'.",
|
||||
));
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ impl Request<Command> {
|
|||
!token.eq_ignore_ascii_case(b"NOT")
|
||||
}) {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected 'NOT' after 'HEADER.FIELDS.'.",
|
||||
));
|
||||
}
|
||||
|
|
@ -185,7 +185,7 @@ impl Request<Command> {
|
|||
.is_none_or( |token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected '(' after 'HEADER.FIELDS'.",
|
||||
));
|
||||
}
|
||||
|
|
@ -194,13 +194,13 @@ impl Request<Command> {
|
|||
match token {
|
||||
Token::ParenthesisClose => break,
|
||||
Token::Argument(value) => {
|
||||
fields.push(CompactString::from_utf8(value).map_err(
|
||||
|_| bad(self.tag.clone(), "Invalid UTF-8 in header field name."),
|
||||
fields.push(String::from_utf8(value).map_err(
|
||||
|_| bad(self.tag.to_compact_string(),"Invalid UTF-8 in header field name."),
|
||||
)?);
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected field name.",
|
||||
))
|
||||
}
|
||||
|
|
@ -220,7 +220,7 @@ impl Request<Command> {
|
|||
} else {
|
||||
Section::Part {
|
||||
num: parse_number::<u32>(&value)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
}
|
||||
};
|
||||
sections.push(section);
|
||||
|
|
@ -228,8 +228,8 @@ impl Request<Command> {
|
|||
Token::Dot => (),
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!(
|
||||
"Invalid token {:?} found in section-spect.",
|
||||
token
|
||||
),
|
||||
|
|
@ -242,7 +242,7 @@ impl Request<Command> {
|
|||
peek: is_peek,
|
||||
sections,
|
||||
partial: parse_partial(&mut tokens)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
});
|
||||
},
|
||||
"BINARY" => {
|
||||
|
|
@ -251,7 +251,7 @@ impl Request<Command> {
|
|||
let param = tokens
|
||||
.next()
|
||||
.ok_or({
|
||||
bad(self.tag.clone(), "Missing parameter after 'BINARY.'.")
|
||||
bad(self.tag.to_compact_string(),"Missing parameter after 'BINARY.'.")
|
||||
})?
|
||||
.unwrap_bytes();
|
||||
if param.eq_ignore_ascii_case(b"PEEK") {
|
||||
|
|
@ -260,7 +260,7 @@ impl Request<Command> {
|
|||
(false, true)
|
||||
} else {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected 'PEEK' or 'SIZE' after 'BINARY.'.",
|
||||
));
|
||||
}
|
||||
|
|
@ -270,7 +270,7 @@ impl Request<Command> {
|
|||
|
||||
// Parse section-part
|
||||
if tokens.next().is_none_or( |token| !token.is_bracket_open()) {
|
||||
return Err(bad(self.tag.to_string(), "Expected '[' after 'BINARY'."));
|
||||
return Err(bad(self.tag.to_compact_string(), "Expected '[' after 'BINARY'."));
|
||||
}
|
||||
let mut sections = Vec::new();
|
||||
while let Some(token) = tokens.next() {
|
||||
|
|
@ -278,15 +278,15 @@ impl Request<Command> {
|
|||
Token::Argument(value) => {
|
||||
sections.push(
|
||||
parse_number::<u32>(&value)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
Token::Dot => (),
|
||||
Token::BracketClose => break,
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!(
|
||||
"Expected part section integer, got {:?}.",
|
||||
token.to_string()
|
||||
),
|
||||
|
|
@ -299,7 +299,7 @@ impl Request<Command> {
|
|||
peek: is_peek,
|
||||
sections,
|
||||
partial: parse_partial(&mut tokens)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
}
|
||||
} else {
|
||||
Attribute::BinarySize { sections }
|
||||
|
|
@ -338,8 +338,8 @@ impl Request<Command> {
|
|||
},
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!("Invalid attribute {:?}", String::from_utf8_lossy(&value)),
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!("Invalid attribute {:?}", String::from_utf8_lossy(&value)),
|
||||
));
|
||||
}
|
||||
);
|
||||
|
|
@ -352,20 +352,26 @@ impl Request<Command> {
|
|||
if !in_parentheses {
|
||||
in_parentheses = true;
|
||||
} else {
|
||||
return Err(bad(self.tag.to_string(), "Unexpected parenthesis open."));
|
||||
return Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Unexpected parenthesis open.",
|
||||
));
|
||||
}
|
||||
}
|
||||
Token::ParenthesisClose => {
|
||||
if in_parentheses {
|
||||
break;
|
||||
} else {
|
||||
return Err(bad(self.tag.to_string(), "Unexpected parenthesis close."));
|
||||
return Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Unexpected parenthesis close.",
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!("Invalid fetch argument {:?}.", token.to_string()),
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!("Invalid fetch argument {:?}.", token.to_string()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -383,11 +389,14 @@ impl Request<Command> {
|
|||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(self.tag.to_string(), "Missing CHANGEDSINCE parameter.")
|
||||
bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Missing CHANGEDSINCE parameter.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
.into();
|
||||
}
|
||||
Token::Argument(param) if param.eq_ignore_ascii_case(b"VANISHED") => {
|
||||
|
|
@ -398,8 +407,8 @@ impl Request<Command> {
|
|||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.clone(),
|
||||
format!("Unsupported parameter '{}'.", token.to_string()),
|
||||
self.tag.to_compact_string(),
|
||||
format_compact!("Unsupported parameter '{}'.", token),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -415,7 +424,10 @@ impl Request<Command> {
|
|||
include_vanished,
|
||||
})
|
||||
} else {
|
||||
Err(bad(self.tag, "No data items to fetch specified."))
|
||||
Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"No data items to fetch specified.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::{CompactString, ToCompactString};
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
|
|
@ -27,13 +29,13 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
mailbox_name: utf7_maybe_decode(
|
||||
tokens
|
||||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
tag: self.tag,
|
||||
|
|
@ -53,12 +55,12 @@ impl Request<Command> {
|
|||
Token::Argument(value) => {
|
||||
selection_options.push(
|
||||
SelectionOption::parse(&value)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid selection option argument.",
|
||||
));
|
||||
}
|
||||
|
|
@ -66,18 +68,20 @@ impl Request<Command> {
|
|||
}
|
||||
tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing reference name."))?
|
||||
.ok_or_else(|| {
|
||||
bad(self.tag.to_compact_string(), "Missing reference name.")
|
||||
})?
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
}
|
||||
token => token
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
};
|
||||
|
||||
match tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing mailbox name."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing mailbox name."))?
|
||||
{
|
||||
Token::ParenthesisOpen => {
|
||||
while let Some(token) = tokens.next() {
|
||||
|
|
@ -87,7 +91,7 @@ impl Request<Command> {
|
|||
mailbox_name.push(
|
||||
token
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +101,7 @@ impl Request<Command> {
|
|||
mailbox_name.push(utf7_maybe_decode(
|
||||
token
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
));
|
||||
}
|
||||
|
|
@ -112,7 +116,7 @@ impl Request<Command> {
|
|||
.is_none_or(|token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid return option, expected parenthesis.",
|
||||
));
|
||||
}
|
||||
|
|
@ -122,14 +126,14 @@ impl Request<Command> {
|
|||
Token::ParenthesisClose => break,
|
||||
Token::Argument(value) => {
|
||||
let mut return_option = ReturnOption::parse(&value)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
if let ReturnOption::Status(status) = &mut return_option {
|
||||
if tokens
|
||||
.next()
|
||||
.is_none_or(|token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Invalid return option, expected parenthesis after STATUS.",
|
||||
));
|
||||
}
|
||||
|
|
@ -137,15 +141,13 @@ impl Request<Command> {
|
|||
match token {
|
||||
Token::ParenthesisClose => break,
|
||||
Token::Argument(value) => {
|
||||
status.push(
|
||||
Status::parse(&value).map_err(|v| {
|
||||
bad(self.tag.to_string(), v)
|
||||
})?,
|
||||
);
|
||||
status.push(Status::parse(&value).map_err(
|
||||
|v| bad(self.tag.to_compact_string(), v),
|
||||
)?);
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Invalid status return option argument.",
|
||||
));
|
||||
}
|
||||
|
|
@ -156,7 +158,7 @@ impl Request<Command> {
|
|||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid return option argument.",
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::login,
|
||||
|
|
@ -20,12 +22,12 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
password: tokens
|
||||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
tag: self.tag,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
|
|
@ -22,15 +24,15 @@ impl Request<Command> {
|
|||
Ok(list::Arguments::Extended {
|
||||
reference_name: tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing reference name."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing reference name."))?
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
mailbox_name: vec![utf7_maybe_decode(
|
||||
tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing mailbox name."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing mailbox name."))?
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
ProtocolVersion::Rev1,
|
||||
)],
|
||||
selection_options: vec![SelectionOption::Subscribed],
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ pub mod thread;
|
|||
use std::{borrow::Cow, str::FromStr};
|
||||
|
||||
use chrono::{DateTime, NaiveDate};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
|
|
@ -112,7 +111,7 @@ impl Flag {
|
|||
if let Some(flag) = flag {
|
||||
Ok(flag)
|
||||
} else {
|
||||
CompactString::from_utf8(value)
|
||||
String::from_utf8(value)
|
||||
.map_err(|_| Cow::from("Invalid UTF-8."))
|
||||
.map(Flag::Keyword)
|
||||
}
|
||||
|
|
@ -137,9 +136,9 @@ impl Flag {
|
|||
"$forwarded" => Flag::Forwarded,
|
||||
"$mdnsent" => Flag::MDNSent,
|
||||
)
|
||||
.unwrap_or_else(|| Flag::Keyword(value.into()))
|
||||
.unwrap_or_else(|| Flag::Keyword(value))
|
||||
} else {
|
||||
let mut keyword = CompactString::with_capacity(value.len());
|
||||
let mut keyword = String::with_capacity(value.len());
|
||||
for c in value.chars() {
|
||||
if c.is_ascii_alphanumeric() {
|
||||
keyword.push(c);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{ProtocolVersion, quota},
|
||||
|
|
@ -21,7 +23,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
tag: self.tag,
|
||||
|
|
@ -40,7 +42,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
tag: self.tag,
|
||||
}),
|
||||
0 => Err(self.into_error("Missing quota root.")),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{ProtocolVersion, rename},
|
||||
|
|
@ -22,7 +24,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
new_mailbox_name: utf7_maybe_decode(
|
||||
|
|
@ -30,7 +32,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
tag: self.tag,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::borrow::Cow;
|
|||
use std::iter::Peekable;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use compact_str::CompactString;
|
||||
use compact_str::ToCompactString;
|
||||
use mail_parser::decoders::charsets::DecoderFnc;
|
||||
use mail_parser::decoders::charsets::map::charset_decoder;
|
||||
|
||||
|
|
@ -38,14 +38,14 @@ impl Request<Command> {
|
|||
tokens.next();
|
||||
is_esearch = true;
|
||||
result_options = parse_result_options(&mut tokens)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
}
|
||||
Some(Token::Argument(value)) if value.eq_ignore_ascii_case(b"charset") => {
|
||||
tokens.next();
|
||||
decoder = charset_decoder(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing charset."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing charset."))?
|
||||
.unwrap_bytes(),
|
||||
);
|
||||
}
|
||||
|
|
@ -53,11 +53,14 @@ impl Request<Command> {
|
|||
}
|
||||
}
|
||||
|
||||
let filter =
|
||||
parse_filters(&mut tokens, decoder).map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
let filter = parse_filters(&mut tokens, decoder)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
|
||||
match filter.len() {
|
||||
0 => Err(bad(self.tag.to_string(), "No filters found in command.")),
|
||||
0 => Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
"No filters found in command.",
|
||||
)),
|
||||
_ => Ok(search::Arguments {
|
||||
tag: self.tag,
|
||||
result_options,
|
||||
|
|
@ -374,7 +377,7 @@ pub fn parse_filters(
|
|||
}
|
||||
Some(token) => {
|
||||
return Err(
|
||||
format!("Unsupported MODSEQ parameter '{}'.", token.to_string()).into()
|
||||
format!("Unsupported MODSEQ parameter '{}'.", token).into()
|
||||
);
|
||||
}
|
||||
None => {
|
||||
|
|
@ -500,16 +503,16 @@ pub fn parse_filters(
|
|||
pub fn decode_argument(
|
||||
tokens: &mut Peekable<IntoIter<Token>>,
|
||||
decoder: Option<DecoderFnc>,
|
||||
) -> super::Result<CompactString> {
|
||||
) -> super::Result<String> {
|
||||
let argument = tokens
|
||||
.next()
|
||||
.ok_or_else(|| Cow::from("Expected string."))?
|
||||
.unwrap_bytes();
|
||||
|
||||
if let Some(decoder) = decoder {
|
||||
Ok(decoder(&argument).into())
|
||||
Ok(decoder(&argument))
|
||||
} else {
|
||||
Ok(CompactString::from_utf8(argument).map_err(|_| Cow::from("Invalid UTF-8 argument."))?)
|
||||
Ok(String::from_utf8(argument).map_err(|_| Cow::from("Invalid UTF-8 argument."))?)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
|
|
@ -27,7 +29,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
);
|
||||
|
||||
|
|
@ -46,7 +48,10 @@ impl Request<Command> {
|
|||
.next()
|
||||
.is_none_or(|token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(self.tag, "Expected '(' after 'QRESYNC'."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Expected '(' after 'QRESYNC'.",
|
||||
));
|
||||
}
|
||||
|
||||
let uid_validity = parse_number::<u32>(
|
||||
|
|
@ -54,32 +59,32 @@ impl Request<Command> {
|
|||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Missing uidvalidity parameter for QRESYNC.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
let modseq = parse_number::<u64>(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Missing modseq parameter for QRESYNC.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
|
||||
let mut known_uids = None;
|
||||
let mut seq_match = None;
|
||||
let has_seq_match = match tokens.peek() {
|
||||
Some(Token::Argument(value)) => {
|
||||
known_uids = parse_sequence_set(value)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
.into();
|
||||
tokens.next();
|
||||
if matches!(tokens.peek(), Some(Token::ParenthesisOpen)) {
|
||||
|
|
@ -103,31 +108,34 @@ impl Request<Command> {
|
|||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Missing known-sequence-set parameter for QRESYNC.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
parse_sequence_set(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Missing known-uid-set parameter for QRESYNC.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
));
|
||||
if tokens
|
||||
.next()
|
||||
.is_none_or(|token| !token.is_parenthesis_close())
|
||||
{
|
||||
return Err(bad(self.tag, "Missing ')' for 'QRESYNC'."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Missing ')' for 'QRESYNC'.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +143,10 @@ impl Request<Command> {
|
|||
.next()
|
||||
.is_none_or(|token| !token.is_parenthesis_close())
|
||||
{
|
||||
return Err(bad(self.tag, "Missing ')' for 'QRESYNC'."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Missing ')' for 'QRESYNC'.",
|
||||
));
|
||||
}
|
||||
|
||||
qresync = QResync {
|
||||
|
|
@ -151,8 +162,8 @@ impl Request<Command> {
|
|||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!("Unexpected value '{}'.", token.to_string()),
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!("Unexpected value '{}'.", token),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -160,8 +171,8 @@ impl Request<Command> {
|
|||
}
|
||||
Some(token) => {
|
||||
return Err(bad(
|
||||
self.tag,
|
||||
format!("Unexpected value '{}'.", token.to_string()),
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
format_compact!("Unexpected value '{}'.", token),
|
||||
));
|
||||
}
|
||||
None => (),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
use mail_parser::decoders::charsets::map::charset_decoder;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -28,7 +29,8 @@ impl Request<Command> {
|
|||
Some(Token::Argument(value)) if value.eq_ignore_ascii_case(b"return") => {
|
||||
tokens.next();
|
||||
(
|
||||
parse_result_options(&mut tokens).map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
parse_result_options(&mut tokens)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
|
@ -40,7 +42,7 @@ impl Request<Command> {
|
|||
.is_none_or(|token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Expected sort criteria between parentheses.",
|
||||
));
|
||||
}
|
||||
|
|
@ -54,31 +56,40 @@ impl Request<Command> {
|
|||
is_ascending = false;
|
||||
} else {
|
||||
sort.push(Comparator {
|
||||
sort: Sort::parse(&value).map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
sort: Sort::parse(&value)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
ascending: is_ascending,
|
||||
});
|
||||
is_ascending = true;
|
||||
}
|
||||
}
|
||||
_ => return Err(bad(self.tag.to_string(), "Invalid result option argument.")),
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid result option argument.",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sort.is_empty() {
|
||||
return Err(bad(self.tag.to_string(), "Missing sort criteria."));
|
||||
return Err(bad(self.tag.to_compact_string(), "Missing sort criteria."));
|
||||
}
|
||||
|
||||
let decoder = charset_decoder(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing charset."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing charset."))?
|
||||
.unwrap_bytes(),
|
||||
);
|
||||
|
||||
let filter =
|
||||
parse_filters(&mut tokens, decoder).map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
let filter = parse_filters(&mut tokens, decoder)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
match filter.len() {
|
||||
0 => Err(bad(self.tag.to_string(), "No filters found in command.")),
|
||||
0 => Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
"No filters found in command.",
|
||||
)),
|
||||
_ => Ok(Arguments {
|
||||
sort: sort.into(),
|
||||
result_options,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::{CompactString, ToCompactString};
|
||||
|
||||
use crate::Command;
|
||||
use crate::protocol::status::Status;
|
||||
use crate::protocol::{ProtocolVersion, status};
|
||||
|
|
@ -21,7 +23,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
);
|
||||
let mut items = Vec::with_capacity(len - 2);
|
||||
|
|
@ -31,7 +33,7 @@ impl Request<Command> {
|
|||
.is_none_or(|token| !token.is_parenthesis_open())
|
||||
{
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Expected parenthesis after mailbox name.",
|
||||
));
|
||||
}
|
||||
|
|
@ -42,12 +44,13 @@ impl Request<Command> {
|
|||
Token::ParenthesisClose => break,
|
||||
Token::Argument(value) => {
|
||||
items.push(
|
||||
Status::parse(&value).map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
Status::parse(&value)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
self.tag.to_compact_string(),
|
||||
"Invalid status return option argument.",
|
||||
));
|
||||
}
|
||||
|
|
@ -61,7 +64,10 @@ impl Request<Command> {
|
|||
items,
|
||||
})
|
||||
} else {
|
||||
Err(bad(self.tag, "At least one status item is required."))
|
||||
Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"At least one status item is required.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{
|
||||
|
|
@ -23,10 +25,10 @@ impl Request<Command> {
|
|||
let sequence_set = parse_sequence_set(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing sequence set."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing sequence set."))?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
let mut unchanged_since = None;
|
||||
|
||||
// CONDSTORE parameters
|
||||
|
|
@ -39,11 +41,14 @@ impl Request<Command> {
|
|||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
bad(self.tag.to_string(), "Missing UNCHANGEDSINCE parameter.")
|
||||
bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Missing UNCHANGEDSINCE parameter.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?
|
||||
.into();
|
||||
}
|
||||
Token::ParenthesisClose => {
|
||||
|
|
@ -51,8 +56,8 @@ impl Request<Command> {
|
|||
}
|
||||
_ => {
|
||||
return Err(bad(
|
||||
self.tag.to_string(),
|
||||
format!("Unsupported parameter '{}'.", token.to_string()),
|
||||
self.tag.to_compact_string(),
|
||||
format_compact!("Unsupported parameter '{}'.", token),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +67,12 @@ impl Request<Command> {
|
|||
// Operation
|
||||
let operation = tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing message data item name."))?
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_compact_string(),
|
||||
"Missing message data item name.",
|
||||
)
|
||||
})?
|
||||
.unwrap_bytes();
|
||||
let (is_silent, operation) = hashify::tiny_map_ignore_case!(operation.as_slice(),
|
||||
"FLAGS" => (false, Operation::Set),
|
||||
|
|
@ -74,8 +84,8 @@ impl Request<Command> {
|
|||
)
|
||||
.ok_or_else(|| {
|
||||
bad(
|
||||
self.tag.to_string(),
|
||||
format!(
|
||||
self.tag.to_compact_string(),
|
||||
format_compact!(
|
||||
"Unsupported message data item name: {:?}",
|
||||
String::from_utf8_lossy(&operation)
|
||||
),
|
||||
|
|
@ -86,30 +96,36 @@ impl Request<Command> {
|
|||
let mut keywords = Vec::new();
|
||||
match tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing flags to set."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing flags to set."))?
|
||||
{
|
||||
Token::ParenthesisOpen => {
|
||||
for token in tokens {
|
||||
match token {
|
||||
Token::Argument(flag) => {
|
||||
keywords.push(
|
||||
Flag::parse_imap(flag).map_err(|v| bad(self.tag.to_string(), v))?,
|
||||
Flag::parse_imap(flag)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
Token::ParenthesisClose => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(self.tag.to_string(), "Unsupported flag."));
|
||||
return Err(bad(self.tag.to_compact_string(), "Unsupported flag."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Token::Argument(flag) => {
|
||||
keywords.push(Flag::parse_imap(flag).map_err(|v| bad(self.tag.to_string(), v))?);
|
||||
keywords.push(
|
||||
Flag::parse_imap(flag).map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
return Err(bad(self.tag, "Invalid flags parameter."));
|
||||
return Err(bad(
|
||||
CompactString::from_string_buffer(self.tag),
|
||||
"Invalid flags parameter.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +139,7 @@ impl Request<Command> {
|
|||
unchanged_since,
|
||||
})
|
||||
} else {
|
||||
Err(bad(self.tag.to_string(), "Missing flags to set."))
|
||||
Err(bad(self.tag.to_compact_string(), "Missing flags to set."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
|
||||
use crate::{
|
||||
Command,
|
||||
protocol::{ProtocolVersion, subscribe},
|
||||
|
|
@ -21,7 +23,7 @@ impl Request<Command> {
|
|||
.next()
|
||||
.unwrap()
|
||||
.unwrap_string()
|
||||
.map_err(|v| bad(self.tag.clone(), v))?,
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?,
|
||||
version,
|
||||
),
|
||||
tag: self.tag,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
use mail_parser::decoders::charsets::map::charset_decoder;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -25,22 +26,25 @@ impl Request<Command> {
|
|||
let algorithm = Algorithm::parse(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing threading algorithm."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing threading algorithm."))?
|
||||
.unwrap_bytes(),
|
||||
)
|
||||
.map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
|
||||
let decoder = charset_decoder(
|
||||
&tokens
|
||||
.next()
|
||||
.ok_or_else(|| bad(self.tag.to_string(), "Missing charset."))?
|
||||
.ok_or_else(|| bad(self.tag.to_compact_string(), "Missing charset."))?
|
||||
.unwrap_bytes(),
|
||||
);
|
||||
|
||||
let filter =
|
||||
parse_filters(&mut tokens, decoder).map_err(|v| bad(self.tag.to_string(), v))?;
|
||||
let filter = parse_filters(&mut tokens, decoder)
|
||||
.map_err(|v| bad(self.tag.to_compact_string(), v))?;
|
||||
match filter.len() {
|
||||
0 => Err(bad(self.tag.to_string(), "No filters found in command.")),
|
||||
0 => Err(bad(
|
||||
self.tag.to_compact_string(),
|
||||
"No filters found in command.",
|
||||
)),
|
||||
_ => Ok(thread::Arguments {
|
||||
algorithm,
|
||||
filter,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
use std::fmt::Display;
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use jmap_proto::types::acl::Acl;
|
||||
|
||||
use crate::utf7::utf7_encode;
|
||||
|
|
@ -72,28 +72,28 @@ pub enum ModRightsOp {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub identifier: Option<CompactString>,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
pub identifier: Option<String>,
|
||||
pub mod_rights: Option<ModRights>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GetAclResponse {
|
||||
pub mailbox_name: CompactString,
|
||||
pub permissions: Vec<(CompactString, Vec<Rights>)>,
|
||||
pub mailbox_name: String,
|
||||
pub permissions: Vec<(String, Vec<Rights>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ListRightsResponse {
|
||||
pub mailbox_name: CompactString,
|
||||
pub identifier: CompactString,
|
||||
pub mailbox_name: String,
|
||||
pub identifier: String,
|
||||
pub permissions: Vec<Vec<Rights>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MyRightsResponse {
|
||||
pub mailbox_name: CompactString,
|
||||
pub mailbox_name: String,
|
||||
pub rights: Vec<Rights>,
|
||||
}
|
||||
|
||||
|
|
@ -249,14 +249,14 @@ impl From<Rights> for Acl {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use crate::protocol::acl::{GetAclResponse, ListRightsResponse, MyRightsResponse, Rights};
|
||||
|
||||
#[test]
|
||||
fn serialize_acl() {
|
||||
assert_eq!(
|
||||
CompactString::from_utf8(
|
||||
String::from_utf8(
|
||||
GetAclResponse {
|
||||
mailbox_name: "INBOX".into(),
|
||||
permissions: vec![
|
||||
|
|
@ -290,7 +290,7 @@ mod tests {
|
|||
);
|
||||
|
||||
assert_eq!(
|
||||
CompactString::from_utf8(
|
||||
String::from_utf8(
|
||||
ListRightsResponse {
|
||||
mailbox_name: "Deleted Items".into(),
|
||||
identifier: "Fred".into(),
|
||||
|
|
@ -307,7 +307,7 @@ mod tests {
|
|||
);
|
||||
|
||||
assert_eq!(
|
||||
CompactString::from_utf8(
|
||||
String::from_utf8(
|
||||
MyRightsResponse {
|
||||
mailbox_name: "Important".into(),
|
||||
rights: vec![Rights::Lookup, Rights::Read, Rights::DeleteMailbox]
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::Flag;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
pub messages: Vec<Message>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub mechanism: Mechanism,
|
||||
pub params: Vec<CompactString>,
|
||||
pub params: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::Sequence;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub sequence_set: Sequence,
|
||||
pub mailbox_name: CompactString,
|
||||
pub mailbox_name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::list::Attribute;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
pub mailbox_role: Option<Attribute>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::{ImapResponse, capability::Capability};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub capabilities: Vec<Capability>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_parser::DateTime;
|
||||
|
||||
use super::{
|
||||
|
|
@ -16,7 +16,7 @@ use super::{
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub sequence_set: Sequence,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub changed_since: Option<u64>,
|
||||
|
|
@ -69,14 +69,9 @@ pub enum Attribute {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Section {
|
||||
Part {
|
||||
num: u32,
|
||||
},
|
||||
Part { num: u32 },
|
||||
Header,
|
||||
HeaderFields {
|
||||
not: bool,
|
||||
fields: Vec<CompactString>,
|
||||
},
|
||||
HeaderFields { not: bool, fields: Vec<String> },
|
||||
Text,
|
||||
Mime,
|
||||
}
|
||||
|
|
@ -134,10 +129,10 @@ pub enum DataItem<'x> {
|
|||
modseq: u64,
|
||||
},
|
||||
EmailId {
|
||||
email_id: CompactString,
|
||||
email_id: String,
|
||||
},
|
||||
ThreadId {
|
||||
thread_id: CompactString,
|
||||
thread_id: String,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -922,7 +917,7 @@ impl ImapResponse for Response<'_> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use mail_parser::DateTime;
|
||||
|
||||
use crate::protocol::{Flag, ImapResponse};
|
||||
|
|
@ -1370,7 +1365,7 @@ mod tests {
|
|||
|
||||
item.serialize(&mut buf);
|
||||
|
||||
assert_eq!(CompactString::from_utf8(buf).unwrap(), expected_response);
|
||||
assert_eq!(String::from_utf8(buf).unwrap(), expected_response);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use crate::utf7::utf7_encode;
|
||||
|
||||
|
|
@ -16,14 +16,14 @@ use super::{
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Arguments {
|
||||
Basic {
|
||||
tag: CompactString,
|
||||
reference_name: CompactString,
|
||||
mailbox_name: CompactString,
|
||||
tag: String,
|
||||
reference_name: String,
|
||||
mailbox_name: String,
|
||||
},
|
||||
Extended {
|
||||
tag: CompactString,
|
||||
reference_name: CompactString,
|
||||
mailbox_name: Vec<CompactString>,
|
||||
tag: String,
|
||||
reference_name: String,
|
||||
mailbox_name: Vec<String>,
|
||||
selection_options: Vec<SelectionOption>,
|
||||
return_options: Vec<ReturnOption>,
|
||||
},
|
||||
|
|
@ -82,12 +82,12 @@ pub enum ChildInfo {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Tag {
|
||||
ChildInfo(Vec<ChildInfo>),
|
||||
OldName(CompactString),
|
||||
OldName(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ListItem {
|
||||
pub mailbox_name: CompactString,
|
||||
pub mailbox_name: String,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub tags: Vec<Tag>,
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ impl Arguments {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_tag(self) -> CompactString {
|
||||
pub fn unwrap_tag(self) -> String {
|
||||
match self {
|
||||
Arguments::Basic { tag, .. } => tag,
|
||||
Arguments::Extended { tag, .. } => tag,
|
||||
|
|
@ -196,7 +196,7 @@ impl Tag {
|
|||
}
|
||||
|
||||
impl ListItem {
|
||||
pub fn new(name: impl Into<CompactString>) -> Self {
|
||||
pub fn new(name: impl Into<String>) -> Self {
|
||||
ListItem {
|
||||
mailbox_name: name.into(),
|
||||
attributes: Vec::new(),
|
||||
|
|
@ -277,7 +277,7 @@ impl ImapResponse for Response {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use crate::protocol::{
|
||||
ImapResponse,
|
||||
|
|
@ -341,8 +341,8 @@ mod tests {
|
|||
response.serialize(&mut buf_1, false, false);
|
||||
response.serialize(&mut buf_2, true, false);
|
||||
|
||||
let response_v1 = CompactString::from_utf8(buf_1).unwrap();
|
||||
let response_v2 = CompactString::from_utf8(buf_2).unwrap();
|
||||
let response_v1 = String::from_utf8(buf_1).unwrap();
|
||||
let response_v2 = String::from_utf8(buf_2).unwrap();
|
||||
|
||||
assert_eq!(response_v2, expected_v2);
|
||||
assert_eq!(response_v1, expected_v1);
|
||||
|
|
@ -391,11 +391,11 @@ mod tests {
|
|||
"* LSUB () \"/\" \"foo\" (\"CHILDINFO\" (\"SUBSCRIBED\"))\r\n",
|
||||
);
|
||||
|
||||
let response_v2 = CompactString::from_utf8(response.clone().serialize()).unwrap();
|
||||
let response_v2 = String::from_utf8(response.clone().serialize()).unwrap();
|
||||
response.is_rev2 = false;
|
||||
response.is_lsub = true;
|
||||
response.status_items.clear();
|
||||
let response_v1 = CompactString::from_utf8(response.serialize()).unwrap();
|
||||
let response_v1 = String::from_utf8(response.serialize()).unwrap();
|
||||
|
||||
assert_eq!(response_v2, expected_v2);
|
||||
assert_eq!(response_v1, expected_v1);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub username: CompactString,
|
||||
pub password: CompactString,
|
||||
pub tag: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use std::{cmp::Ordering, fmt::Display};
|
|||
|
||||
use ahash::AHashSet;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use jmap_proto::types::keyword::{ArchivedKeyword, Keyword};
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ pub enum Flag {
|
|||
Deleted,
|
||||
Forwarded,
|
||||
MDNSent,
|
||||
Keyword(CompactString),
|
||||
Keyword(String),
|
||||
}
|
||||
|
||||
impl Flag {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::{ImapResponse, quoted_string};
|
||||
|
||||
pub struct Response {
|
||||
pub shared_prefix: Option<CompactString>,
|
||||
pub shared_prefix: Option<String>,
|
||||
}
|
||||
|
||||
impl ImapResponse for Response {
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::{ImapResponse, capability::QuotaResourceName, quoted_string};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub name: CompactString,
|
||||
pub tag: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub struct QuotaItem {
|
||||
pub name: CompactString,
|
||||
pub name: String,
|
||||
pub resources: Vec<QuotaResource>,
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ pub struct QuotaResource {
|
|||
}
|
||||
|
||||
pub struct Response {
|
||||
pub quota_root_items: Vec<CompactString>,
|
||||
pub quota_root_items: Vec<String>,
|
||||
pub quota_items: Vec<QuotaItem>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub new_mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
pub new_mailbox_name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use store::fts::{FilterItem, FilterType};
|
||||
|
||||
use super::{Flag, Sequence, quoted_string, serialize_sequence};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub is_esearch: bool,
|
||||
pub sort: Option<Vec<Comparator>>,
|
||||
pub result_options: Vec<ResultOption>,
|
||||
|
|
@ -64,15 +64,15 @@ pub enum Filter {
|
|||
Sequence(Sequence, bool),
|
||||
All,
|
||||
Answered,
|
||||
Bcc(CompactString),
|
||||
Bcc(String),
|
||||
Before(i64),
|
||||
Body(CompactString),
|
||||
Cc(CompactString),
|
||||
Body(String),
|
||||
Cc(String),
|
||||
Deleted,
|
||||
Draft,
|
||||
Flagged,
|
||||
From(CompactString),
|
||||
Header(CompactString, CompactString),
|
||||
From(String),
|
||||
Header(String, String),
|
||||
Keyword(Flag),
|
||||
Larger(u32),
|
||||
On(i64),
|
||||
|
|
@ -82,9 +82,9 @@ pub enum Filter {
|
|||
SentSince(i64),
|
||||
Since(i64),
|
||||
Smaller(u32),
|
||||
Subject(CompactString),
|
||||
Text(CompactString),
|
||||
To(CompactString),
|
||||
Subject(String),
|
||||
Text(String),
|
||||
To(String),
|
||||
Unanswered,
|
||||
Undeleted,
|
||||
Undraft,
|
||||
|
|
@ -111,8 +111,8 @@ pub enum Filter {
|
|||
ModSeq((u64, ModSeqEntry)),
|
||||
|
||||
// RFC 8474 - ObjectID
|
||||
EmailId(CompactString),
|
||||
ThreadId(CompactString),
|
||||
EmailId(String),
|
||||
ThreadId(String),
|
||||
}
|
||||
|
||||
impl FilterItem for Filter {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use crate::{ResponseCode, StatusResponse};
|
||||
|
||||
|
|
@ -12,8 +12,8 @@ use super::{ImapResponse, Sequence, list::ListItem};
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
pub condstore: bool,
|
||||
pub qresync: Option<QResync>,
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ pub struct Response {
|
|||
pub is_rev2: bool,
|
||||
pub closed_previous: bool,
|
||||
pub highest_modseq: Option<HighestModSeq>,
|
||||
pub mailbox_id: CompactString,
|
||||
pub mailbox_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use crate::utf7::utf7_encode;
|
||||
|
||||
|
|
@ -12,8 +12,8 @@ use super::quoted_string;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
pub items: Vec<Status>,
|
||||
}
|
||||
|
||||
|
|
@ -33,14 +33,14 @@ pub enum Status {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StatusItem {
|
||||
pub mailbox_name: CompactString,
|
||||
pub mailbox_name: String,
|
||||
pub items: Vec<(Status, StatusItemType)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum StatusItemType {
|
||||
Number(u64),
|
||||
String(CompactString),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl StatusItem {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::{Flag, ImapResponse, Sequence, fetch::FetchItem};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub sequence_set: Sequence,
|
||||
pub operation: Operation,
|
||||
pub is_silent: bool,
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub mailbox_name: CompactString,
|
||||
pub tag: String,
|
||||
pub mailbox_name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
|
||||
use super::{ImapResponse, search::Filter};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Arguments {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub filter: Vec<Filter>,
|
||||
pub algorithm: Algorithm,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use compact_str::CompactString;
|
||||
use std::fmt::Display;
|
||||
|
||||
use compact_str::{CompactString, format_compact};
|
||||
|
||||
use super::{ResponseCode, ResponseType};
|
||||
|
||||
|
|
@ -17,7 +19,7 @@ pub enum Error {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Request<T: CommandParser> {
|
||||
pub tag: CompactString,
|
||||
pub tag: String,
|
||||
pub command: T,
|
||||
pub tokens: Vec<Token>,
|
||||
}
|
||||
|
|
@ -43,7 +45,7 @@ pub enum Token {
|
|||
impl<T: CommandParser> Default for Request<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tag: CompactString::new(""),
|
||||
tag: String::new(),
|
||||
command: T::default(),
|
||||
tokens: Vec::new(),
|
||||
}
|
||||
|
|
@ -112,7 +114,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
if !self.buf.is_empty() {
|
||||
self.current_request_size += self.buf.len();
|
||||
if self.current_request_size > self.max_request_size {
|
||||
return Err(self.error_reset(format!(
|
||||
return Err(self.error_reset(format_compact!(
|
||||
"Request exceeds maximum limit of {} bytes.",
|
||||
self.max_request_size
|
||||
)));
|
||||
|
|
@ -128,7 +130,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
fn push_token(&mut self, token: Token) -> Result<(), Error> {
|
||||
self.current_request_size += 1;
|
||||
if self.current_request_size > self.max_request_size {
|
||||
return Err(self.error_reset(format!(
|
||||
return Err(self.error_reset(format_compact!(
|
||||
"Request exceeds maximum limit of {} bytes.",
|
||||
self.max_request_size
|
||||
)));
|
||||
|
|
@ -150,7 +152,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
State::Tag => match ch {
|
||||
b' ' => {
|
||||
if !self.buf.is_empty() {
|
||||
self.request.tag = CompactString::from_utf8(std::mem::replace(
|
||||
self.request.tag = String::from_utf8(std::mem::replace(
|
||||
&mut self.buf,
|
||||
Vec::with_capacity(10),
|
||||
))
|
||||
|
|
@ -160,7 +162,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
}
|
||||
b'\t' | b'\r' => {}
|
||||
b'\n' => {
|
||||
return Err(self.error_reset(format!(
|
||||
return Err(self.error_reset(format_compact!(
|
||||
"Missing command after tag {:?}, found CRLF instead.",
|
||||
std::str::from_utf8(&self.buf).unwrap_or_default()
|
||||
)));
|
||||
|
|
@ -187,7 +189,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
T::parse(&self.buf, is_uid).ok_or_else(|| {
|
||||
let command =
|
||||
String::from_utf8_lossy(&self.buf).into_owned();
|
||||
self.error_reset(format!(
|
||||
self.error_reset(format_compact!(
|
||||
"Unrecognized command '{}'.",
|
||||
command
|
||||
))
|
||||
|
|
@ -206,7 +208,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
return Err(self.error_reset(format!(
|
||||
return Err(self.error_reset(format_compact!(
|
||||
"Invalid character {:?} in command name.",
|
||||
ch as char
|
||||
)));
|
||||
|
|
@ -315,7 +317,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
})?;
|
||||
if self.current_request_size + size as usize > self.max_request_size
|
||||
{
|
||||
return Err(self.error_reset(format!(
|
||||
return Err(self.error_reset(format_compact!(
|
||||
"Literal exceeds the maximum request size of {} bytes.",
|
||||
self.max_request_size
|
||||
)));
|
||||
|
|
@ -343,7 +345,7 @@ impl<T: CommandParser> Receiver<T> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(self.error_reset(format!(
|
||||
return Err(self.error_reset(format_compact!(
|
||||
"Invalid character {:?} in literal.",
|
||||
ch as char
|
||||
)));
|
||||
|
|
@ -386,10 +388,10 @@ impl<T: CommandParser> Receiver<T> {
|
|||
}
|
||||
|
||||
impl Token {
|
||||
pub fn unwrap_string(self) -> crate::parser::Result<CompactString> {
|
||||
pub fn unwrap_string(self) -> crate::parser::Result<String> {
|
||||
match self {
|
||||
Token::Argument(value) => {
|
||||
CompactString::from_utf8(value).map_err(|_| "Invalid UTF-8 in argument.".into())
|
||||
String::from_utf8(value).map_err(|_| "Invalid UTF-8 in argument.".into())
|
||||
}
|
||||
other => Ok(other.to_string()),
|
||||
}
|
||||
|
|
@ -445,6 +447,12 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for Token {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
f.write_str(&String::from_utf8_lossy(self.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
|
|
@ -459,17 +467,14 @@ impl Token {
|
|||
Token::Nil => b"",
|
||||
}
|
||||
}
|
||||
pub fn to_string(&self) -> CompactString {
|
||||
CompactString::from_utf8_lossy(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn err(tag: Option<CompactString>, message: impl Into<trc::Value>) -> Self {
|
||||
pub fn err(tag: Option<impl Into<CompactString>>, message: impl Into<trc::Value>) -> Self {
|
||||
Error::Error {
|
||||
response: trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx_opt(trc::Key::Id, tag)
|
||||
.ctx_opt(trc::Key::Id, tag.map(Into::into))
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
.code(ResponseCode::Parse),
|
||||
}
|
||||
|
|
@ -493,13 +498,13 @@ impl<T: CommandParser> Request<T> {
|
|||
pub fn into_error(self, message: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx(trc::Key::Id, self.tag)
|
||||
.ctx(trc::Key::Id, CompactString::from_string_buffer(self.tag))
|
||||
}
|
||||
|
||||
pub fn into_parse_error(self, message: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx(trc::Key::Id, self.tag)
|
||||
.ctx(trc::Key::Id, CompactString::from_string_buffer(self.tag))
|
||||
.ctx(trc::Key::Code, ResponseCode::Parse)
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
// Ported from https://github.com/jstedfast/MailKit/blob/master/MailKit/Net/Imap/ImapEncoding.cs
|
||||
// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use crate::protocol::ProtocolVersion;
|
||||
|
||||
static UTF_7_RANK: &[u8] = &[
|
||||
|
|
@ -22,7 +20,7 @@ static UTF_7_RANK: &[u8] = &[
|
|||
|
||||
static UTF_7_MAP: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
|
||||
|
||||
pub fn utf7_decode(text: &str) -> Option<CompactString> {
|
||||
pub fn utf7_decode(text: &str) -> Option<String> {
|
||||
let mut bytes: Vec<u16> = Vec::with_capacity(text.len());
|
||||
let mut bits = 0;
|
||||
let mut v: u32 = 0;
|
||||
|
|
@ -70,11 +68,11 @@ pub fn utf7_decode(text: &str) -> Option<CompactString> {
|
|||
}
|
||||
}
|
||||
|
||||
CompactString::from_utf16(&bytes).ok()
|
||||
String::from_utf16(&bytes).ok()
|
||||
}
|
||||
|
||||
pub fn utf7_encode(text: &str) -> CompactString {
|
||||
let mut result = CompactString::with_capacity(text.len());
|
||||
pub fn utf7_encode(text: &str) -> String {
|
||||
let mut result = String::with_capacity(text.len());
|
||||
let mut shifted = false;
|
||||
let mut bits = 0;
|
||||
let mut u: u32 = 0;
|
||||
|
|
@ -124,7 +122,7 @@ pub fn utf7_encode(text: &str) -> CompactString {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn utf7_maybe_decode(text: CompactString, version: ProtocolVersion) -> CompactString {
|
||||
pub fn utf7_maybe_decode(text: String, version: ProtocolVersion) -> String {
|
||||
if version.is_rev2() {
|
||||
text
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use common::{
|
|||
listener::{SessionStream, limiter::InFlight},
|
||||
sharing::EffectiveAcl,
|
||||
};
|
||||
use compact_str::CompactString;
|
||||
|
||||
use directory::backend::internal::manage::ManageDirectory;
|
||||
use email::{
|
||||
mailbox::{
|
||||
|
|
@ -60,7 +60,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
|
||||
// Fetch shared mailboxes
|
||||
for &account_id in access_token.shared_accounts(Collection::Mailbox) {
|
||||
let prefix: CompactString = format!(
|
||||
let prefix: String = format!(
|
||||
"{}/{}",
|
||||
session.server.core.jmap.shared_folder,
|
||||
session
|
||||
|
|
@ -69,9 +69,8 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.get_principal_name(account_id)
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
.unwrap_or_else(|| Id::from(account_id).to_string().into())
|
||||
)
|
||||
.into();
|
||||
.unwrap_or_else(|| Id::from(account_id).to_string())
|
||||
);
|
||||
mailboxes.push(
|
||||
session
|
||||
.fetch_account_mailboxes(account_id, prefix.into(), &access_token, None)
|
||||
|
|
@ -89,7 +88,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
async fn fetch_account_mailboxes(
|
||||
&self,
|
||||
account_id: u32,
|
||||
mailbox_prefix: Option<CompactString>,
|
||||
mailbox_prefix: Option<String>,
|
||||
access_token: &AccessToken,
|
||||
current_state: Option<AccountState>,
|
||||
) -> trc::Result<Option<Account>> {
|
||||
|
|
@ -153,7 +152,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
|
||||
// Build mailbox path and map it to its effective id
|
||||
let mailbox_name = if let Some(prefix) = &account.prefix {
|
||||
let mut name = CompactString::with_capacity(prefix.len() + mailbox.path.len() + 1);
|
||||
let mut name = String::with_capacity(prefix.len() + mailbox.path.len() + 1);
|
||||
name.push_str(prefix.as_str());
|
||||
name.push('/');
|
||||
name.push_str(mailbox.path.as_str());
|
||||
|
|
@ -167,7 +166,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.jmap
|
||||
.default_folders
|
||||
.iter()
|
||||
.find(|f| f.name == mailbox_name || f.aliases.iter().any(|a| a == mailbox_name))
|
||||
.find(|f| f.name == mailbox_name || f.aliases.iter().any(|a| a == &mailbox_name))
|
||||
.and_then(|f| special_uses.get(&f.special_use))
|
||||
.copied()
|
||||
.unwrap_or(mailbox.document_id);
|
||||
|
|
@ -275,7 +274,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
|
||||
// Fetch mailboxes for each new shared account
|
||||
for account_id in added_account_ids {
|
||||
let prefix: CompactString = format!(
|
||||
let prefix: String = format!(
|
||||
"{}/{}",
|
||||
self.server.core.jmap.shared_folder,
|
||||
self.server
|
||||
|
|
@ -283,9 +282,8 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.get_principal_name(account_id)
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
.unwrap_or_else(|| Id::from(account_id).to_string().into())
|
||||
)
|
||||
.into();
|
||||
.unwrap_or_else(|| Id::from(account_id).to_string())
|
||||
);
|
||||
added_accounts.push(
|
||||
self.fetch_account_mailboxes(account_id, prefix.into(), &access_token, None)
|
||||
.await?
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue