Copy disabled (too large)
Download .txt
Showing preview only (12,036K chars total). Download the full file to get everything.
Repository: stalwartlabs/stalwart
Branch: main
Commit: 2266634f36e2
Files: 1534
Total size: 11.2 MB
Directory structure:
gitextract_l0u7gilb/
├── .dockerignore
├── .editorconfig
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── issue-triage.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── config.yml
│ │ └── confirmed_issue.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── scorecard.yml
│ ├── test.yml
│ └── trivy.yml
├── .gitignore
├── CHANGELOG.md
├── CNAME
├── CONTRIBUTING.md
├── Cargo.toml
├── Dockerfile
├── Dockerfile.build
├── LICENSES/
│ ├── AGPL-3.0-only.txt
│ └── LicenseRef-SEL.txt
├── README.md
├── SECURITY.md
├── SECURITY_PROCESS.md
├── SECURITY_TEMPLATE.md
├── UPGRADING/
│ ├── v0_04.md
│ ├── v0_05.md
│ ├── v0_06.md
│ ├── v0_07.md
│ ├── v0_08.md
│ ├── v0_09.md
│ ├── v0_10.md
│ ├── v0_11.md
│ ├── v0_12.md
│ ├── v0_13.md
│ ├── v0_14.md
│ └── v0_15.md
├── api/
│ └── v1/
│ └── openapi.yml
├── crates/
│ ├── cli/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── main.rs
│ │ └── modules/
│ │ ├── account.rs
│ │ ├── cli.rs
│ │ ├── database.rs
│ │ ├── dkim.rs
│ │ ├── domain.rs
│ │ ├── export.rs
│ │ ├── group.rs
│ │ ├── import.rs
│ │ ├── list.rs
│ │ ├── mod.rs
│ │ ├── queue.rs
│ │ └── report.rs
│ ├── common/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/
│ │ ├── addresses.rs
│ │ ├── auth/
│ │ │ ├── access_token.rs
│ │ │ ├── mod.rs
│ │ │ ├── oauth/
│ │ │ │ ├── config.rs
│ │ │ │ ├── crypto.rs
│ │ │ │ ├── introspect.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── oidc.rs
│ │ │ │ ├── registration.rs
│ │ │ │ └── token.rs
│ │ │ ├── rate_limit.rs
│ │ │ ├── roles.rs
│ │ │ └── sasl.rs
│ │ ├── config/
│ │ │ ├── groupware.rs
│ │ │ ├── imap.rs
│ │ │ ├── inner.rs
│ │ │ ├── jmap/
│ │ │ │ ├── capabilities.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── settings.rs
│ │ │ ├── mod.rs
│ │ │ ├── network.rs
│ │ │ ├── scripts.rs
│ │ │ ├── server/
│ │ │ │ ├── listener.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── tls.rs
│ │ │ ├── smtp/
│ │ │ │ ├── auth.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── queue.rs
│ │ │ │ ├── report.rs
│ │ │ │ ├── resolver.rs
│ │ │ │ ├── session.rs
│ │ │ │ └── throttle.rs
│ │ │ ├── spamfilter.rs
│ │ │ ├── storage.rs
│ │ │ └── telemetry.rs
│ │ ├── core.rs
│ │ ├── dns.rs
│ │ ├── enterprise/
│ │ │ ├── alerts.rs
│ │ │ ├── config.rs
│ │ │ ├── license.rs
│ │ │ ├── llm.rs
│ │ │ ├── mod.rs
│ │ │ └── undelete.rs
│ │ ├── expr/
│ │ │ ├── eval.rs
│ │ │ ├── functions/
│ │ │ │ ├── array.rs
│ │ │ │ ├── asynch.rs
│ │ │ │ ├── email.rs
│ │ │ │ ├── misc.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── text.rs
│ │ │ ├── if_block.rs
│ │ │ ├── mod.rs
│ │ │ ├── parser.rs
│ │ │ └── tokenizer.rs
│ │ ├── i18n.rs
│ │ ├── ipc.rs
│ │ ├── lib.rs
│ │ ├── listener/
│ │ │ ├── acme/
│ │ │ │ ├── cache.rs
│ │ │ │ ├── directory.rs
│ │ │ │ ├── jose.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── order.rs
│ │ │ │ └── resolver.rs
│ │ │ ├── asn.rs
│ │ │ ├── blocked.rs
│ │ │ ├── limiter.rs
│ │ │ ├── listen.rs
│ │ │ ├── mod.rs
│ │ │ ├── stream.rs
│ │ │ └── tls.rs
│ │ ├── manager/
│ │ │ ├── backup.rs
│ │ │ ├── boot.rs
│ │ │ ├── config.rs
│ │ │ ├── console.rs
│ │ │ ├── mod.rs
│ │ │ ├── reload.rs
│ │ │ ├── restore.rs
│ │ │ └── webadmin.rs
│ │ ├── scripts/
│ │ │ ├── functions/
│ │ │ │ ├── array.rs
│ │ │ │ ├── email.rs
│ │ │ │ ├── header.rs
│ │ │ │ ├── image.rs
│ │ │ │ ├── misc.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── text.rs
│ │ │ │ ├── unicode.rs
│ │ │ │ └── url.rs
│ │ │ ├── mod.rs
│ │ │ └── plugins/
│ │ │ ├── dns.rs
│ │ │ ├── exec.rs
│ │ │ ├── headers.rs
│ │ │ ├── http.rs
│ │ │ ├── llm_prompt.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── text.rs
│ │ ├── sharing/
│ │ │ ├── acl.rs
│ │ │ ├── mod.rs
│ │ │ ├── notification.rs
│ │ │ └── resources.rs
│ │ ├── storage/
│ │ │ ├── blob.rs
│ │ │ ├── index.rs
│ │ │ ├── mod.rs
│ │ │ └── state.rs
│ │ └── telemetry/
│ │ ├── metrics/
│ │ │ ├── mod.rs
│ │ │ ├── otel.rs
│ │ │ ├── prometheus.rs
│ │ │ └── store.rs
│ │ ├── mod.rs
│ │ ├── tracers/
│ │ │ ├── journald.rs
│ │ │ ├── log.rs
│ │ │ ├── mod.rs
│ │ │ ├── otel.rs
│ │ │ ├── stdout.rs
│ │ │ └── store.rs
│ │ └── webhooks/
│ │ └── mod.rs
│ ├── dav/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── calendar/
│ │ │ ├── copy_move.rs
│ │ │ ├── delete.rs
│ │ │ ├── freebusy.rs
│ │ │ ├── get.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── proppatch.rs
│ │ │ ├── query.rs
│ │ │ ├── scheduling.rs
│ │ │ └── update.rs
│ │ ├── card/
│ │ │ ├── copy_move.rs
│ │ │ ├── delete.rs
│ │ │ ├── get.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── proppatch.rs
│ │ │ ├── query.rs
│ │ │ └── update.rs
│ │ ├── common/
│ │ │ ├── acl.rs
│ │ │ ├── lock.rs
│ │ │ ├── mod.rs
│ │ │ ├── propfind.rs
│ │ │ └── uri.rs
│ │ ├── file/
│ │ │ ├── copy_move.rs
│ │ │ ├── delete.rs
│ │ │ ├── get.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── proppatch.rs
│ │ │ └── update.rs
│ │ ├── lib.rs
│ │ ├── principal/
│ │ │ ├── matching.rs
│ │ │ ├── mod.rs
│ │ │ ├── propfind.rs
│ │ │ └── propsearch.rs
│ │ └── request.rs
│ ├── dav-proto/
│ │ ├── Cargo.toml
│ │ ├── resources/
│ │ │ ├── requests/
│ │ │ │ ├── acl-001.json
│ │ │ │ ├── acl-001.xml
│ │ │ │ ├── acl-002.json
│ │ │ │ ├── acl-002.xml
│ │ │ │ ├── acl-003.json
│ │ │ │ ├── acl-003.xml
│ │ │ │ ├── acl-004.json
│ │ │ │ ├── acl-004.xml
│ │ │ │ ├── lockinfo-001.json
│ │ │ │ ├── lockinfo-001.xml
│ │ │ │ ├── lockinfo-002.json
│ │ │ │ ├── lockinfo-002.xml
│ │ │ │ ├── mkcol-001.json
│ │ │ │ ├── mkcol-001.xml
│ │ │ │ ├── mkcol-002.json
│ │ │ │ ├── mkcol-002.xml
│ │ │ │ ├── mkcol-003.json
│ │ │ │ ├── mkcol-003.xml
│ │ │ │ ├── mkcol-004.json
│ │ │ │ ├── mkcol-004.xml
│ │ │ │ ├── propertyupdate-001.json
│ │ │ │ ├── propertyupdate-001.xml
│ │ │ │ ├── propertyupdate-002.json
│ │ │ │ ├── propertyupdate-002.xml
│ │ │ │ ├── propfind-001.json
│ │ │ │ ├── propfind-001.xml
│ │ │ │ ├── propfind-002.json
│ │ │ │ ├── propfind-002.xml
│ │ │ │ ├── propfind-003.json
│ │ │ │ ├── propfind-003.xml
│ │ │ │ ├── propfind-004.json
│ │ │ │ ├── propfind-004.xml
│ │ │ │ ├── propfind-005.json
│ │ │ │ ├── propfind-005.xml
│ │ │ │ ├── propfind-006.json
│ │ │ │ ├── propfind-006.xml
│ │ │ │ ├── propfind-007.json
│ │ │ │ ├── propfind-007.xml
│ │ │ │ ├── propfind-008.json
│ │ │ │ ├── propfind-008.xml
│ │ │ │ ├── propfind-009.json
│ │ │ │ ├── propfind-009.xml
│ │ │ │ ├── propfind-010.json
│ │ │ │ ├── propfind-010.xml
│ │ │ │ ├── report-001.json
│ │ │ │ ├── report-001.xml
│ │ │ │ ├── report-002.json
│ │ │ │ ├── report-002.xml
│ │ │ │ ├── report-003.json
│ │ │ │ ├── report-003.xml
│ │ │ │ ├── report-004.json
│ │ │ │ ├── report-004.xml
│ │ │ │ ├── report-005.json
│ │ │ │ ├── report-005.xml
│ │ │ │ ├── report-006.json
│ │ │ │ ├── report-006.xml
│ │ │ │ ├── report-007.json
│ │ │ │ ├── report-007.xml
│ │ │ │ ├── report-008.json
│ │ │ │ ├── report-008.xml
│ │ │ │ ├── report-009.json
│ │ │ │ ├── report-009.xml
│ │ │ │ ├── report-010.json
│ │ │ │ ├── report-010.xml
│ │ │ │ ├── report-011.json
│ │ │ │ ├── report-011.xml
│ │ │ │ ├── report-012.json
│ │ │ │ ├── report-012.xml
│ │ │ │ ├── report-013.json
│ │ │ │ ├── report-013.xml
│ │ │ │ ├── report-014.json
│ │ │ │ ├── report-014.xml
│ │ │ │ ├── report-015.json
│ │ │ │ ├── report-015.xml
│ │ │ │ ├── report-016.json
│ │ │ │ ├── report-016.xml
│ │ │ │ ├── report-017.json
│ │ │ │ ├── report-017.xml
│ │ │ │ ├── report-018.json
│ │ │ │ ├── report-018.xml
│ │ │ │ ├── report-019.json
│ │ │ │ ├── report-019.xml
│ │ │ │ ├── report-020.json
│ │ │ │ ├── report-020.xml
│ │ │ │ ├── report-021.json
│ │ │ │ ├── report-021.xml
│ │ │ │ ├── report-022.json
│ │ │ │ ├── report-022.xml
│ │ │ │ ├── report-023.json
│ │ │ │ ├── report-023.xml
│ │ │ │ ├── report-024.json
│ │ │ │ ├── report-024.xml
│ │ │ │ ├── report-025.json
│ │ │ │ └── report-025.xml
│ │ │ └── responses/
│ │ │ ├── 001.xml
│ │ │ ├── 002.xml
│ │ │ ├── 003.xml
│ │ │ ├── 004.xml
│ │ │ ├── 005.xml
│ │ │ ├── 006.xml
│ │ │ ├── 007.xml
│ │ │ ├── 008.xml
│ │ │ ├── 009.xml
│ │ │ ├── 010.xml
│ │ │ ├── 011.xml
│ │ │ ├── 012.xml
│ │ │ ├── 013.xml
│ │ │ ├── 014.xml
│ │ │ ├── 015.xml
│ │ │ ├── 016.xml
│ │ │ ├── 017.xml
│ │ │ ├── 018.xml
│ │ │ ├── 019.xml
│ │ │ └── 020.xml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── parser/
│ │ │ ├── header.rs
│ │ │ ├── mod.rs
│ │ │ ├── property.rs
│ │ │ └── tokenizer.rs
│ │ ├── requests/
│ │ │ ├── acl.rs
│ │ │ ├── lockinfo.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── propertyupdate.rs
│ │ │ ├── propfind.rs
│ │ │ └── report.rs
│ │ ├── responses/
│ │ │ ├── acl.rs
│ │ │ ├── error.rs
│ │ │ ├── lock.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── multistatus.rs
│ │ │ ├── property.rs
│ │ │ ├── propstat.rs
│ │ │ └── schedule.rs
│ │ └── schema/
│ │ ├── mod.rs
│ │ ├── property.rs
│ │ ├── request.rs
│ │ └── response.rs
│ ├── directory/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── backend/
│ │ │ ├── imap/
│ │ │ │ ├── client.rs
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── pool.rs
│ │ │ │ └── tls.rs
│ │ │ ├── internal/
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── manage.rs
│ │ │ │ └── mod.rs
│ │ │ ├── ldap/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── pool.rs
│ │ │ ├── memory/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ └── mod.rs
│ │ │ ├── mod.rs
│ │ │ ├── oidc/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ └── mod.rs
│ │ │ ├── smtp/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── pool.rs
│ │ │ └── sql/
│ │ │ ├── config.rs
│ │ │ ├── lookup.rs
│ │ │ └── mod.rs
│ │ ├── core/
│ │ │ ├── cache.rs
│ │ │ ├── config.rs
│ │ │ ├── dispatch.rs
│ │ │ ├── mod.rs
│ │ │ ├── principal.rs
│ │ │ └── secret.rs
│ │ └── lib.rs
│ ├── email/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── cache/
│ │ │ ├── email.rs
│ │ │ ├── mailbox.rs
│ │ │ └── mod.rs
│ │ ├── identity/
│ │ │ ├── index.rs
│ │ │ └── mod.rs
│ │ ├── lib.rs
│ │ ├── mailbox/
│ │ │ ├── destroy.rs
│ │ │ ├── index.rs
│ │ │ ├── manage.rs
│ │ │ └── mod.rs
│ │ ├── message/
│ │ │ ├── copy.rs
│ │ │ ├── crypto.rs
│ │ │ ├── delete.rs
│ │ │ ├── delivery.rs
│ │ │ ├── index/
│ │ │ │ ├── extractors.rs
│ │ │ │ ├── metadata.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── search.rs
│ │ │ ├── ingest.rs
│ │ │ ├── metadata.rs
│ │ │ └── mod.rs
│ │ ├── push/
│ │ │ └── mod.rs
│ │ ├── sieve/
│ │ │ ├── delete.rs
│ │ │ ├── index.rs
│ │ │ ├── ingest.rs
│ │ │ └── mod.rs
│ │ └── submission/
│ │ ├── index.rs
│ │ └── mod.rs
│ ├── groupware/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── cache/
│ │ │ ├── calcard.rs
│ │ │ ├── file.rs
│ │ │ └── mod.rs
│ │ ├── calendar/
│ │ │ ├── alarm.rs
│ │ │ ├── dates.rs
│ │ │ ├── expand.rs
│ │ │ ├── index.rs
│ │ │ ├── itip.rs
│ │ │ ├── mod.rs
│ │ │ └── storage.rs
│ │ ├── contact/
│ │ │ ├── index.rs
│ │ │ ├── mod.rs
│ │ │ └── storage.rs
│ │ ├── file/
│ │ │ ├── index.rs
│ │ │ ├── mod.rs
│ │ │ └── storage.rs
│ │ ├── lib.rs
│ │ └── scheduling/
│ │ ├── attendee.rs
│ │ ├── event_cancel.rs
│ │ ├── event_create.rs
│ │ ├── event_update.rs
│ │ ├── inbound.rs
│ │ ├── itip.rs
│ │ ├── mod.rs
│ │ ├── organizer.rs
│ │ └── snapshot.rs
│ ├── http/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── auth/
│ │ │ ├── authenticate.rs
│ │ │ ├── mod.rs
│ │ │ └── oauth/
│ │ │ ├── auth.rs
│ │ │ ├── mod.rs
│ │ │ ├── openid.rs
│ │ │ ├── registration.rs
│ │ │ └── token.rs
│ │ ├── autoconfig/
│ │ │ └── mod.rs
│ │ ├── form/
│ │ │ └── mod.rs
│ │ ├── lib.rs
│ │ ├── management/
│ │ │ ├── crypto.rs
│ │ │ ├── dkim.rs
│ │ │ ├── dns.rs
│ │ │ ├── enterprise/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── telemetry.rs
│ │ │ │ └── undelete.rs
│ │ │ ├── log.rs
│ │ │ ├── mod.rs
│ │ │ ├── principal.rs
│ │ │ ├── queue.rs
│ │ │ ├── reload.rs
│ │ │ ├── report.rs
│ │ │ ├── settings.rs
│ │ │ ├── spam.rs
│ │ │ ├── stores.rs
│ │ │ └── troubleshoot.rs
│ │ └── request.rs
│ ├── http-proto/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── context.rs
│ │ ├── lib.rs
│ │ ├── request.rs
│ │ └── response.rs
│ ├── imap/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── core/
│ │ │ ├── client.rs
│ │ │ ├── mailbox.rs
│ │ │ ├── message.rs
│ │ │ ├── mod.rs
│ │ │ └── session.rs
│ │ ├── lib.rs
│ │ └── op/
│ │ ├── acl.rs
│ │ ├── append.rs
│ │ ├── authenticate.rs
│ │ ├── capability.rs
│ │ ├── close.rs
│ │ ├── copy_move.rs
│ │ ├── create.rs
│ │ ├── delete.rs
│ │ ├── enable.rs
│ │ ├── expunge.rs
│ │ ├── fetch.rs
│ │ ├── idle.rs
│ │ ├── list.rs
│ │ ├── login.rs
│ │ ├── logout.rs
│ │ ├── mod.rs
│ │ ├── namespace.rs
│ │ ├── noop.rs
│ │ ├── quota.rs
│ │ ├── rename.rs
│ │ ├── search.rs
│ │ ├── select.rs
│ │ ├── status.rs
│ │ ├── store.rs
│ │ ├── subscribe.rs
│ │ └── thread.rs
│ ├── imap-proto/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── parser/
│ │ │ ├── acl.rs
│ │ │ ├── append.rs
│ │ │ ├── authenticate.rs
│ │ │ ├── copy_move.rs
│ │ │ ├── create.rs
│ │ │ ├── delete.rs
│ │ │ ├── enable.rs
│ │ │ ├── fetch.rs
│ │ │ ├── list.rs
│ │ │ ├── login.rs
│ │ │ ├── lsub.rs
│ │ │ ├── mod.rs
│ │ │ ├── quota.rs
│ │ │ ├── rename.rs
│ │ │ ├── search.rs
│ │ │ ├── select.rs
│ │ │ ├── sort.rs
│ │ │ ├── status.rs
│ │ │ ├── store.rs
│ │ │ ├── subscribe.rs
│ │ │ └── thread.rs
│ │ ├── protocol/
│ │ │ ├── acl.rs
│ │ │ ├── append.rs
│ │ │ ├── authenticate.rs
│ │ │ ├── capability.rs
│ │ │ ├── copy_move.rs
│ │ │ ├── create.rs
│ │ │ ├── delete.rs
│ │ │ ├── enable.rs
│ │ │ ├── expunge.rs
│ │ │ ├── fetch.rs
│ │ │ ├── list.rs
│ │ │ ├── login.rs
│ │ │ ├── mod.rs
│ │ │ ├── namespace.rs
│ │ │ ├── quota.rs
│ │ │ ├── rename.rs
│ │ │ ├── search.rs
│ │ │ ├── select.rs
│ │ │ ├── status.rs
│ │ │ ├── store.rs
│ │ │ ├── subscribe.rs
│ │ │ └── thread.rs
│ │ ├── receiver.rs
│ │ └── utf7.rs
│ ├── jmap/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── addressbook/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── api/
│ │ │ ├── acl.rs
│ │ │ ├── auth.rs
│ │ │ ├── event_source.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ ├── request.rs
│ │ │ └── session.rs
│ │ ├── blob/
│ │ │ ├── copy.rs
│ │ │ ├── download.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── upload.rs
│ │ ├── calendar/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── calendar_event/
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── calendar_event_notification/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── changes/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── state.rs
│ │ ├── contact/
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── email/
│ │ │ ├── body.rs
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── headers.rs
│ │ │ ├── import.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ ├── set.rs
│ │ │ └── snippet.rs
│ │ ├── file/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── identity/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── lib.rs
│ │ ├── mailbox/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── participant_identity/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── principal/
│ │ │ ├── availability.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── query.rs
│ │ ├── push/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── quota/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── query.rs
│ │ ├── share_notification/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── sieve/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ ├── set.rs
│ │ │ └── validate.rs
│ │ ├── submission/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── thread/
│ │ │ ├── get.rs
│ │ │ └── mod.rs
│ │ ├── vacation/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ └── websocket/
│ │ ├── mod.rs
│ │ ├── stream.rs
│ │ └── upgrade.rs
│ ├── jmap-proto/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── error/
│ │ │ ├── method.rs
│ │ │ ├── mod.rs
│ │ │ ├── request.rs
│ │ │ └── set.rs
│ │ ├── lib.rs
│ │ ├── method/
│ │ │ ├── availability.rs
│ │ │ ├── changes.rs
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── import.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ ├── query_changes.rs
│ │ │ ├── search_snippet.rs
│ │ │ ├── set.rs
│ │ │ ├── upload.rs
│ │ │ └── validate.rs
│ │ ├── object/
│ │ │ ├── addressbook.rs
│ │ │ ├── blob.rs
│ │ │ ├── calendar.rs
│ │ │ ├── calendar_event.rs
│ │ │ ├── calendar_event_notification.rs
│ │ │ ├── contact.rs
│ │ │ ├── email.rs
│ │ │ ├── email_submission.rs
│ │ │ ├── file_node.rs
│ │ │ ├── identity.rs
│ │ │ ├── mailbox.rs
│ │ │ ├── mod.rs
│ │ │ ├── participant_identity.rs
│ │ │ ├── principal.rs
│ │ │ ├── push_subscription.rs
│ │ │ ├── quota.rs
│ │ │ ├── search_snippet.rs
│ │ │ ├── share_notification.rs
│ │ │ ├── sieve.rs
│ │ │ ├── thread.rs
│ │ │ └── vacation_response.rs
│ │ ├── references/
│ │ │ ├── eval.rs
│ │ │ ├── jsptr.rs
│ │ │ ├── mod.rs
│ │ │ └── resolve.rs
│ │ ├── request/
│ │ │ ├── capability.rs
│ │ │ ├── deserialize.rs
│ │ │ ├── method.rs
│ │ │ ├── mod.rs
│ │ │ ├── parser.rs
│ │ │ ├── reference.rs
│ │ │ └── websocket.rs
│ │ ├── response/
│ │ │ ├── mod.rs
│ │ │ ├── serialize.rs
│ │ │ └── status.rs
│ │ └── types/
│ │ ├── date.rs
│ │ ├── mod.rs
│ │ └── state.rs
│ ├── main/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── managesieve/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── core/
│ │ │ ├── client.rs
│ │ │ ├── mod.rs
│ │ │ └── session.rs
│ │ ├── lib.rs
│ │ └── op/
│ │ ├── authenticate.rs
│ │ ├── capability.rs
│ │ ├── checkscript.rs
│ │ ├── deletescript.rs
│ │ ├── getscript.rs
│ │ ├── havespace.rs
│ │ ├── listscripts.rs
│ │ ├── logout.rs
│ │ ├── mod.rs
│ │ ├── noop.rs
│ │ ├── putscript.rs
│ │ ├── renamescript.rs
│ │ └── setactive.rs
│ ├── migration/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── addressbook_v2.rs
│ │ ├── blob.rs
│ │ ├── calendar_v2.rs
│ │ ├── changelog.rs
│ │ ├── contact_v2.rs
│ │ ├── email_v1.rs
│ │ ├── email_v2.rs
│ │ ├── encryption_v1.rs
│ │ ├── encryption_v2.rs
│ │ ├── event_v1.rs
│ │ ├── event_v2.rs
│ │ ├── identity_v1.rs
│ │ ├── lib.rs
│ │ ├── mailbox.rs
│ │ ├── object.rs
│ │ ├── principal_v1.rs
│ │ ├── principal_v2.rs
│ │ ├── push_v1.rs
│ │ ├── push_v2.rs
│ │ ├── queue_v1.rs
│ │ ├── queue_v2.rs
│ │ ├── report.rs
│ │ ├── sieve_v1.rs
│ │ ├── sieve_v2.rs
│ │ ├── submission.rs
│ │ ├── tasks_v1.rs
│ │ ├── tasks_v2.rs
│ │ ├── threads.rs
│ │ ├── v011.rs
│ │ ├── v012.rs
│ │ ├── v013.rs
│ │ └── v014.rs
│ ├── nlp/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── classifier/
│ │ │ ├── adam.rs
│ │ │ ├── feature.rs
│ │ │ ├── ftrl.rs
│ │ │ ├── mod.rs
│ │ │ ├── model.rs
│ │ │ ├── reservoir.rs
│ │ │ ├── sgd.rs
│ │ │ └── train.rs
│ │ ├── language/
│ │ │ ├── detect.rs
│ │ │ ├── mod.rs
│ │ │ ├── search_snippet.rs
│ │ │ ├── stemmer.rs
│ │ │ └── stopwords.rs
│ │ ├── lib.rs
│ │ └── tokenizers/
│ │ ├── chinese.rs
│ │ ├── japanese.rs
│ │ ├── mod.rs
│ │ ├── space.rs
│ │ ├── stream.rs
│ │ ├── types.rs
│ │ └── word.rs
│ ├── pop3/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── client.rs
│ │ ├── lib.rs
│ │ ├── mailbox.rs
│ │ ├── op/
│ │ │ ├── authenticate.rs
│ │ │ ├── delete.rs
│ │ │ ├── fetch.rs
│ │ │ ├── list.rs
│ │ │ └── mod.rs
│ │ ├── protocol/
│ │ │ ├── mod.rs
│ │ │ ├── request.rs
│ │ │ └── response.rs
│ │ └── session.rs
│ ├── services/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── broadcast/
│ │ │ ├── mod.rs
│ │ │ ├── publisher.rs
│ │ │ └── subscriber.rs
│ │ ├── housekeeper/
│ │ │ └── mod.rs
│ │ ├── lib.rs
│ │ ├── state_manager/
│ │ │ ├── ece.rs
│ │ │ ├── http.rs
│ │ │ ├── manager.rs
│ │ │ ├── mod.rs
│ │ │ └── push.rs
│ │ └── task_manager/
│ │ ├── alarm.rs
│ │ ├── imip.rs
│ │ ├── index.rs
│ │ ├── lock.rs
│ │ ├── merge_threads.rs
│ │ └── mod.rs
│ ├── smtp/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── core/
│ │ │ ├── mod.rs
│ │ │ ├── params.rs
│ │ │ └── throttle.rs
│ │ ├── inbound/
│ │ │ ├── auth.rs
│ │ │ ├── data.rs
│ │ │ ├── ehlo.rs
│ │ │ ├── hooks/
│ │ │ │ ├── client.rs
│ │ │ │ ├── message.rs
│ │ │ │ └── mod.rs
│ │ │ ├── mail.rs
│ │ │ ├── milter/
│ │ │ │ ├── client.rs
│ │ │ │ ├── macros.rs
│ │ │ │ ├── message.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── protocol.rs
│ │ │ │ └── receiver.rs
│ │ │ ├── mod.rs
│ │ │ ├── rcpt.rs
│ │ │ ├── session.rs
│ │ │ ├── spam.rs
│ │ │ ├── spawn.rs
│ │ │ └── vrfy.rs
│ │ ├── lib.rs
│ │ ├── outbound/
│ │ │ ├── client.rs
│ │ │ ├── dane/
│ │ │ │ ├── dnssec.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── verify.rs
│ │ │ ├── delivery.rs
│ │ │ ├── local.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── mta_sts/
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── parse.rs
│ │ │ │ └── verify.rs
│ │ │ └── session.rs
│ │ ├── queue/
│ │ │ ├── dsn.rs
│ │ │ ├── manager.rs
│ │ │ ├── mod.rs
│ │ │ ├── quota.rs
│ │ │ ├── spool.rs
│ │ │ └── throttle.rs
│ │ ├── reporting/
│ │ │ ├── analysis.rs
│ │ │ ├── dkim.rs
│ │ │ ├── dmarc.rs
│ │ │ ├── mod.rs
│ │ │ ├── scheduler.rs
│ │ │ ├── spf.rs
│ │ │ └── tls.rs
│ │ └── scripts/
│ │ ├── envelope.rs
│ │ ├── event_loop.rs
│ │ ├── exec.rs
│ │ └── mod.rs
│ ├── spam-filter/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── analysis/
│ │ │ ├── classifier.rs
│ │ │ ├── date.rs
│ │ │ ├── dmarc.rs
│ │ │ ├── domain.rs
│ │ │ ├── ehlo.rs
│ │ │ ├── from.rs
│ │ │ ├── headers.rs
│ │ │ ├── html.rs
│ │ │ ├── init.rs
│ │ │ ├── ip.rs
│ │ │ ├── llm.rs
│ │ │ ├── messageid.rs
│ │ │ ├── mime.rs
│ │ │ ├── mod.rs
│ │ │ ├── pyzor.rs
│ │ │ ├── received.rs
│ │ │ ├── recipient.rs
│ │ │ ├── replyto.rs
│ │ │ ├── rules.rs
│ │ │ ├── score.rs
│ │ │ ├── subject.rs
│ │ │ └── url.rs
│ │ ├── lib.rs
│ │ └── modules/
│ │ ├── classifier.rs
│ │ ├── dnsbl.rs
│ │ ├── expression.rs
│ │ ├── html.rs
│ │ ├── mod.rs
│ │ ├── pyzor.rs
│ │ └── sanitize.rs
│ ├── store/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── backend/
│ │ │ ├── azure/
│ │ │ │ └── mod.rs
│ │ │ ├── composite/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read_replica.rs
│ │ │ │ ├── sharded_blob.rs
│ │ │ │ └── sharded_lookup.rs
│ │ │ ├── elastic/
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── search.rs
│ │ │ ├── foundationdb/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ └── write.rs
│ │ │ ├── fs/
│ │ │ │ └── mod.rs
│ │ │ ├── http/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ └── mod.rs
│ │ │ ├── kafka/
│ │ │ │ ├── mod.rs
│ │ │ │ └── pubsub.rs
│ │ │ ├── meili/
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── search.rs
│ │ │ ├── memory/
│ │ │ │ └── mod.rs
│ │ │ ├── mod.rs
│ │ │ ├── mysql/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ ├── search.rs
│ │ │ │ └── write.rs
│ │ │ ├── nats/
│ │ │ │ ├── mod.rs
│ │ │ │ └── pubsub.rs
│ │ │ ├── postgres/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ ├── search.rs
│ │ │ │ ├── tls.rs
│ │ │ │ └── write.rs
│ │ │ ├── redis/
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── pool.rs
│ │ │ │ └── pubsub.rs
│ │ │ ├── rocksdb/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ └── write.rs
│ │ │ ├── s3/
│ │ │ │ └── mod.rs
│ │ │ ├── sqlite/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── pool.rs
│ │ │ │ ├── read.rs
│ │ │ │ └── write.rs
│ │ │ └── zenoh/
│ │ │ ├── mod.rs
│ │ │ └── pubsub.rs
│ │ ├── config.rs
│ │ ├── dispatch/
│ │ │ ├── blob.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── pubsub.rs
│ │ │ ├── search.rs
│ │ │ └── store.rs
│ │ ├── lib.rs
│ │ ├── query/
│ │ │ ├── acl.rs
│ │ │ ├── log.rs
│ │ │ └── mod.rs
│ │ ├── search/
│ │ │ ├── bm_u32.rs
│ │ │ ├── bm_u64.rs
│ │ │ ├── document.rs
│ │ │ ├── fields.rs
│ │ │ ├── index.rs
│ │ │ ├── local.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ ├── split.rs
│ │ │ └── term.rs
│ │ └── write/
│ │ ├── assert.rs
│ │ ├── batch.rs
│ │ ├── bitpack.rs
│ │ ├── blob.rs
│ │ ├── key.rs
│ │ ├── log.rs
│ │ ├── mod.rs
│ │ └── serialize.rs
│ ├── trc/
│ │ ├── Cargo.toml
│ │ ├── event-macro/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ └── src/
│ │ ├── atomics/
│ │ │ ├── array.rs
│ │ │ ├── bitset.rs
│ │ │ ├── counter.rs
│ │ │ ├── gauge.rs
│ │ │ ├── histogram.rs
│ │ │ └── mod.rs
│ │ ├── event/
│ │ │ ├── conv.rs
│ │ │ ├── description.rs
│ │ │ ├── level.rs
│ │ │ ├── metrics.rs
│ │ │ └── mod.rs
│ │ ├── ipc/
│ │ │ ├── bitset.rs
│ │ │ ├── channel.rs
│ │ │ ├── collector.rs
│ │ │ ├── metrics.rs
│ │ │ ├── mod.rs
│ │ │ └── subscriber.rs
│ │ ├── lib.rs
│ │ ├── macros.rs
│ │ └── serializers/
│ │ ├── binary.rs
│ │ ├── json.rs
│ │ ├── mod.rs
│ │ └── text.rs
│ ├── types/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── acl.rs
│ │ ├── blob.rs
│ │ ├── blob_hash.rs
│ │ ├── collection.rs
│ │ ├── dead_property.rs
│ │ ├── field.rs
│ │ ├── id.rs
│ │ ├── keyword.rs
│ │ ├── lib.rs
│ │ ├── semver.rs
│ │ ├── special_use.rs
│ │ └── type_state.rs
│ └── utils/
│ ├── Cargo.toml
│ ├── proc-macros/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── src/
│ ├── bimap.rs
│ ├── cache.rs
│ ├── chained_bytes.rs
│ ├── cheeky_hash.rs
│ ├── codec/
│ │ ├── base32_custom.rs
│ │ ├── leb128.rs
│ │ └── mod.rs
│ ├── config/
│ │ ├── cron.rs
│ │ ├── http.rs
│ │ ├── ipmask.rs
│ │ ├── mod.rs
│ │ ├── parser.rs
│ │ └── utils.rs
│ ├── glob.rs
│ ├── lib.rs
│ ├── map/
│ │ ├── bitmap.rs
│ │ ├── mod.rs
│ │ ├── mutex_map.rs
│ │ └── vec_map.rs
│ ├── snowflake.rs
│ ├── suffixlist.rs
│ ├── template.rs
│ ├── topological.rs
│ └── url_params.rs
├── docker-bake.hcl
├── install.sh
├── resources/
│ ├── apparmor.d/
│ │ └── stalwart-mail
│ ├── config/
│ │ └── config.toml
│ ├── docker/
│ │ ├── Dockerfile.fdb
│ │ ├── download.sh
│ │ └── entrypoint.sh
│ ├── html-templates/
│ │ ├── calendar-alarm.html
│ │ ├── calendar-alarm.html.min
│ │ ├── calendar-alarm.mjml
│ │ ├── calendar-invite.html
│ │ ├── calendar-invite.html.min
│ │ └── calendar-invite.mjml
│ ├── locales/
│ │ └── i18n.yml
│ ├── scripts/
│ │ └── ossify.py
│ └── systemd/
│ ├── stalwart-mail.service
│ └── stalwart.mail.plist
└── tests/
├── Cargo.toml
├── resources/
│ ├── acme/
│ │ ├── Docker.pebble
│ │ ├── config.toml
│ │ ├── docker-compose-pebble.yaml
│ │ └── test_acme.sh
│ ├── crypto/
│ │ ├── cert_mixed.pem
│ │ ├── cert_pgp.der
│ │ ├── cert_pgp.pem
│ │ ├── cert_smime.der
│ │ ├── cert_smime.pem
│ │ └── is_encrypted.txt
│ ├── imap/
│ │ ├── 000.imap
│ │ ├── 000.txt
│ │ ├── 001.imap
│ │ ├── 001.txt
│ │ ├── 002.imap
│ │ ├── 002.txt
│ │ ├── 003.imap
│ │ ├── 003.txt
│ │ ├── 004.imap
│ │ ├── 004.txt
│ │ ├── 005.imap
│ │ ├── 005.txt
│ │ ├── 006.imap
│ │ ├── 006.txt
│ │ ├── 007.imap
│ │ ├── 007.txt
│ │ ├── 008.imap
│ │ ├── 008.txt
│ │ ├── 009.imap
│ │ ├── 009.txt
│ │ ├── 010.imap
│ │ ├── 010.txt
│ │ ├── 011.imap
│ │ ├── 011.txt
│ │ ├── 012.imap
│ │ ├── 012.txt
│ │ ├── 013.imap
│ │ ├── 013.txt
│ │ ├── 014.imap
│ │ └── 014.txt
│ ├── imap-test/
│ │ ├── append
│ │ ├── append-binary
│ │ ├── atoms
│ │ ├── broken/
│ │ │ ├── search-intdate
│ │ │ └── search-intdate.mbox
│ │ ├── catenate
│ │ ├── catenate-multiappend
│ │ ├── close
│ │ ├── copy
│ │ ├── default.mbox
│ │ ├── esearch
│ │ ├── esearch-condstore
│ │ ├── esearch.mbox
│ │ ├── esort
│ │ ├── expunge
│ │ ├── expunge2
│ │ ├── fetch
│ │ ├── fetch-binary-mime
│ │ ├── fetch-binary-mime-base64
│ │ ├── fetch-binary-mime-base64.mbox
│ │ ├── fetch-binary-mime-qp
│ │ ├── fetch-binary-mime-qp.mbox
│ │ ├── fetch-binary-mime.mbox
│ │ ├── fetch-body
│ │ ├── fetch-body-message-rfc822
│ │ ├── fetch-body-message-rfc822-mime
│ │ ├── fetch-body-message-rfc822-mime.mbox
│ │ ├── fetch-body-message-rfc822-x2
│ │ ├── fetch-body-message-rfc822-x2.mbox
│ │ ├── fetch-body-message-rfc822.mbox
│ │ ├── fetch-body-mime
│ │ ├── fetch-body-mime.mbox
│ │ ├── fetch-body.mbox
│ │ ├── fetch-bodystructure
│ │ ├── fetch-bodystructure.mbox
│ │ ├── fetch-envelope
│ │ ├── fetch-envelope.mbox
│ │ ├── id
│ │ ├── list
│ │ ├── listext
│ │ ├── logout
│ │ ├── move
│ │ ├── multiappend
│ │ ├── mutf7
│ │ ├── nil
│ │ ├── nil.mbox
│ │ ├── notify
│ │ ├── pipeline
│ │ ├── search-addresses
│ │ ├── search-addresses.mbox
│ │ ├── search-body
│ │ ├── search-body.mbox
│ │ ├── search-context-update
│ │ ├── search-context-update2
│ │ ├── search-context-update3
│ │ ├── search-date
│ │ ├── search-date.mbox
│ │ ├── search-flags
│ │ ├── search-header
│ │ ├── search-header.mbox
│ │ ├── search-partial
│ │ ├── search-partial.mbox
│ │ ├── search-sets
│ │ ├── search-size
│ │ ├── search-size.mbox
│ │ ├── select
│ │ ├── select.mbox
│ │ ├── sort-addresses
│ │ ├── sort-addresses.mbox
│ │ ├── sort-arrival
│ │ ├── sort-arrival.mbox
│ │ ├── sort-date
│ │ ├── sort-date.mbox
│ │ ├── sort-display-from
│ │ ├── sort-display-from.mbox
│ │ ├── sort-display-to
│ │ ├── sort-display-to.mbox
│ │ ├── sort-partial
│ │ ├── sort-partial.mbox
│ │ ├── sort-size
│ │ ├── sort-size.mbox
│ │ ├── sort-subject
│ │ ├── sort-subject.mbox
│ │ ├── store
│ │ ├── subscribe
│ │ ├── thread
│ │ ├── thread-orderedsubject
│ │ ├── thread-orderedsubject.mbox
│ │ ├── thread-orderedsubject2
│ │ ├── thread-orderedsubject2.mbox
│ │ ├── thread.mbox
│ │ ├── thread2
│ │ ├── thread2.mbox
│ │ ├── thread3
│ │ ├── thread3.mbox
│ │ ├── thread4
│ │ ├── thread4.mbox
│ │ ├── thread5
│ │ ├── thread5.mbox
│ │ ├── thread6
│ │ ├── thread6.mbox
│ │ ├── thread7
│ │ ├── thread7.mbox
│ │ ├── thread8
│ │ ├── thread8.mbox
│ │ ├── uidplus
│ │ ├── uidvalidity
│ │ ├── uidvalidity-rename
│ │ ├── urlauth
│ │ ├── urlauth-binary
│ │ ├── urlauth-binary.mbox
│ │ └── urlauth2
│ ├── itip/
│ │ ├── google_calendar.txt
│ │ ├── itip_incoming.txt
│ │ ├── put_validation.txt
│ │ ├── rfc5546_event_recurring.txt
│ │ ├── rfc5546_event_single.txt
│ │ ├── rfc5546_todo.txt
│ │ ├── rfc6638_recurring.txt
│ │ └── rfc6638_single.txt
│ ├── jmap/
│ │ ├── email_get/
│ │ │ ├── headers.eml
│ │ │ ├── headers.json
│ │ │ ├── message_attachment.eml
│ │ │ ├── message_attachment.json
│ │ │ ├── multipart_alternative.eml
│ │ │ ├── multipart_alternative.json
│ │ │ ├── multipart_cid.eml
│ │ │ ├── multipart_cid.json
│ │ │ ├── multipart_mixed.eml
│ │ │ ├── multipart_mixed.json
│ │ │ ├── multipart_related.eml
│ │ │ ├── multipart_related.json
│ │ │ ├── rfc8621.eml
│ │ │ ├── rfc8621.json
│ │ │ ├── single_part.eml
│ │ │ ├── single_part.json
│ │ │ ├── text_body_missing.eml
│ │ │ ├── text_body_missing.json
│ │ │ ├── text_body_missing_multipart.eml
│ │ │ └── text_body_missing_multipart.json
│ │ ├── email_parse/
│ │ │ ├── attachment.eml
│ │ │ ├── attachment.json
│ │ │ ├── attachment.part1
│ │ │ ├── attachment.part2
│ │ │ ├── attachment.part3
│ │ │ ├── attachment_b64.eml
│ │ │ ├── attachment_b64.json
│ │ │ ├── attachment_b64.part1
│ │ │ ├── attachment_b64.part2
│ │ │ ├── headers.eml
│ │ │ └── headers.json
│ │ ├── email_set/
│ │ │ ├── headers.eml
│ │ │ ├── headers.jmap
│ │ │ ├── headers.json
│ │ │ ├── minimal.eml
│ │ │ ├── minimal.jmap
│ │ │ ├── minimal.json
│ │ │ ├── mixed.eml
│ │ │ ├── mixed.jmap
│ │ │ ├── mixed.json
│ │ │ ├── nested_body.eml
│ │ │ ├── nested_body.jmap
│ │ │ ├── nested_body.json
│ │ │ ├── rfc8621_1.eml
│ │ │ ├── rfc8621_1.jmap
│ │ │ ├── rfc8621_1.json
│ │ │ ├── rfc8621_2.eml
│ │ │ ├── rfc8621_2.jmap
│ │ │ └── rfc8621_2.json
│ │ ├── email_snippet/
│ │ │ ├── html.eml
│ │ │ ├── mixed.eml
│ │ │ ├── subpart.eml
│ │ │ ├── text_plain.eml
│ │ │ └── text_plain_chinese.eml
│ │ └── sieve/
│ │ ├── test_discard_reject.sieve
│ │ ├── test_include.sieve
│ │ ├── test_include_global.sieve
│ │ ├── test_include_this.sieve
│ │ ├── test_mailbox.sieve
│ │ ├── test_notify_fcc.sieve
│ │ ├── test_redirect_enclose.sieve
│ │ ├── validate_error.sieve
│ │ └── validate_ok.sieve
│ ├── ldap/
│ │ ├── ldap.cfg
│ │ └── run_glauth.sh
│ ├── otel/
│ │ ├── docker-compose.yaml
│ │ ├── otel-collector-config.yaml
│ │ └── stalwart-config.toml
│ ├── proxy-protocol/
│ │ ├── Docker.haproxy
│ │ └── haproxy.cfg
│ ├── scripts/
│ │ ├── create_test_cluster.sh
│ │ ├── create_test_env.sh
│ │ ├── create_test_users.sh
│ │ ├── imap-log-parser.py
│ │ ├── imap_import.py
│ │ ├── imap_import_single.py
│ │ ├── stress_test.py
│ │ └── stress_test_prepare.py
│ ├── smtp/
│ │ ├── antispam/
│ │ │ ├── bounce.test
│ │ │ ├── classifier.ham
│ │ │ ├── classifier.spam
│ │ │ ├── classifier.test
│ │ │ ├── classifier_features.test
│ │ │ ├── classifier_html.test
│ │ │ ├── combined.test
│ │ │ ├── date.test
│ │ │ ├── dmarc.test
│ │ │ ├── from.test
│ │ │ ├── headers.test
│ │ │ ├── helo.test
│ │ │ ├── html.test
│ │ │ ├── ip.test
│ │ │ ├── llm.test
│ │ │ ├── messageid.test
│ │ │ ├── mime.test
│ │ │ ├── pyzor.test
│ │ │ ├── rbl.test
│ │ │ ├── received.test
│ │ │ ├── recipient.test
│ │ │ ├── replyto.test
│ │ │ ├── spamtrap.test
│ │ │ ├── subject.test
│ │ │ └── url.test
│ │ ├── certs/
│ │ │ ├── tls_cert.pem
│ │ │ └── tls_privatekey.pem
│ │ ├── config/
│ │ │ ├── if-blocks.toml
│ │ │ ├── lists.toml
│ │ │ ├── rules-dynvalue.toml
│ │ │ ├── rules-eval.toml
│ │ │ ├── rules.toml
│ │ │ ├── servers.toml
│ │ │ ├── throttle.toml
│ │ │ └── toml-parser.toml
│ │ ├── dane/
│ │ │ ├── dns.txt
│ │ │ ├── internet.nl.0.cert
│ │ │ ├── internet.nl.1.cert
│ │ │ ├── mail.ietf.org.0.cert
│ │ │ ├── mail.ietf.org.1.cert
│ │ │ ├── mail.ietf.org.2.cert
│ │ │ └── mail.ietf.org.3.cert
│ │ ├── dsn/
│ │ │ ├── delay.eml
│ │ │ ├── failure.eml
│ │ │ ├── mixed.eml
│ │ │ ├── original.txt
│ │ │ └── success.eml
│ │ ├── lists/
│ │ │ ├── test-list1.txt
│ │ │ └── test-list2.txt
│ │ ├── messages/
│ │ │ ├── arc.eml
│ │ │ ├── dkim.eml
│ │ │ ├── invalid_arc.eml
│ │ │ ├── invalid_dkim.eml
│ │ │ ├── loop.eml
│ │ │ ├── multipart.eml
│ │ │ ├── no_dkim.eml
│ │ │ └── no_msgid.eml
│ │ ├── milter/
│ │ │ ├── message.eml
│ │ │ └── message.json
│ │ ├── reports/
│ │ │ ├── arf1.eml
│ │ │ ├── arf2.eml
│ │ │ ├── arf3.eml
│ │ │ ├── arf4.eml
│ │ │ ├── arf5.eml
│ │ │ ├── dmarc1.eml
│ │ │ ├── dmarc2.eml
│ │ │ ├── dmarc3.eml
│ │ │ ├── dmarc4.eml
│ │ │ ├── dmarc5.eml
│ │ │ ├── tls1.eml
│ │ │ └── tls2.eml
│ │ └── sieve/
│ │ ├── awl.sieve
│ │ ├── awl_include.sieve
│ │ ├── stage_connect.sieve
│ │ ├── stage_data.sieve
│ │ ├── stage_ehlo.sieve
│ │ ├── stage_mail.sieve
│ │ └── stage_rcpt.sieve
│ ├── tls_cert.pem
│ └── tls_privatekey.pem
└── src/
├── cluster/
│ ├── broadcast.rs
│ ├── mod.rs
│ └── stress.rs
├── directory/
│ ├── imap.rs
│ ├── internal.rs
│ ├── ldap.rs
│ ├── mod.rs
│ ├── oidc.rs
│ ├── smtp.rs
│ └── sql.rs
├── http_server.rs
├── imap/
│ ├── acl.rs
│ ├── antispam.rs
│ ├── append.rs
│ ├── basic.rs
│ ├── body_structure.rs
│ ├── condstore.rs
│ ├── copy_move.rs
│ ├── fetch.rs
│ ├── idle.rs
│ ├── mailbox.rs
│ ├── managesieve.rs
│ ├── mod.rs
│ ├── pop.rs
│ ├── search.rs
│ ├── store.rs
│ └── thread.rs
├── jmap/
│ ├── auth/
│ │ ├── limits.rs
│ │ ├── mod.rs
│ │ ├── oauth.rs
│ │ ├── permissions.rs
│ │ └── quota.rs
│ ├── calendar/
│ │ ├── acl.rs
│ │ ├── alarm.rs
│ │ ├── calendars.rs
│ │ ├── event.rs
│ │ ├── identity.rs
│ │ ├── mod.rs
│ │ └── notification.rs
│ ├── contacts/
│ │ ├── acl.rs
│ │ ├── addressbook.rs
│ │ ├── contact.rs
│ │ └── mod.rs
│ ├── core/
│ │ ├── blob.rs
│ │ ├── event_source.rs
│ │ ├── mod.rs
│ │ ├── push_subscription.rs
│ │ └── websocket.rs
│ ├── files/
│ │ ├── acl.rs
│ │ ├── mod.rs
│ │ └── node.rs
│ ├── mail/
│ │ ├── acl.rs
│ │ ├── antispam.rs
│ │ ├── changes.rs
│ │ ├── copy.rs
│ │ ├── crypto.rs
│ │ ├── delivery.rs
│ │ ├── get.rs
│ │ ├── mailbox.rs
│ │ ├── mod.rs
│ │ ├── parse.rs
│ │ ├── query.rs
│ │ ├── query_changes.rs
│ │ ├── search_snippet.rs
│ │ ├── set.rs
│ │ ├── sieve_script.rs
│ │ ├── submission.rs
│ │ ├── thread_get.rs
│ │ ├── thread_merge.rs
│ │ └── vacation_response.rs
│ ├── mod.rs
│ ├── principal/
│ │ ├── availability.rs
│ │ ├── get.rs
│ │ └── mod.rs
│ └── server/
│ ├── enterprise.rs
│ ├── mod.rs
│ ├── purge.rs
│ └── webhooks.rs
├── lib.rs
├── smtp/
│ ├── config.rs
│ ├── inbound/
│ │ ├── antispam.rs
│ │ ├── asn.rs
│ │ ├── auth.rs
│ │ ├── basic.rs
│ │ ├── data.rs
│ │ ├── dmarc.rs
│ │ ├── ehlo.rs
│ │ ├── limits.rs
│ │ ├── mail.rs
│ │ ├── milter.rs
│ │ ├── mod.rs
│ │ ├── rcpt.rs
│ │ ├── rewrite.rs
│ │ ├── scripts.rs
│ │ ├── sign.rs
│ │ ├── throttle.rs
│ │ └── vrfy.rs
│ ├── lookup/
│ │ ├── mod.rs
│ │ ├── sql.rs
│ │ └── utils.rs
│ ├── management/
│ │ ├── mod.rs
│ │ ├── queue.rs
│ │ └── report.rs
│ ├── mod.rs
│ ├── outbound/
│ │ ├── dane.rs
│ │ ├── extensions.rs
│ │ ├── fallback_relay.rs
│ │ ├── ip_lookup.rs
│ │ ├── lmtp.rs
│ │ ├── mod.rs
│ │ ├── mta_sts.rs
│ │ ├── smtp.rs
│ │ ├── throttle.rs
│ │ └── tls.rs
│ ├── queue/
│ │ ├── concurrent.rs
│ │ ├── dsn.rs
│ │ ├── manager.rs
│ │ ├── mod.rs
│ │ ├── retry.rs
│ │ └── virtualq.rs
│ ├── reporting/
│ │ ├── analyze.rs
│ │ ├── dmarc.rs
│ │ ├── mod.rs
│ │ ├── scheduler.rs
│ │ └── tls.rs
│ └── session.rs
├── store/
│ ├── blob.rs
│ ├── cleanup.rs
│ ├── import_export.rs
│ ├── lookup.rs
│ ├── mod.rs
│ ├── ops.rs
│ └── query.rs
└── webdav/
├── acl.rs
├── basic.rs
├── cal_alarm.rs
├── cal_itip.rs
├── cal_query.rs
├── cal_scheduling.rs
├── card_query.rs
├── copy_move.rs
├── lock.rs
├── mkcol.rs
├── mod.rs
├── multiget.rs
├── principals.rs
├── prop.rs
├── put_get.rs
└── sync.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
// Ignore everything
*
// Allow what is needed
!crates
!tests
!resources
!Cargo.lock
!Cargo.toml
================================================
FILE: .editorconfig
================================================
# https://EditorConfig.org
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 100
================================================
FILE: .github/DISCUSSION_TEMPLATE/issue-triage.yml
================================================
labels: ["triage"]
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> Please review the [documentation](https://stalw.art/docs/), check the [FAQ](https://stalw.art/docs/faq), and search existing [Discussions](https://github.com/stalwartlabs/stalwart/discussions) and [Issues](https://github.com/stalwartlabs/stalwart/issues?q=sort%3Areactions-desc) before opening a new Discussion.
>
> Most reported issues turn out to be configuration problems rather than actual bugs. Starting here helps us triage effectively—if this is confirmed as a bug, we'll create an Issue for tracking.
- type: markdown
attributes:
value: "# Issue Details"
- type: textarea
attributes:
label: Issue Description
description: |
Provide a detailed description of the issue. Include relevant context such as your configuration, environment, and any recent changes that might have led to the issue.
placeholder: |
When trying to send an email via SMTP, the connection is accepted but the message is rejected with error 550.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: |
Describe how you expect Stalwart to behave in this situation. Include any relevant documentation links.
placeholder: |
The email should be accepted and delivered to the recipient's mailbox.
validations:
required: false
- type: textarea
attributes:
label: Actual Behavior
description: |
Describe how Stalwart actually behaves in this situation. If it is not immediately obvious how the actual behavior differs from the expected behavior described above, please mention the deviation specifically.
placeholder: |
The email is rejected with error: "550 5.7.1 Relay access denied"
validations:
required: false
- type: textarea
attributes:
label: Reproduction Steps
description: |
Provide a detailed set of step-by-step instructions for reproducing this issue.
placeholder: |
1. Configure Stalwart with the attached configuration.
2. Attempt to send an email from user@example.com to external@domain.com.
3. Observe the 550 error in the SMTP session.
validations:
required: false
- type: textarea
attributes:
label: Relevant Log Output
description: |
Please copy and paste any relevant log output. Set logging level to `trace` if you can't find any relevant errors in the log.
render: shell
- type: dropdown
attributes:
label: Stalwart Version
description: What version of Stalwart are you running?
options:
- v0.15.x
- v0.14.x
- v0.13.x
- v0.12.x or lower
validations:
required: true
- type: dropdown
attributes:
label: Installation Method
description: How did you install Stalwart?
options:
- Docker
- Binary (Linux)
- Binary (macOS)
- Binary (FreeBSD)
- Binary (Windows)
- NixOS
- Built from source
validations:
required: true
- type: dropdown
attributes:
label: Database Backend
description: What database are you using for the data store?
options:
- RocksDB
- FoundationDB
- PostgreSQL
- MySQL
- SQLite
validations:
required: true
- type: dropdown
attributes:
label: Blob Storage
description: What blob storage are you using?
options:
- RocksDB
- FoundationDB
- PostgreSQL
- MySQL
- SQLite
- Filesystem
- S3-compatible
- Azure
validations:
required: true
- type: dropdown
attributes:
label: Search Engine
description: What search engine are you using?
options:
- Internal
- Meilisearch
- Elasticsearch
- PostgreSQL
- MySQL
validations:
required: true
- type: dropdown
attributes:
label: Directory Backend
description: Where is your directory/user database located?
options:
- Internal
- SQL
- LDAP
- OIDC
validations:
required: true
- type: textarea
attributes:
label: Additional Context
description: |
Add any other context about the problem here. This could include:
- Client software and versions (Thunderbird, Apple Mail, K-9, etc.)
- Proxy or reverse proxy configuration (nginx, Traefik, etc.)
- Network setup (NAT, firewall rules, etc.)
validations:
required: false
- type: markdown
attributes:
value: |
# Acknowledgements
> [!TIP]
> Use these links to review existing [Discussions](https://github.com/stalwartlabs/stalwart/discussions) and [Issues](https://github.com/stalwartlabs/stalwart/issues?q=sort%3Areactions-desc).
- type: checkboxes
attributes:
label: "I acknowledge that:"
options:
- label: I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
required: true
- label: I have searched the Stalwart repository (both open and closed Discussions and Issues) and confirm this is not a duplicate.
required: true
- label: I have set the logging level to `trace` and included relevant log output if applicable.
required: false
- label: I agree to follow the project's [Code of Conduct](https://github.com/stalwartlabs/.github/blob/main/CODE_OF_CONDUCT.md).
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Report an Issue
url: https://github.com/stalwartlabs/stalwart/discussions/new?category=issue-triage
about: Report a potential bug. Confirmed bugs will be converted to Issues.
- name: Questions & Support
url: https://github.com/stalwartlabs/stalwart/discussions/new?category=q-a
about: Get help with configuration, troubleshooting, or general questions.
- name: Feature Requests
url: https://github.com/stalwartlabs/stalwart/discussions/new?category=feature-requests-and-ideas
about: Suggest new features or improvements.
- name: Join Stalwart's Reddit
url: https://www.reddit.com/r/stalwartlabs
about: Join our subreddit for help, discussions and release announcements.
- name: Join Stalwart's Discord
url: https://discord.com/servers/stalwart-923615863037390889
about: Join our Discord server for help, discussions and release announcements.
================================================
FILE: .github/ISSUE_TEMPLATE/confirmed_issue.yml
================================================
name: Confirmed Bug Report
description: Only for issues that have been discussed and confirmed as bugs in GitHub Discussions.
labels: ["bug"]
title: "🪲: "
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> This template is **only** for issues that have already been discussed and confirmed as bugs in the [Discussions](https://github.com/stalwartlabs/stalwart/discussions) section.
>
> If you haven't had your issue confirmed yet, please [start a Discussion](https://github.com/stalwartlabs/stalwart/discussions/new?category=issue-triage) first.
- type: input
attributes:
label: Discussion Link
description: Provide the link to the Discussion where this issue was confirmed as a bug.
placeholder: https://github.com/stalwartlabs/stalwart/discussions/1234
validations:
required: true
- type: textarea
attributes:
label: Bug Summary
description: Brief summary of the confirmed bug.
validations:
required: true
- type: textarea
attributes:
label: Additional Information
description: |
Include any additional information not covered in the original Discussion, such as new findings, workarounds discovered, or updated reproduction steps.
validations:
required: false
- type: checkboxes
attributes:
label: Confirmation
options:
- label: This issue was discussed and confirmed as a bug in the linked Discussion.
required: true
- label: I have included the link to the Discussion above.
required: true
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
# Workflow files stored in the default location of `.github/workflows`
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/ci.yml
================================================
name: "CI"
on:
workflow_dispatch:
inputs:
Docker:
required: false
default: false
type: boolean
Release:
required: false
default: false
type: boolean
push:
tags: ["v*.*.*"]
env:
SCCACHE_GHA_ENABLED: true
RUSTC_WRAPPER: sccache
CARGO_TERM_COLOR: always
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
multiarch:
strategy:
fail-fast: false
matrix:
include:
- variant: gnu
- variant: musl
name: Merge image / ${{matrix.variant}}
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
attestations: write
packages: write
needs: [linux]
if: github.event_name == 'push' || inputs.Docker
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Log In to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{github.repository_owner}}
password: ${{github.token}}
- name: Log In to DockerHub
uses: docker/login-action@v3
with:
username: ${{secrets.DOCKERHUB_USERNAME}}
password: ${{secrets.DOCKERHUB_TOKEN}}
- name: Download ${{matrix.variant}} meta bake definition
uses: actions/download-artifact@v7
with:
name: bake-meta-${{matrix.variant}}
path: ${{ runner.temp }}/${{matrix.variant}}
- name: Download ${{matrix.variant}} digests
uses: actions/download-artifact@v7
with:
path: ${{ runner.temp }}/${{matrix.variant}}/digests
pattern: digests-${{matrix.variant}}-*
merge-multiple: true
- name: Create ${{matrix.variant}} manifest list and push
working-directory: ${{ runner.temp }}/${{matrix.variant}}/digests
run: |
docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("ghcr.io/${{github.repository}}")) | "-t " + .) | join(" ")' ${{ runner.temp }}/${{matrix.variant}}/bake-meta.json) \
$(printf 'ghcr.io/${{github.repository}}@sha256:%s ' *)
docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("index.docker.io/${{github.repository}}")) | "-t " + .) | join(" ")' ${{ runner.temp }}/${{matrix.variant}}/bake-meta.json) \
$(printf 'index.docker.io/${{github.repository}}@sha256:%s ' *)
- name: Inspect ${{matrix.variant}} image
id: manifest-digest
run: |
docker buildx imagetools inspect --format '{{json .Manifest}}' ghcr.io/${{github.repository}}:$(jq -r '.target."docker-metadata-action".args.DOCKER_META_VERSION' ${{ runner.temp }}/${{matrix.variant}}/bake-meta.json) | jq -r '.digest' > GHCR_DIGEST_SHA
echo "GHCR_DIGEST_SHA=$(cat GHCR_DIGEST_SHA)" | tee -a "${GITHUB_ENV}"
docker buildx imagetools inspect --format '{{json .Manifest}}' index.docker.io/${{github.repository}}:$(jq -r '.target."docker-metadata-action".args.DOCKER_META_VERSION' ${{ runner.temp }}/${{matrix.variant}}/bake-meta.json) | jq -r '.digest' > DOCKERHUB_DIGEST_SHA
echo "DOCKERHUB_DIGEST_SHA=$(cat DOCKERHUB_DIGEST_SHA)" | tee -a "${GITHUB_ENV}"
cosign sign --yes $(jq --arg GHCR_DIGEST_SHA "$(cat GHCR_DIGEST_SHA)" -cr '.target."docker-metadata-action".tags | map(select(startswith("ghcr.io/${{github.repository}}")) | . + "@" + $GHCR_DIGEST_SHA) | join(" ")' ${{ runner.temp }}/${{matrix.variant}}/bake-meta.json)
cosign sign --yes $(jq --arg DOCKERHUB_DIGEST_SHA "$(cat DOCKERHUB_DIGEST_SHA)" -cr '.target."docker-metadata-action".tags | map(select(startswith("index.docker.io/${{github.repository}}")) | . + "@" + $DOCKERHUB_DIGEST_SHA) | join(" ")' ${{ runner.temp }}/${{matrix.variant}}/bake-meta.json)
- name: Attest GHCR
uses: actions/attest-build-provenance@v3
with:
subject-name: ghcr.io/${{github.repository}}
subject-digest: ${{ env.GHCR_DIGEST_SHA }}
push-to-registry: true
- name: Attest Dockerhub
uses: actions/attest-build-provenance@v3
with:
subject-name: index.docker.io/${{github.repository}}
subject-digest: ${{ env.DOCKERHUB_DIGEST_SHA }}
push-to-registry: true
linux:
permissions:
id-token: write
contents: write
attestations: write
packages: write
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
platform: linux/amd64
suffix: ""
build_env: ""
- target: x86_64-unknown-linux-musl
platform: linux/amd64
suffix: "-alpine"
build_env: ""
- target: aarch64-unknown-linux-gnu
platform: linux/arm64
suffix: ""
build_env: "JEMALLOC_SYS_WITH_LG_PAGE=16 "
- target: aarch64-unknown-linux-musl
platform: linux/arm64
suffix: "-alpine"
build_env: "JEMALLOC_SYS_WITH_LG_PAGE=16 "
- target: armv7-unknown-linux-gnueabihf
platform: linux/arm/v7
suffix: ""
build_env: "JEMALLOC_SYS_WITH_LG_PAGE=16 "
- target: armv7-unknown-linux-musleabihf
platform: linux/arm/v7
suffix: "-alpine"
build_env: "JEMALLOC_SYS_WITH_LG_PAGE=16 "
- target: arm-unknown-linux-gnueabihf
platform: linux/arm/v6
suffix: ""
build_env: ""
- target: arm-unknown-linux-musleabihf
platform: linux/arm/v6
suffix: "-alpine"
build_env: ""
name: Build / ${{matrix.target}}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.1
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: "arm64,arm"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-config-inline: |
[registry."docker.io"]
mirrors = ["https://mirror.gcr.io"]
driver-opts: |
network=host
- name: Log In to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{github.repository_owner}}
password: ${{github.token}}
- name: Log In to DockerHub
uses: docker/login-action@v3
with:
username: ${{secrets.DOCKERHUB_USERNAME}}
password: ${{secrets.DOCKERHUB_TOKEN}}
- name: Calculate shasum of external deps
id: cal-dep-shasum
run: |
echo "checksum=$(yq -p toml -oy '.package[] | select((.source | contains("")) or (.checksum | contains("")))' Cargo.lock | sha256sum | awk '{print $1}')" >> "$GITHUB_OUTPUT"
- name: Cache apt
uses: actions/cache@v5
id: apt-cache
with:
path: |
var-cache-apt
var-lib-apt
key: apt-cache-${{ hashFiles('Dockerfile.build') }}
- name: Cache Cargo
uses: actions/cache@v5
id: cargo-cache
with:
path: |
usr-local-cargo-registry
usr-local-cargo-git
key: cargo-cache-${{ steps.cal-dep-shasum.outputs.checksum }}
- name: Inject cache into docker
uses: reproducible-containers/buildkit-cache-dance@v3.3.0
with:
cache-map: |
{
"var-cache-apt": "/var/cache/apt",
"var-lib-apt": "/var/lib/apt",
"usr-local-cargo-registry": "/usr/local/cargo/registry",
"usr-local-cargo-git": "/usr/local/cargo/git"
}
skip-extraction: ${{ steps.cargo-cache.outputs.cache-hit }} && ${{ steps.apt-cache.outputs.cache-hit }}
- name: Extract Metadata for Docker
uses: docker/metadata-action@v5
id: meta
with:
images: |
index.docker.io/${{github.repository}}
ghcr.io/${{github.repository}}
flavor: |
suffix=${{matrix.suffix}},onlatest=true
tags: |
type=ref,event=tag
type=ref,event=branch,prefix=branch-
type=edge,branch=main
type=semver,pattern=v{{major}}.{{minor}}
- name: Build Artifact
id: bake
uses: docker/bake-action@v6
env:
DOCKER_BUILD_RECORD_UPLOAD: false
TARGET: ${{matrix.target}}
GHCR_REPO: ghcr.io/${{github.repository}}
BUILD_ENV: ${{matrix.build_env}}
DOCKER_PLATFORM: ${{matrix.platform}}
SUFFIX: ${{matrix.suffix}}
with:
source: .
set: |
*.tags=
image.output=type=image,"name=ghcr.io/${{github.repository}},index.docker.io/${{github.repository}}",push-by-digest=true,name-canonical=true,push=true,compression=zstd,compression-level=9,force-compression=true,oci-mediatypes=true
files: |
docker-bake.hcl
${{ steps.meta.outputs.bake-file }}
targets: ${{(github.event_name == 'push' || inputs.Docker) && 'build,image' || 'build'}}
- name: Upload Artifacts
uses: actions/upload-artifact@v6
with:
name: artifact-${{matrix.target}}
path: |
artifact
!artifact/*.json
- name: Export digest & Rename meta bake definition file
if: github.event_name == 'push' || inputs.Docker
run: |
mv "${{ steps.meta.outputs.bake-file }}" "${{ runner.temp }}/bake-meta.json"
mkdir -p ${{ runner.temp }}/digests
digest="${{ fromJSON(steps.bake.outputs.metadata).image['containerimage.digest'] }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
if: github.event_name == 'push' || inputs.Docker
uses: actions/upload-artifact@v6
with:
name: digests-${{matrix.suffix == '' && 'gnu' || 'musl'}}-${{ matrix.target }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
- name: Upload GNU meta bake definition
uses: actions/upload-artifact@v6
if: (github.event_name == 'push' || inputs.Docker) && endsWith(matrix.target,'gnu') && startsWith(matrix.target,'x86')
with:
name: bake-meta-gnu
path: ${{ runner.temp }}/bake-meta.json
if-no-files-found: error
retention-days: 1
- name: Upload musl meta bake definition
uses: actions/upload-artifact@v6
if: (github.event_name == 'push' || inputs.Docker) && endsWith(matrix.target,'musl') && startsWith(matrix.target,'x86')
with:
name: bake-meta-musl
path: ${{ runner.temp }}/bake-meta.json
if-no-files-found: error
retention-days: 1
windows:
name: Build / ${{matrix.target}}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
# - target: aarch64-pc-windows-msvc
- target: x86_64-pc-windows-msvc
steps:
- name: Checkout
uses: actions/checkout@v6.0.1
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
with:
disable_annotations: true
- name: Build
run: |
rustup target add ${{matrix.target}}
cargo build --release --target ${{matrix.target}} -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats enterprise"
cargo build --release --target ${{matrix.target}} -p stalwart-cli
mkdir -p artifacts
mv ./target/${{matrix.target}}/release/stalwart.exe ./artifacts/stalwart.exe
mv ./target/${{matrix.target}}/release/stalwart-cli.exe ./artifacts/stalwart-cli.exe
- name: Upload Artifacts
uses: actions/upload-artifact@v6
with:
name: artifact-${{matrix.target}}
path: artifacts
macos:
name: Build / ${{matrix.target}}
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-apple-darwin
- target: x86_64-apple-darwin
steps:
- name: Checkout
uses: actions/checkout@v6.0.1
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
with:
disable_annotations: true
#- name: Build FoundationDB Edition
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# run: |
# rustup target add ${{matrix.target}}
# # Get latest FoundationDB installer
# curl --retry 5 -Lso foundationdb.pkg "$(gh api -X GET /repos/apple/foundationdb/releases --jq '.[] | select(.prerelease == false) | .assets[] | select(.name | test("${{startsWith(matrix.target, 'x86') && 'x86_64' || 'arm64'}}" + ".pkg$")) | .browser_download_url' | head -n1)"
# echo "=== Package contents ==="
# pkgutil --payload-files foundationdb.pkg || true
# sudo installer -allowUntrusted -verbose -dumplog -pkg foundationdb.pkg -target /
# cargo build --release --target ${{matrix.target}} -p stalwart --no-default-features --features "foundationdb s3 redis nats enterprise"
# mkdir -p artifacts
# mv ./target/${{matrix.target}}/release/stalwart ./artifacts/stalwart-foundationdb
- name: Build
run: |
rustup target add ${{matrix.target}}
cargo build --release --target ${{matrix.target}} -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats enterprise"
cargo build --release --target ${{matrix.target}} -p stalwart-cli
mkdir -p artifacts
mv ./target/${{matrix.target}}/release/stalwart ./artifacts/stalwart
mv ./target/${{matrix.target}}/release/stalwart-cli ./artifacts/stalwart-cli
- name: Upload Artifacts
uses: actions/upload-artifact@v6
with:
name: artifact-${{matrix.target}}
path: artifacts
release:
name: Release
permissions:
id-token: write
contents: write
attestations: write
if: github.event_name == 'push' || inputs.Release
needs: [linux, windows, macos]
runs-on: ubuntu-latest
steps:
- name: Download Artifacts
uses: actions/download-artifact@v7
with:
path: archive
pattern: artifact-*
- name: Compress
run: |
set -eux
BASE_DIR="$(pwd)/archive"
compress_files() {
local dir="$1"
local archive_dir_name="${dir#artifact-}"
cd "$dir"
# Process each file in the directory
for file in `ls`; do
filename="${file%.*}"
extension="${file##*.}"
if [ "$extension" = "exe" ]; then
7z a -tzip "${filename}-${archive_dir_name}.zip" "$file" > /dev/null
else
tar -czf "${filename}-${archive_dir_name}.tar.gz" "$file"
fi
done
cd $BASE_DIR
}
cd $BASE_DIR
for arch_dir in `ls`; do
dir_name=$(basename "$arch_dir")
compress_files "$dir_name"
done
- name: Attest binary
id: attest
uses: actions/attest-build-provenance@v3
with:
subject-path: |
archive/**/*.tar.gz
archive/**/*.zip
- name: Use cosign to sign existing artifacts
uses: sigstore/gh-action-sigstore-python@v3.2.0
with:
inputs: |
archive/**/*.tar.gz
archive/**/*.zip
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
archive/**/*.tar.gz
archive/**/*.zip
archive/**/*.sigstore.json
prerelease: ${{!startsWith(github.ref, 'refs/tags/') || null}}
tag_name: ${{!startsWith(github.ref, 'refs/tags/') && 'nightly' || null}}
# TODO add instructions about using cosign to verify binary artifact
append_body: true
body: |
<hr />
### Check binary attestation at [here](${{ steps.attest.outputs.attestation-url }})
================================================
FILE: .github/workflows/scorecard.yml
================================================
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '31 6 * * 0'
push:
branches: [ "main" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4.2.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
# file_mode: git
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: results.sarif
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
workflow_dispatch:
jobs:
style:
name: Check Style
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.1
- name: Check Style
run: cargo fmt --all --check
test:
name: Test
needs: style
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.1
- name: Install dependencies
run: |
sudo apt-get update -y
curl -LO https://github.com/glauth/glauth/releases/download/v2.2.0/glauth-linux-arm64
chmod a+rx glauth-linux-arm64
nohup ./glauth-linux-arm64 -c tests/resources/ldap.cfg &
curl -Lo minio.deb https://dl.min.io/server/minio/release/linux-amd64/archive/minio_20230629051228.0.0_amd64.deb
sudo dpkg -i minio.deb
mkdir ~/minio
nohup minio server ~/minio --console-address :9090 &
curl -LO https://dl.min.io/client/mc/release/linux-amd64/mc
chmod a+rx mc
./mc alias set myminio http://localhost:9000 minioadmin minioadmin
./mc mb tmp
- name: Rust Cache
uses: Swatinem/rust-cache@v2
- name: JMAP Protocol Tests
run: cargo test -p jmap_proto -- --nocapture
- name: IMAP Protocol Tests
run: cargo test -p imap_proto -- --nocapture
- name: Full-text search Tests
run: cargo test -p store -- --nocapture
- name: Directory Tests
run: cargo test -p tests directory -- --nocapture
- name: SMTP Tests
run: cargo test -p tests smtp -- --nocapture
- name: IMAP Tests
run: cargo test -p tests imap -- --nocapture
- name: JMAP Tests
run: cargo test -p tests jmap -- --nocapture
================================================
FILE: .github/workflows/trivy.yml
================================================
# trivy ci workflow
name: trivy
on:
workflow_dispatch:
push:
branches: [ "main" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main" ]
schedule:
- cron: '00 12 * * *'
permissions:
contents: read
jobs:
build:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
name: Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6.0.1
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
ignore-unfixed: true
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: 'trivy-results.sarif'
================================================
FILE: .gitignore
================================================
/target
.vscode
.idea
*.failed
*_failed
run.sh
_ignore
.DS_Store
================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
## [0.15.5] - 2026-02-14
If you are upgrading from v0.14.x and below, this version includes **multiple breaking changes**. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_15.md) for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
## Added
## Changed
## Fixed
- IMAP/JMAP: OOM when `mail-parser` returns cyclical MIME structures [CVE-2026-26312](https://github.com/stalwartlabs/stalwart/security/advisories/GHSA-jm95-876q-c9gw).
- Tracing: Fix tracing indexing when using separate stores.
- JMAP: Fix `upToId` computation in `*/queryChanges`.
- JMAP: Include createdIds when the property is present.
- JMAP: Respect query arguments in `Email/queryChanges`.
- JMAP: Return the correct container/item change id when there are no changes.
## [0.15.4] - 2026-01-19
If you are upgrading from v0.14.x and below, this version includes **multiple breaking changes**. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_15.md) for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
## Added
- IMAP: Map `HEADER SUBJECT/FROM/TO` searches to `SUBJECT/FROM/TO` queries.
- Sieve: Update spam status on user scripts.
## Changed
## Fixed
- Search: Return all document ids when no filters are provided.
- Search: Filters not applied when a single message is in the account.
- IMAP: Return `ALREADYEXISTS` code when creating existing mailboxes.
- IMAP: Do not return quota resources if no quota is set.
- JMAP/changes: Update `newState` with last changeId if an invalid fromChangeId is provided.
- JMAP/CalendarIdentity: Do not update invalid calendar identities.
- AI API: Include request error details if available.
## [0.15.3] - 2025-12-29
If you are upgrading from v0.14.x and below, this version includes **multiple breaking changes**. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_15.md) for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
## Added
- Polish locale support (contributed by @mrxkp) (#2480)
## Changed
## Fixed
- Meilisearch: Return correct error messages when failing to create indexes (#2574)
- PostgreSQL search: Truncate emails to 650kb for full-text search indexing.
- FoundationDB search: Batch large transactions (#2567).
- Spam filter: Fix training sample size checks
- IMAP: Fix UTF7 encoding with Emojis (contributed by @dojiong) (#2564).
## [0.15.2] - 2025-12-22
If you are upgrading from v0.14.x and below, this version includes **multiple breaking changes**. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_15.md) for more information on how to upgrade from previous versions.
If you are upgrading from v0.15.x, replace the binary and update the webadmin.
## Added
- OAuth: Add device authorization endpoint (#2225).
## Changed
- Antispam: Only auto-learn spam from traps or multiple RBL hits.
## Fixed
- mySQL search: Use `MEDIUMTEXT` field type for email body and attachments (#2544).
- PostgreSQL search: Truncate large text fields.
- ElasticSearch: Implement pagination (#2551).
- Antispam: Fix `NO_SPACE_IN_FROM` spam tag detection logic (#2372).
- IMAP: Fix shared folder double nesting (test suite credits to @ochnygosch) (#2358).
- JMAP: Use latest `Received` header in JMAP `Email/import` (credits to @apexskier) (#2374).
- JMAP: Return unsorted search results when the index is not ready (#2544).
- LDAP: Lowercase attribute comparison (credits to @pdf) (#2363).
- CLI: Fix same-host JMAP redirection on non-standard ports (#2271).
## [0.15.1] - 2025-12-17
This version includes **multiple breaking changes**. If you are upgrading from v0.14.x and below, please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_15.md) for more information on how to upgrade from previous versions.
## Added
## Changed
## Fixed
- PostgreSQL: Sanitize search index values (#2533)
- Elasticsearch: Ignore `resource_already_exists_exception` errors when creating indexes (#2535)
- Migrate 0.13.x data (#2534)
## [0.15.0] - 2025-12-16
This version includes **multiple breaking changes**. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_15.md) for more information on how to upgrade from previous versions.
## Added
- Linear spam classifier using FTRL-Proximal and feature/cuckoo hashing.
- Meilisearch store backend implementation (#1482).
- PostgreSQL and mySQL native full-text search support.
- Multiple performance improvements and database access optimizations.
- Encryption-at-rest: Spam training privacy setting.
- Enterprise: Undelete e-mail feature now includes From/Subject/Received information.
- IMAP: Implemented new keywords and mailbox attributes described in [draft-ietf-mailmaint-messageflag-mailboxattribute-13](https://datatracker.ietf.org/doc/html/draft-ietf-mailmaint-messageflag-mailboxattribute-13)
## Changed
- IMAP: Always return special use flags in responses.
## Fixed
- JMAP: `FileNode/set` fails to delete files (#2485).
- JMAP: Return error when using `blobId` in JSContact and JSCalendar (#2431).
- Directory: Deletion of list or domain issues (#2415).
- MTA: Headers and body stripped from mail delivery subsystem failure notifications (#2344).
- MTA: Hooks only run if sieve script, milter or rewrite is configured (#2317).
- Autodiscover: Endpoint should be case insensitive (#2440).
- Housekeeper: Panic during DST transition (#2366).
- Import/Export: Fix import/export utility (#1882).
- Enterprise: Remove tenant admin permissions when license is invalid.
## [0.14.1] - 2025-10-28
If you are upgrading from v0.13.4 and below, this version includes **breaking changes** to the internal directory, calendar and contacts. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_14.md) for more information on how to upgrade from previous versions.
## Added
- Autoconfig for CalDAV, CardDAV and WebDAV (#1937)
## Changed
- HTTP: Remove HTTP STS `preload` directive.
## Fixed
- Directory: Keep OTP Auth and AppPasswords unless the remote directory provides new ones (#2319)
- JMAP: Fix `ContactCard/set` and `CalendarEvent/set` destroy methods (#2308).
## [0.14.0] - 2025-10-22
If you are upgrading from v0.13.4 and below, this version includes **breaking changes** to the internal directory, calendar and contacts. Please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_14.md) for more information on how to upgrade from previous versions.
## Added
- JMAP for Calendars ([draft-ietf-jmap-calendars](https://datatracker.ietf.org/doc/draft-ietf-jmap-calendars/)).
- JMAP for Contacts ([RFC 9610](https://datatracker.ietf.org/doc/rfc9610/)).
- JMAP for File Storage ([draft-ietf-jmap-filenode](https://datatracker.ietf.org/doc/draft-ietf-jmap-filenode/)).
- JMAP Sharing ([RFC 9670](https://datatracker.ietf.org/doc/rfc9670/))
- CalDAV: support for `supported-calendar-component-set` (#1893)
- i18n: Greek language support (contributed by @infl00p)
- i18n: Swedish language support (contributed by @purung)
## Changed
- **Breaking Database Changes** (migrated automatically on first start):
- Internal directory schema changed.
- Calendar and Contacts storage schema changed.
- Sieve scripts storage schema changed.
- Push Subscriptions storage schema changed.
- Replaced `sieve.untrusted.limits.max-scripts` and `jmap.push.max-total` with `object-quota.*` settings.
- Cluster node roles now allow sharding.
## Fixed
- Push Subscription: Clean-up of expired subscriptions and cluster notification of changes (#1248)
- CalDAV: Per-user CalDAV properties (#2058)
## [0.13.4] - 2025-09-30
If you are upgrading from v0.11.x or v0.12.x, this version includes **breaking changes** to the message queue and MTA configuration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
## Changed
- JMAP: Protocol layer rewrite for zero-copy deserialization and architectural improvements.
## Fixed
- IMAP: Unbounded memory allocation in request parser ([CVE-2025-61600 ](https://github.com/stalwartlabs/stalwart/security/advisories/GHSA-8jqj-qj5p-v5rr)).
- IMAP: Wrong permission checked for GETACL.
- JMAP: References to previous method fail when there are no results (#1507).
- JMAP: Enforce quota checks on `Blob/copy`.
- JMAP: `Mailbox/get` fails without `accountId` argument (#1936).
- JMAP: Do not return `invalidProperties` when email update doesn't contain changes (#1139)
- iTIP: Include date properties in `REPLY` (#2102).
- OIDC: Do not set `username` field if it is the same as the `email` field.
- Telemetry: Fix `calculateMetrics` housekeeper task (#2155).
- Directory: Always use `rsplit` to extract the domain part from email addresses.
## [0.13.3] - 2025-09-10
If you are upgrading from v0.11.x or v0.12.x, this version includes **breaking changes** to the message queue and MTA configuration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- CLI: Health checks (contributed by @Codekloeppler)
## Changed
- WebDAV: Assisted discovery v2
## Fixed
- iTIP: Do not send a REPLY when deleting an event that was not accepted.
- iTIP: Include event details in REPLY messages (#2102).
- iTIP: Add organizer to iMIP replies if missing to deal with MS Exchange 2010 bug.
- OIDC: Do not overwrite locally defined aliases (#2065).
- HTTP: Scan ban should only be triggered by HTTP parse errors.
- HTTP: Skip scanner fail2ban checks when the proxy client IP can't be parsed (#2121).
- JMAP: Do not allow roles to be removed from system mailboxes (#1977).
- JMAP WS: Fix panic when using invalid server url.
- SMTP: Do no send `EHLO` twice when `STARTTLS` is unavailable (#2050).
- IMAP: Allow `ENABLE UTF8` in IMAPrev1.
- IMAP: Include `administer` permission in ACL responses.
- IMAP: Add owner rights to ACL get responses.
- IMAP: Do not auto-train Bayes when moving messages from Junk to Trash.
- IMAP/ManageSieve: Increase maximum quoted argument size (#2039).
- CalDAV: Limit recurrence expansions in calendar reports ([CVE-2025-59045](https://github.com/stalwartlabs/stalwart/security/advisories/GHSA-xv4r-q6gr-6pfg)).
- WebDAV: Do not fix percent encoding on WebDAV FS (#2036).
## [0.13.2] - 2025-07-28
If you are upgrading from v0.11.x or v0.12.x, this version includes **breaking changes** to the message queue and MTA configuration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- ACME: DeSEC cloud DNS provider support (contributed by @Tyr3al).
- ACME: OVH cloud DNS provider support (contributed by @srachner).
- CalDAV Scheduling: Catalan language support (contributed by @jolupa) (#1873).
- MTA: Allow to send e-mails as group, while member of that group (#485).
- OIDC: Allow local access tokens to be used with third-party OIDC backends (#1311 stalwartlabs/webadmin#52).
## Changed
- IMAP: Return `OK` when moving/copying non-existent messages (#670).
- IMAP: Copy flags when copying/moving messages between accounts.
## Fixed
- MTA: Do not convert e-mail local parts to lowercase (#1916).
- Sieve: `fileinto` should override spam filter (#1917).
- JMAP: Incorrect `accountId` used in email set and import methods (#1777).
- WebDAV: Always return `MULTISTATUS` when calendar-query yields no results.
- LDAP: Only set account name if not returned in LDAP query (#1471).
- Enterprise: Invalidate logo cache when changes are made (#1856).
- Enterprise: Fix tenant quota update API.
## [0.13.1] - 2025-07-16
If you are upgrading from v0.11.x or v0.12.x, this version includes **breaking changes** to the message queue and MTA configuration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- ACME: DigitalOcean cloud DNS provider support (#1667).
## Changed
## Fixed
- Migration: Old queue events not deleted causing high CPU usage in some deployments (#1833).
- MTA: `mta-sts` setting parsing issue (#1830).
- JMAP: `sortOrder` should not be null (#1831).
- Allow invalid TOML when parsing database settings (#1822).
## [0.13.0] - 2025-07-15
If you are upgrading from v0.11.x or v0.12.x, this version includes **breaking changes** to the message queue and MTA configuration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- MTA queue enhancements (#1246 #1035 #457).
- Danish locale support (contributed by @Fadil2k) (#1772).
- DKIM support for `stalwart-cli` (contributed by @rmsc) (#1804).
## Changed
- Invalidate access token caches in a cluster using pub/sub (#1741).
- Allow updating secrets for all directory types.
## Fixed
- WebDAV: Return all shared resources in `calendar-home-set` and `addressbook-home-set` (#1796).
- WebDAV ACL: Fix write permission and `multiget` reports (#1768).
- CalDAV Scheduling: Include `DTSTART`/`DTEND` properties in iMIP `CANCEL` messages (#1775).
- HTTP: Do not include `WWW-Authenticate` headers in API responses (#1795).
- API: Allow API keys to be used with external directories (#1815).
- IMAP: Fix issue creating subfolders under INBOX for group shared folder (#1817).
- IMAP: Custom Name for Shared Folders ignored (#1620).
- LDAP: `local` placeholder should return username when its not an email address (#1784).
## [0.12.5] - 2025-06-25
If you are upgrading from v0.11.x, this version includes **breaking changes** to the database layout and requires a migration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- Calendar Scheduling Extensions to CalDAV - RFC6368 (#1514)
- Calendar E-Mail Notifications (#1514)
- Limited i18n support for calendaring events.
- Assisted CalDAV/CardDAV shared resource discovery (#1691).
## Changed
- JMAP: Allow unauthenticated access to JMAP session object.
## Fixed
- WebDAV: Return NOTFOUND error instead of MULTISTATUS on empty PROPFIND responses (#1657).
- WebDAV: Update account name when refreshing DAV caches (#1694).
- JMAP: Do not include email address in identity names (#1688).
- IMAP: Normalize `INBOX` name when creating/renaming folders (#1636).
- LDAP: Request `secret-changed` attribute in LDAP queries (#1409).
- Branding: Unable to change logos (#1652).
- Antispam: Skip `card-is-ham` override when sender does not pass DMARC (#1648).
- FoundationDB: Renew old/expired FDB read transactions after the `1007` error code is received rather than estimating expiration time.
## [0.12.4] - 2025-06-03
If you are upgrading from v0.11.x, this version includes **breaking changes** to the database layout and requires a migration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- LDAP authentication enhancements (#1269 #1471 #795 #1496).
- MTA: Return Queue IDs during message acceptance (#927).
## Changed
- LDAP: `bind.auth.enable` is now `bind.auth.method`, read the updated [LDAP documentation](https://stalw.art/docs/auth/backend/ldap) for more information.
## Fixed
- DNS: `hickory-resolver` bug hitting 100% CPU usage when resolving DNSSEC records.
- IMAP: Return the message UID in the destination mailbox if the message already exists (#1201).
- MTA: TLS reports being issued for sent TLS reports (infinite loop) (#1301).
- WebDAV: Return `CTag` on `/dav/cal/account` resources to force iOS synchronize.
- CardDAV: Strict vCard parsing (#1607).
- WebDAV: Dead property updates (#1611).
- WebDAV: Use last change id in `CTag`.
## [0.12.3] - 2025-05-30
If you are upgrading from v0.11.x, this version includes **breaking changes** to the database layout and requires a migration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- Store vanished IMAP UIDs and WebDAV paths in the changelog.
## Changed
## Fixed
- XML `CDATA` injection (credits to @andreymal for the report).
- Macro references are replaced with their content when writing config file (#1595).
- Double nested CalDAV and CardDAV property tags (#1591).
- Allow empty properties in PROPPATCH requests (#1580).
## [0.12.2] - 2025-05-27
If you are upgrading from v0.11.x, this version includes **breaking changes** to the database layout and requires a migration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
- CardDAV: Legacy vCard 2.1 and 3.0 serialization support.
- WebDAV: Add SRV Records to help DAV autodiscovery (closes #1565).
## Changed
## Fixed
- Report list attempts to deserialize empty values (#1562)
- Refresh expired FoundationDB transactions while retrieving large blobs (#1555).
## [0.12.1] - 2025-05-26
If you are upgrading from v0.11.x, this version includes **breaking changes** to the database layout and requires a migration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
## Added
## Changed
## Fixed
- Migration tool to generate the correct next id (#1561).
- Failed to parse setting dav.lock.max-timeout (closes #1559).
- Failed to build OpenTelemetry span exporter: no http client specified (#1571).
## [0.12.0] - 2025-05-26
This version includes **breaking changes** to the database layout and requires a migration. Please read the [UPGRADING.md](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING.md) file for more information on how to upgrade from previous versions.
### Added
- [Collaboration](https://stalw.art/docs/collaboration/overview) features including [Calendars over CalDAV](https://stalw.art/docs/http/calendar/), [Contacts over CardDAV](https://stalw.art/docs/http/contact/) and [File Storage over WebDAV](https://stalw.art/docs/http/file-storage/).
- Peer-to-peer [cluster coordination](https://stalw.art/docs/cluster/coordination/overview) or with Apache Kafka, Redpanda, NATS or Redis.
- Incremental caching of emails, calendars, contacts and file metadata.
- Zero-copy deserialization.
- Train spam messages as ham when the sender is in the user's address book.
- `XOAUTH2` SASL mechanism support (#1194 #1369).
- Support for RFC9698, the `JMAPACCESS` Extension for IMAP.
- Search index for accounts and other principals (#1368).
- Add `description` property to OIDC ID token (#1234).
### Changed
- Deprecated gossip protocol in favor of the new [coordinator](https://stalw.art/docs/cluster/coordination/overview) options.
- Renamed Git repository from `stalwartlabs/mail-server` to `stalwartlabs/stalwart` and the Docker image from `stalwartlabs/mail-server` to `stalwartlabs/stalwart`.
- Renamed multiple settings:
- `server.http.*` to `http.*`.
- `jmap.folders.*` to `email.folders.*`.
- `jmap.account.purge.frequency` to `account.purge.frequency`.
- `jmap.email.auto-expunge` to `email.auto-expunge`.
- `jmap.protocol.changes.max-history` to `changes.max-history`.
- `storage.encryption.*` to `email.encryption.*`.
- Deprecated `lookup.default.*` settings in favor of `server.hostname` and `report.domain`. v0.11 and before supported both, v0.12 will only support the new settings.
### Fixed
- Allow undiscovered UIDs to be used in IMAP `COPY`/`MOVE` operations (#1201).
- Refuse loopback SMTP delivery (#1377).
- Hide the current server version (#1435).
- Use the newest `X-Spam-Status` Header (#1308).
- MySQL Driver error: Transactions couldn't be nested (#1271).
- Spawn a delivery thread for `EmailSubmission/set` requests (#1540).
- ACME: Don't restrict challenge types (#1522).
- Autoconfig: return `%EMAILADDRESS%` if no e-mail address is provided (#1537).
## [0.11.8] - 2025-04-30
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
### Changed
### Fixed
- Allow undiscovered UIDs to be used in `COPY`/`MOVE` operations (#1201).
## [0.11.7] - 2025-03-23
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- LDAP attribute to indicate password change (#1156).
### Changed
- Lazy DKIM key parsing (#1211).
- Enable `edns0` for system resolver by default (#1282).
- Bump FoundationDB to `7.3`.
### Fixed
- Fix incorrect `UIDNEXT` when mailbox is empty (#1201).
- Sender variable not set when evaluating `must-match-sender` (#1294).
- Do not panic when mailboxId is not found (#1293).
- Prioritize local over span keys when serializing webhook payloads (#1250).
- Allow TLS name mismatch as per RFC7671 Section 5.1.
- Try with implicit MX when no MX records are found.
- SQL `secrets` directory query.
## [0.11.5] - 2025-02-01
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
### Changed
- Open source third party OIDC support.
### Fixed
- Case insensitive flag parsing (#1138).
- BCC not removed from JMAP EmailSubmissions (#618).
- Group pipelined IMAP FETCH and STATUS operations (#1096).
## [0.11.4] - 2025-01-29
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- RFC 9208 - IMAP QUOTA Extension (#484).
### Changed
- `session.throttle.*` is now `queue.limiter.inbound.*`.
- `queue.throttle.*` is now `queue.limiter.outbound.*`.
- Changed DNSBL error level to debug (#1107).
### Fixed
- Creating a mailbox in a shared folder results in wrong hierarchy (#1128).
- IMAP LIST-STATUS (RFC 5819) returns items in wrong order (#1129).
- Avoid non-RFC SMTP status codes (#1109).
- Do not DNSBL check invalid domains (#1107).
- Sieve message flag parser (#1059).
- Sieve script import case insensitivity (#962).
- `mailto:` parsing in HTMLs.
## [0.11.2] - 2025-01-17
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Automatic revoking of access tokens when secrets, permissions, ACLs or group memberships change (#649).
- Increased concurrency for local message delivery (configurable via `queue.threads.local`).
- Cluster node roles.
- `config_get` expression function.
### Changed
- `queue.outbound.concurrency` is now `queue.threads.remote`.
- `lookup.default.hostname` is now `server.hostname`.
- `lookup.default.domain` is now `report.domain`.
### Fixed
- Distributed locking issues in non-Redis stores (#1066).
- S3 incorrect backoff wait time after failures.
- Panic parsing broken HTMLs.
- Update CLI response serializer to v0.11.x (#1082).
- Histogram bucket counts (#1079).
- Do not rate limit trusted IPs (#1078).
- Avoid double encrypting PGP parts encoded as plain text (#1083).
- Return empty SASL challenge rather than "" (#1064).
## [0.11.0] - 2025-01-06
This version includes breaking changes to the configuration file, please read [UPGRADING.md](UPGRADING.md) for details.
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Spam filter rewritten in Rust for a significant performance improvement.
- Multiple spam filter improvements (#947) such as training spam/ham when moving between inbox and spam folders (#819).
- Improved distributed locking and handling of large distributed SMTP queues.
- ASN and GeoIP lookups.
- Bulk operations REST endpoints (#925).
- Faster S3-FIFO caching.
- Support adding the `Delivered-To` header (#916).
- Semver compatibility checks when upgrading (#844).
- Sharded In-Memory Store.
### Changed
- Removed authentication rate limit (no longer necessary since there is fail2ban).
- Pipes have been deprecated in favor of MTA hooks.
### Fixed
- OpenPGP EOF error (#1024).
- Convert emails obtained from external directories to lowercase (#1004).
- LDAP: Support both name and email fields to be mapped to the same attribute.
- Admin role can't be assigned if an account with the same name exists.
- Fix macro detection in DNS record generation (#978).
- Use host FQDN in install script (#1003).
## [0.10.7] - 2024-12-04
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Delivery and DMARC Troubleshooting (#420).
- Support for external email addresses on mailing lists (#152).
- Azure blob storage support.
### Changed
### Fixed
- Some mails can't be moved out of the junk folder (#670).
- Out of bound index error on Sieve script (#941).
- Missing `User-Agent` header for ACME (#937).
- UTF8 support in IMAP4rev1 (#948).
- Account alias owner leak on autodiscover.
- Include all events in OTEL traces + Include spanId in webhooks.
- Implement `todo!()` causing panic on concurrency and rate limits.
- Mark SQL store as active if used as a telemetry store.
- Discard empty form submissions.
## [0.10.6] - 2024-11-07
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Enterprise license automatic renewals before expiration (disabled by default).
- Allow to LDAP search using bind dn instead of auth bind connection when bind auth is enabled (#873)
### Changed
### Fixed
- Include `preferred_username` and `email` in OIDC `id_token`.
- Verify roles and permissions when creating or modifying accounts (#874)
## [0.10.5] - 2024-10-15
To upgrade replace the `stalwart-mail` binary.
### Added
- Data store CLI.
### Changed
### Fixed
- Tokenizer performance issue (#863)
- Incorrect AI model endpoint setting.
## [0.10.4] - 2024-10-08
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Detect and ban port scanners as well as other forms of abuse (#820).
- ACME External Account Binding support (#379).
### Changed
- The settings `server.fail2ban.*` have been moved to `server.auto-ban.*`.
- The event `security.brute-force-ban` is now `security.abuse-ban`.
### Fixed
- Do not send SPF failures reports to local domains.
- Allow `nonce` in OAuth code requests.
- Warn when there are errors migrating domains rather than aborting migration.
## [0.10.3] - 2024-10-07
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin. Enterprise users wishing to use the new LLM-powered spam filter should also upgrade the spam filter rules.
### Added
- AI-powered Spam filtering and Sieve scripting (Enterprise feature).
### Changed
- The untrusted Sieve interpreter now has the `vnd.stalwart.expressions` extension enabled by default. This allows Sieve users to use the `eval` function to evaluate expressions in their scripts. If you would like to disable this extension, you can do so by adding `vnd.stalwart.expressions` to `sieve.untrusted.disabled-capabilities`.
### Fixed
- S3-compatible backends: Retry on `5xx` errors.
- OIDC: Include `nonce` parameter in `id_token` response.
## [0.10.2] - 2024-10-02
To upgrade first upgrade the webadmin and then replace the `stalwart-mail` binary. If you read these instructions too late, you can upgrade to the latest web-admin using `curl -k -u admin:yourpass https://yourserver/api/update/webadmin`.
### Added
- OpenID Connect server (#298).
- OpenID Connect backend support (Enterprise feature).
- OpenID Connect Dynamic Client Registration (#4)
- OAuth 2.0 Dynamic Client Registration Protocol ([RFC7591](https://datatracker.ietf.org/doc/html/rfc7591)) (#136)
- OAuth 2.0 Token Introspection ([RFC7662](https://datatracker.ietf.org/doc/html/rfc7662)).
- Contact form submission handling.
- `webadmin.path` setting to override unpack directory (#792).
### Changed
### Fixed
- Missing `LIST-STATUS` from RFC5819 in IMAP capability responses (#816).
- Do not allow tenant domains to be deleted if they have members (#812).
- Tenant principal limits (#810).
## [0.10.1] - 2024-09-26
To upgrade replace the `stalwart-mail` binary.
### Added
- `OAUTHBEARER` SASL support in all services (#627).
### Changed
### Fixed
- Fixed `migrate_directory` range scan (#784).
## [0.10.0] - 2024-09-21
This version includes breaking changes to how accounts are stored. Please read [UPGRADING.md](UPGRADING.md) for details.
### Added
- Multi-tenancy (Enterprise feature).
- Branding (Enterprise feature).
- Roles and permissions.
- Full-text search re-indexing.
- Partial database backups (#497).
### Changed
### Fixed
- IMAP `IDLE` support for command pipelining, aka the Apple Mail iOS 18 bug (#765).
- Case insensitive INBOX `fileinto` (#763).
- Properly decode undelete account name (#761).
## [0.9.4] - 2024-09-09
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Support for global Sieve scripts that can be used by users to filter their incoming mail.
- Allow localhost to override HTTP access controls to prevent lockouts.
### Changed
- Sieve runtime error default log level is now `debug`.
### Fixed
- Ignore INBOX case on Sieve's `fileinto` (#725)
- Local keys parsing and retrieval issues.
- Lookup reload does not include database settings.
- Account count is incorrect.
## [0.9.3] - 2024-08-29
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Dashboard (Enterprise feature)
- Alerts (Enterprise feature)
- SYN Flood (session "loitering") attack protection (#482)
- Mailbox brute force protection (#688)
- Mail from is allowed (`session.mail.is-allowed`) expression (#609)
### Changed
- `authentication.fail2ban` setting renamed to `server.fail2ban.authentication`.
- Added elapsed times to message filtering events.
### Fixed
- Include queueId in MTA Hooks (#708)
- Do not insert empty keywords in FTS index.
## [0.9.2] - 2024-08-21
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Message delivery history (Enterprise feature)
- Live tracing and logging (Enterprise feature)
- SQL Read Replicas (Enterprise feature)
- Distributed S3 Blob Store (Enterprise feature)
### Changed
### Fixed
- Autodiscover request parser issues.
- Do not create tables when using SQL as an external directory (fixes #291)
- Do not hardcode logger id (fixes #348)
- Include `Forwarded-For IP` address in `http.request-url` event (fixes #682)
## [0.9.1] - 2024-08-08
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Metrics support (closes #478)
- OpenTelemetry Push Exporter
- Prometheus Pull Exporter (closes #275)
- HTTP endpoint access controls (closes #266 #329 #542)
- Add `options` setting to PostgreSQL driver (closes #662)
- Add `isActive` property to defaults on Sieve/get JMAP method (closes #624)
### Changed
- Perform `must-match-sender` checks after sender rewriting (closes #394)
- Only perform email ingest duplicate check on the target mailbox (closes #632)
### Fixed
- Properly parse `Forwarded` and `X-Forwarded-For` headers (fixes #669)
- Resolve DKIM macros when generating DNS records (fixes #666)
- Fixed `is_local_domain` Sieve function (fixes #622)
## [0.9.0] - 2024-08-01
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin. This version includes breaking changes to the Webhooks configuration and produces a slightly different log output, read [UPGRADING.md](UPGRADING.md) for details.
### Added
- Improved and faster tracing and logging.
- Customizable event logging levels.
### Changed
### Fixed
- ManageSieve: Return capabilities after successful `STARTTLS`
- Do not provide `{auth_authen}` Milter macro unless the user is authenticated
## [0.8.5] - 2024-07-07
To upgrade replace the `stalwart-mail` binary.
### Added
- Restore deleted e-mails (Enterprise Edition only)
- Kubernetes (K8S) livenessProbe and readinessProbe endpoints.
### Changed
- Avoid sending reports for DMARC/delivery reports (#173)
### Fixed
- Refresh old FoundationDB read transactions (#520)
- Subscribing shared mailboxes doesn't work (#251)
## [0.8.4] - 2024-07-03
To upgrade replace the `stalwart-mail` binary.
### Added
### Changed
### Fixed
- Fix TOTP validation order.
- Increase Jemalloc page size on armv7 builds.
## [0.8.3] - 2024-07-01
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin.
### Added
- Two-factor authentication with Time-based One-Time Passwords (#436)
- Application passwords (#479).
- Option to disable user accounts.
### Changed
- DANE success on EndEntity match regardless of TrustAnchor validation.
### Fixed
- Fix ManageSieve GETSCRIPT response: Add missing CRLF (#563)
- Do not return CAPABILITIES after ManageSieve AUTH=PLAIN SASL exchange (#548)
- POP3 QUIT must write a response (#568)
## [0.8.2] - 2024-06-22
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin and spam filter versions.
### Added
- Webhooks support (#480)
- MTA Hooks (like milter but over HTTP)
- Manually train and test spam classifier (#473 #264 #257 #471)
- Allow configuring default mailbox names, roles and subscriptions (#125 #290 #458 #498)
- Include `robots.txt` (#542)
### Changed
- Milter support on all SMTP stages (#183)
- Do not announce `STARTTLS` if the listener does not support it.
### Fixed
- Incoming reports stored in the wrong subspace (#543)
- Return `OK` after a successful ManageSieve SASL authentication flow (#187)
- Case-insensitive search in settings API (#487)
- Fix `session.rcpt.script` default variable name (#502)
## [0.8.1] - 2024-05-23
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin and spam filter versions.
### Added
- POP3 support.
- DKIM signature length exploit protection.
- Faster email deletion.
- Junk/Trash folder auto-expunge and changelog auto-expiry (#403)
- IP allowlists.
- HTTP Strict Transport Security option.
- Add TLS Reporting DNS entry (#464).
### Changed
- Use separate account for master user.
- Include server hostname in SMTP greetings (#448).
### Fixed
- IP addresses trigger `R_SUSPICIOUS_URL` false positive (#461 #419).
- JMAP identities should not return null signatures.
- Include authentication headers and check queue quotas on Sieve message forwards.
- ARC seal using just one signature.
- Remove technical subdomains from MTA-STS policies and TLS records (#429).
## [0.8.0] - 2024-05-13
This version uses a different database layout which is incompatible with previous versions. Please read the [UPGRADING.md](UPGRADING.md) file for more information on how to upgrade from previous versions.
### Added
- Clustering support with node auto-discovery and partition-tolerant failure detection.
- Autoconfig and MS Autodiscover support (#336)
- New variables `retry_num`, `notify_num`, `last_error` add `last_status` available in queue expressions.
- Performance improvements, in particular for FoundationDB.
- Improved full-text indexing with lower disk space usage.
- MTA-STS policy management.
- TLSA Records generation for DANE (#397)
- Queued message visualization from the web-admin.
- Master user support.
### Changed
- Make `certificate.*` local keys by default.
- Removed `server.run-as.*` settings.
- Add Microsoft Office Macro types to bad mime types (#391)
### Fixed
- mySQL TLS support (#415)
- Resolve file macros after dropping root privileges.
- Updated order of SPF Records (#395).
- Avoid duplicate accountIds when using case insensitive external directories (#399)
- `authenticated_as` variable not usable for must-match-sender (#372)
- Remove `StandardOutput`, `StandardError` in service (#390)
- SMTP `AUTH=LOGIN` compatibility issues with Microsoft Outlook (#400)
## [0.7.3] - 2024-05-01
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin version.
### Added
- Full database export and import functionality
- Add --help and --version command line arguments (#365)
- Allow catch-all addresses when validating must match sender
### Changed
- Add `groupOfUniqueNames` to the list of LDAP object classes
### Fixed
- Trim spaces in DNS-01 ACME secrets (#382)
- Allow only one journald tracer (#375)
- `authenticated_as` variable not usable for must-match-sender (#372)
- Fixed `BOGUS_ENCRYPTED_AND_TEXT` spam filter rule
- Fixed parsing of IPv6 DNS server addresses
## [0.7.2] - 2024-04-17
To upgrade replace the `stalwart-mail` binary and then upgrade to the latest web-admin version.
### Added
- Support for `DNS-01` and `HTTP-01` ACME challenges (#226)
- Configurable external resources (#355)
### Changed
### Fixed
- Startup failure when Elasticsearch is down/starting up (#334)
- URL decode path elements in REST API.
## [0.7.1] - 2024-04-12
To upgrade replace the `stalwart-mail` binary.
### Added
- Make initial admin password configurable via env (#311)
### Changed
- WebAdmin download URL.
### Fixed
- Remove ASN.1 DER structure from DKIM ED25519 public keys.
- Filter out invalid timestamps on log entries.
## [0.7.0] - 2024-04-09
This version uses a different database layout and introduces multiple breaking changes in the configuration files. Please read the [UPGRADING.md](UPGRADING.md) file for more information on how to upgrade from previous versions.
### Added
- Web-based administration interface.
- REST API for management and configuration.
- Automatic RSA and ED25519 DKIM key generation.
- Support for compressing binaries in the blob store (#227).
- Improved performance accessing IMAP mailboxes with a large number of messages.
- Support for custom DNS resolvers.
- Support for multiple loggers with different levels and outputs.
### Changed
### Fixed
- Store quotas as `u64` rather than `u32`.
- Second IDLE connections disconnects the first one (#280).
- Use relaxed DNS parsing, allowing underscores in DNS labels (#172).
- Escape regexes within `matches()` expressions (#155).
- ManageSieve LOGOUT should reply with `OK` instead of `BYE`.
## [0.6.0] - 2024-02-14
This version introduces breaking changes in the configuration file. Please read the [UPGRADING.md](UPGRADING.md) file for more information on how to upgrade from previous versions.
### Added
- Distributed and fault-tolerant SMTP message queues.
- Distributed rate-limiting and fail2ban.
- Expressions in configuration files.
### Changed
### Fixed
- Do not include `STATUS` in IMAP `NOOP` responses (#234).
- Allow multiple SMTP `HELO` commands.
- Redirect OAuth using a `301` instead of a `307` code.
## [0.5.3] - 2024-01-14
Please read the [UPGRADING.md](UPGRADING.md) file for more information on how to upgrade from previous versions.
### Added
- Built-in [fail2ban](https://stalw.art/docs/server/fail2ban) and IP address/mask blocking (#164).
- CLI: Read URL and credentials from environment variables (#88).
- mySQL driver: Add `max-allowed-packet` setting (#201).
### Changed
- Unified storage settings for all services (read the [UPGRADING.md](UPGRADING.md) for details)
### Fixed
- IMAP retrieval of auto-encrypted emails (#203).
- mySQL driver: Parse `timeout.wait` property as duration (#202).
- `X-Forwarded-For` header on JMAP Rate-Limit does not work (#208).
- Use timeouts in install script (#138).
## [0.5.2] - 2024-01-07
Please read the [UPGRADING.md](UPGRADING.md) file for more information on how to upgrade from previous versions.
### Added
- [ACME](https://stalw.art/docs/server/tls/acme) support for automatic TLS certificate generation and renewal (#160).
- TLS certificate [hot-reloading](https://stalw.art/docs/management/database/maintenance#tls-certificate-reloading).
- [HAProxy protocol](https://stalw.art/docs/server/proxy) support (#36).
### Changed
### Fixed
- IMAP command `SEARCH <seqnum>` is using UIDs rather than sequence numbers.
- IMAP responses to `APPEND` and `EXPUNGE` should include `HIGHESTMODSEQ` when `CONDSTORE` is enabled.
## [0.5.1] - 2024-01-02
### Added
- SMTP smuggling protection: Sanitization of outgoing messages that do not use `CRLF` as line endings.
- SMTP sender validation for authenticated users: Added the `session.auth.must-match-sender` configuration option to enforce that the sender address used in the `MAIL FROM` command matches the authenticated user or any of their associated e-mail addresses.
### Changed
### Fixed
- Invalid DKIM signatures for empty message bodies.
- IMAP command `SEARCH BEFORE` is not properly parsed.
- IMAP command `FETCH` fails to parse single arguments without parentheses.
- IMAP command `ENABLE QRESYNC` should also enable `CONDSTORE` extension.
- IMAP response to `ENABLE` command does not include enabled capabilities list.
- IMAP response to `FETCH ENVELOPE` should not return `NIL` when the `From` header is missing.
## [0.5.0] - 2023-12-27
This version requires a database migration and introduces breaking changes in the configuration file. Please read the [UPGRADING.md](UPGRADING.md) file for more information.
### Added
- Performance enhancements:
- Messages are parsed only once and their offsets stored in the database, which avoids having to parse them on every `FETCH` request.
- Background full-text indexing.
- Optimization of database access functions.
- Storage layer improvements:
- In addition to `FoundationDB` and `SQLite`, now it is also possible to use `RocksDB`, `PostgreSQL` and `mySQL` as a storage backend.
- Blobs can now be stored in any of the supported data stores, it is no longer limited to the file system or S3/MinIO.
- Full-text searching con now be done internally or delegated to `ElasticSearch`.
- Spam databases can now be stored in any of the supported data stores or `Redis`. It is no longer necessary to have an SQL server to use the spam filter.
- Internal directory:
- User account, groups and mailing lists can now be managed directly from Stalwart without the need of an external LDAP or SQL directory.
- HTTP API to manage users, groups, domains and mailing lists.
- IMAP4rev1 `Recent` flag support, which improves compatibility with old IMAP clients.
- LDAP bind authentication, to support some LDAP servers such as `lldap` which do not expose the userPassword attribute.
- Messages marked a spam by the spam filter can now be automatically moved to the account's `Junk Mail` folder.
- Automatic creation of JMAP identities.
### Changed
### Fixed
- Spamhaus DNSBL return codes.
- CLI tool reports authentication errors rather than a parsing error.
## [0.4.2] - 2023-11-01
### Added
- JMAP for Quotas support ([RFC9425](https://www.rfc-editor.org/rfc/rfc9425.html))
- JMAP Blob Management Extension support ([RFC9404](https://www.rfc-editor.org/rfc/rfc9404.html))
- Spam Filter - Empty header rules.
### Changed
### Fixed
- Daylight savings time support for crontabs.
- JMAP `oldState` doesn’t reflect in `*/changes` (#56)
## [0.4.1] - 2023-10-26
### Added
### Changed
### Fixed
- Dockerfile entrypoint script.
- `bayes_is_balanced` function.
## [0.4.0] - 2023-10-25
This version introduces some breaking changes in the configuration file. Please read the [UPGRADING.md](UPGRADING.md) file for more information.
### Added
- Built-in Spam and Phishing filter.
- Scheduled queries on some directory types.
- In-memory maps and lists containing glob or regex patterns.
- Remote retrieval of in-memory list/maps with fallback mechanisms.
- Macros and support for including files from TOML config files.
### Changed
- `config.toml` is now split in multiple TOML files for better organization.
- **BREAKING:** Configuration key prefix `jmap.sieve` (JMAP Sieve Interpreter) has been renamed to `sieve.untrusted`.
- **BREAKING:** Configuration key prefix `sieve` (SMTP Sieve Interpreter) has been renamed to `sieve.trusted`.
### Fixed
## [0.3.10] - 2023-10-17
### Added
- Option to allow invalid certificates on outbound SMTP connections.
- Option to disable ansi colors on `stdout`.
### Changed
- SMTP reject messages are now logged as `info` rather than `debug`.
### Fixed
## [0.3.9] - 2023-10-07
### Added
- Support for reading environment variables from the configuration file using the `!ENV_VAR_NAME` special keyword.
- Option to disable ANSI color codes in logs.
### Changed
- Querying directories from a Sieve script is now done using the `query()` method from `eval`. Your scripts will need to be updated, please refer to the [new syntax](https://stalw.art/docs/smtp/filter/sieve#directory-queries).
### Fixed
- IPrev lookups of IPv4 mapped to IPv6 addresses.
## [0.3.8] - 2023-09-19
### Added
- Journal logging support
- IMAP support for UTF8 APPEND
### Changed
- Replaced `rpgp` with `sequoia-pgp` due to rpgp bug.
### Fixed
- Fix: IMAP folders that contain a & can't be used (#90)
- Fix: Ignore empty lines in IMAP requests
## [0.3.7] - 2023-09-05
### Added
- Option to disable IMAP All Messages folder (#68).
- Option to allow unencrypted SMTP AUTH (#72)
- Support for `rcpt-domain` key in `rcpt.relay` SMTP rule evaluation.
### Changed
### Fixed
- SMTP strategy `Ipv6thenIpv4` returns only IPv6 addresses (#70)
- Invalid IMAP `FETCH` responses for non-UTF-8 messages (#70)
- Allow `STATUS` and `ACL` IMAP operations on virtual mailboxes.
- IMAP `SELECT QRESYNC` without specifying a UID causes panic (#67)
- Milter `DATA` command is sent after headers which causes ClamAV to hang.
- Sieve `redirect` of unmodified messages does not work.
## [0.3.6] - 2023-08-29
### Added
- Arithmetic and logical expression evaluation in Sieve scripts.
- Support for storing query results in Sieve variables.
- Results of SPF, DKIM, ARC, DMARC and IPREV checks available as environment variables in Sieve scripts.
- Configurable protocol flags for Milter filters.
- Fall-back to plain text when `STARTTLS` fails and `starttls` is set to `optional`.
### Changed
### Fixed
- Do not panic when `hash = 0` in reports. (#60)
- JMAP Session resource returns `EmailSubmission` capabilities using arrays rather than objects.
- ManageSieve `PUTSCRIPT` should replace existing scripts.
## [0.3.5] - 2023-08-18
### Added
- TCP listener option `nodelay`.
### Changed
### Fixed
- SMTP: Allow disabling `STARTTLS`.
- JMAP: Support for `OPTIONS` HTTP method.
## [0.3.4] - 2023-08-09
### Added
- JMAP: Support for setting custom HTTP response headers (#52)
### Changed
### Fixed
- SMTP: Missing envelope keys in rewrite rules (#25)
- SMTP: Remove CRLF from Milter headers
- JMAP/IMAP: Successful authentication requests should not count when rate limiting
- IMAP: Case insensitive Inbox selection
- IMAP: Automatically create Inbox for group accounts
## [0.3.3] - 2023-08-02
### Added
- Encryption at rest with **S/MIME** or **OpenPGP**.
- Support for referencing context variables from dynamic values.
### Changed
### Fixed
- Support for PKCS8v1 ED25519 keys (#20).
- Automatic retry for import/export blob downloads (#14)
## [0.3.2] - 2023-07-28
### Added
- Sender and recipient address rewriting using regular expressions and sieve scripts.
- Subaddressing and catch-all addresses using regular expressions (#10).
- Dynamic variables in SMTP rules.
### Changed
- Added CLI to Docker container (#19).
### Fixed
- Workaround for a bug in `sqlx` that caused SQL time-outs (#15).
- Support for ED25519 certificates in PEM files (#20).
- Better handling of concurrent IMAP UID map modifications (#17).
- LDAP domain lookups from SMTP rules.
## [0.3.1] - 2023-07-22
### Added
- Milter filter support.
- Match IP address type using /0 mask (#16).
### Changed
### Fixed
- Support for OpenLDAP password hashing schemes between curly brackets (#8).
- Add CA certificates to Docker runtime (#5).
## [0.3.0] - 2023-07-16
### Added
- **LDAP** and **SQL** authentication.
- **subaddressing** and **catch-all** addresses.
- **S3-compatible** storage.
### Changed
- Merged the `stalwart-jmap`, `stalwart-imap` and `stalwart-smtp` repositories into
`stalwart-mail`.
- Removed clustering module and replaced it with a **FoundationDB** backend option.
- Integrated Stalwart SMTP into Stalwart JMAP.
- Rewritten JMAP protocol parser.
- Rewritten store backend.
- Rewritten IMAP server to have direct access to the message store (no more IMAP proxy).
- Replaced `actix` with `hyper`.
### Fixed
================================================
FILE: CNAME
================================================
get.stalw.art
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
## Contributions are Temporarily Limited
Thank you for your interest in contributing to Stalwart. We appreciate the support and enthusiasm of the open-source community. However, at this stage of the project, we are **limiting the scope of external contributions**.
Stalwart is currently **not accepting external contributions**, except for bug fixes and small, well-scoped changes. The project is approaching version 1.0, and as we move toward this milestone, development is progressing rapidly. The architecture of Stalwart is still evolving, and many internal components are subject to change.
Due to these ongoing changes and the fast pace of development, we do not have the time or resources to thoroughly review and integrate most pull requests. Accepting broad contributions at this time could lead to confusion and unnecessary rework for both contributors and maintainers.
While we are not accepting most code contributions, you can still support the project in meaningful ways. Reporting bugs, providing feedback, and helping test the software are all valuable forms of participation. If you encounter an issue, please open a detailed report that includes steps to reproduce the problem and any relevant logs or context. We also welcome thoughtful suggestions and questions through our issue tracker or discussion channels.
We plan to open the project to broader contributions once we reach a stable 1.0 release. At that point, with a more mature architecture and clearer development roadmap, we will be better positioned to collaborate with the community. We will update this policy accordingly when the time comes.
Thank you for your understanding and continued support. We’re excited about the future of Stalwart and look forward to working with the community in the near future.
## Code of Conduct
Please note we have a code of conduct, please follow it in all your interactions with the project.
## Licensing
This project is licensed under the Affero General Public License (AGPL) version 3.0. By contributing to this project, you agree that your contributions will be licensed under the AGPL-3.0 license.
## Fiduciary Contributor License Agreement
Before making any contributions, all contributors are required to sign the Fiduciary Contributor License Agreement (FLA). The FLA is a legal agreement that assigns the copyright of contributions to a designated fiduciary, who manages these rights on behalf of the project. This arrangement ensures that the software remains free and open, even as contributors come and go.
Key points of the FLA:
- Ensures the software remains free and open source
- Protects the project from potential copyright issues
- Includes a reversion clause: if the fiduciary violates Free Software principles, rights revert to the original contributors
For more details about FLA, please refer to the [FLA FAQ](https://fsfe.org/activities/fla/fla.en.html).
## Pull Request Process
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
build.
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Increase the version numbers in any examples files and the README.md to the new version that this
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you.
## Code of Conduct
We as members, contributors, and leaders pledge to make participation in our community a harassment-free
experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex
characteristics, gender identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive,
and healthy community.
You can read the full Code of Conduct [here](https://github.com/stalwartlabs/.github/blob/main/CODE_OF_CONDUCT.md).
================================================
FILE: Cargo.toml
================================================
[workspace]
resolver = "2"
members = [
"crates/main",
"crates/types",
"crates/http",
"crates/http-proto",
"crates/jmap",
"crates/jmap-proto",
"crates/email",
"crates/imap",
"crates/imap-proto",
"crates/smtp",
"crates/managesieve",
"crates/pop3",
"crates/dav-proto",
"crates/dav",
"crates/groupware",
"crates/spam-filter",
"crates/nlp",
"crates/store",
"crates/directory",
"crates/services",
"crates/utils",
"crates/common",
"crates/trc",
"crates/migration",
"crates/cli",
"tests",
]
[profile.dev]
opt-level = 0
debug = 1
#codegen-units = 4
lto = false
incremental = true
panic = 'unwind'
debug-assertions = true
overflow-checks = false
rpath = false
[profile.release]
opt-level = 3
debug = false
codegen-units = 1
lto = true
incremental = false
panic = 'unwind'
debug-assertions = false
overflow-checks = false
rpath = false
strip = true
[profile.test]
opt-level = 0
debug = 1
#codegen-units = 16
lto = false
incremental = true
debug-assertions = true
overflow-checks = true
rpath = false
[profile.bench]
opt-level = 3
debug = false
codegen-units = 1
lto = true
incremental = false
debug-assertions = false
overflow-checks = false
rpath = false
================================================
FILE: Dockerfile
================================================
# Stalwart Dockerfile
# Credits: https://github.com/33KK
FROM --platform=$BUILDPLATFORM docker.io/lukemathwalker/cargo-chef:latest-rust-slim-trixie AS chef
WORKDIR /build
FROM --platform=$BUILDPLATFORM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path /recipe.json
FROM --platform=$BUILDPLATFORM chef AS builder
ARG TARGETPLATFORM
RUN case "${TARGETPLATFORM}" in \
"linux/arm64") echo "aarch64-unknown-linux-gnu" > /target.txt && echo "-C linker=aarch64-linux-gnu-gcc" > /flags.txt ;; \
"linux/amd64") echo "x86_64-unknown-linux-gnu" > /target.txt && echo "-C linker=x86_64-linux-gnu-gcc" > /flags.txt ;; \
*) exit 1 ;; \
esac
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -yq --no-install-recommends build-essential libclang-19-dev \
g++-aarch64-linux-gnu binutils-aarch64-linux-gnu \
g++-x86-64-linux-gnu binutils-x86-64-linux-gnu
RUN rustup target add "$(cat /target.txt)"
COPY --from=planner /recipe.json /recipe.json
RUN RUSTFLAGS="$(cat /flags.txt)" cargo chef cook --target "$(cat /target.txt)" --release --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats enterprise" --recipe-path /recipe.json
COPY . .
RUN RUSTFLAGS="$(cat /flags.txt)" cargo build --target "$(cat /target.txt)" --release -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats enterprise"
RUN RUSTFLAGS="$(cat /flags.txt)" cargo build --target "$(cat /target.txt)" --release -p stalwart-cli
RUN mv "/build/target/$(cat /target.txt)/release" "/output"
FROM docker.io/debian:trixie-slim
WORKDIR /opt/stalwart
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -yq --no-install-recommends ca-certificates
COPY --from=builder /output/stalwart /usr/local/bin
COPY --from=builder /output/stalwart-cli /usr/local/bin
COPY ./resources/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod -R 755 /usr/local/bin
CMD ["/usr/local/bin/stalwart"]
VOLUME [ "/opt/stalwart" ]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENTRYPOINT ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
================================================
FILE: Dockerfile.build
================================================
# syntax=docker/dockerfile:1
# check=skip=FromPlatformFlagConstDisallowed,RedundantTargetPlatform
# *****************
# Base image for planner & builder
# *****************
FROM --platform=$BUILDPLATFORM rust:slim-trixie AS base
ENV DEBIAN_FRONTEND="noninteractive" \
BINSTALL_DISABLE_TELEMETRY=true \
CARGO_TERM_COLOR=always \
LANG=C.UTF-8 \
TZ=UTC \
TERM=xterm-256color
# With zig, we only need libclang and make
RUN \
--mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
rm -f /etc/apt/apt.conf.d/docker-clean && \
echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache && \
apt-get update && \
apt-get install -yq --no-install-recommends curl jq xz-utils make libclang-19-dev
# Install zig
RUN \
ZIG_VERSION=0.13.0 && \
[ ! -z "$ZIG_VERSION" ] && \
curl --retry 5 -Ls "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-$(uname -m)-${ZIG_VERSION}.tar.xz" | tar -J -x -C /usr/local && \
ln -s "/usr/local/zig-linux-$(uname -m)-${ZIG_VERSION}/zig" /usr/local/bin/zig
# Install cargo-binstall
RUN curl --retry 5 -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
# Install cargo-chef & sccache & cargo-zigbuild
RUN cargo binstall --no-confirm cargo-chef sccache cargo-zigbuild
# *****************
# Planner
# *****************
FROM base AS planner
WORKDIR /app
COPY . .
# Generate recipe file
RUN cargo chef prepare --recipe-path recipe.json
# *****************
# Builder
# *****************
FROM base AS builder
WORKDIR /app
COPY --from=planner /app/recipe.json recipe.json
ARG TARGET
ARG BUILD_ENV
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Install toolchain and specify some env variables
RUN \
rustup set profile minimal && \
rustup target add ${TARGET} && \
mkdir -p artifact && \
touch /env-cargo && \
if [ ! -z "${BUILD_ENV}" ]; then \
echo "export ${BUILD_ENV}" >> /env-cargo; \
echo "Setting up ${BUILD_ENV}"; \
fi && \
if [[ "${TARGET}" == *gnu ]]; then \
base_arch="${TARGET%%-*}"; \
case "$base_arch" in \
x86_64) \
echo "export FDB_ARCH=amd64" >> /env-cargo; \
;; \
aarch64) \
echo "export FDB_ARCH=aarch64" >> /env-cargo; \
;; \
*) \
exit 1; \
;; \
esac; \
fi
# Install FoundationDB
RUN \
source /env-cargo && \
if [ ! -z "${FDB_ARCH}" ]; then \
curl --retry 5 -Lso fdb-client.deb "$(curl --retry 5 -Ls 'https://api.github.com/repos/apple/foundationdb/releases' | jq --arg FDB_ARCH "$FDB_ARCH" -r '.[] | select(.prerelease == false) | .assets[] | select(.name | test("foundationdb-clients.*" + $FDB_ARCH + ".deb$")) | .browser_download_url' | head -n1)" && \
mkdir -p /fdb && \
dpkg -x fdb-client.deb /fdb && \
mv /fdb/usr/include/foundationdb /usr/include && \
mv /fdb/usr/lib/libfdb_c.so /usr/lib && \
rm -rf fdb-client.deb /fdb; \
fi
# Cargo-chef Cache layer
RUN \
--mount=type=secret,id=ACTIONS_RESULTS_URL,env=ACTIONS_RESULTS_URL \
--mount=type=secret,id=ACTIONS_RUNTIME_TOKEN,env=ACTIONS_RUNTIME_TOKEN \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
if [ ! -z "${FDB_ARCH}" ]; then \
RUSTFLAGS="-L /usr/lib" cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "foundationdb s3 redis nats enterprise"; \
fi
RUN \
--mount=type=secret,id=ACTIONS_RESULTS_URL,env=ACTIONS_RESULTS_URL \
--mount=type=secret,id=ACTIONS_RUNTIME_TOKEN,env=ACTIONS_RUNTIME_TOKEN \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats enterprise" && \
cargo chef cook --recipe-path recipe.json --zigbuild --release --target ${TARGET} -p stalwart-cli
# Copy the source code
COPY . .
ENV RUSTC_WRAPPER="sccache" \
SCCACHE_GHA_ENABLED=true
# Build FoundationDB version
RUN \
--mount=type=secret,id=ACTIONS_RESULTS_URL,env=ACTIONS_RESULTS_URL \
--mount=type=secret,id=ACTIONS_RUNTIME_TOKEN,env=ACTIONS_RUNTIME_TOKEN \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
if [ ! -z "${FDB_ARCH}" ]; then \
RUSTFLAGS="-L /usr/lib" cargo zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "foundationdb s3 redis nats enterprise" && \
mv /app/target/${TARGET}/release/stalwart /app/artifact/stalwart-foundationdb; \
fi
# Build generic version
RUN \
--mount=type=secret,id=ACTIONS_RESULTS_URL,env=ACTIONS_RESULTS_URL \
--mount=type=secret,id=ACTIONS_RUNTIME_TOKEN,env=ACTIONS_RUNTIME_TOKEN \
--mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
source /env-cargo && \
cargo zigbuild --release --target ${TARGET} -p stalwart --no-default-features --features "sqlite postgres mysql rocks s3 redis azure nats enterprise" && \
cargo zigbuild --release --target ${TARGET} -p stalwart-cli && \
mv /app/target/${TARGET}/release/stalwart /app/artifact/stalwart && \
mv /app/target/${TARGET}/release/stalwart-cli /app/artifact/stalwart-cli
# *****************
# Binary stage
# *****************
FROM scratch AS binaries
COPY --from=builder /app/artifact /
# *****************
# Runtime image for GNU targets
# *****************
FROM --platform=$TARGETPLATFORM docker.io/library/debian:trixie-slim AS gnu
WORKDIR /opt/stalwart
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -yq --no-install-recommends ca-certificates tzdata
COPY --from=builder /app/artifact/stalwart /usr/local/bin
COPY --from=builder /app/artifact/stalwart-cli /usr/local/bin
COPY ./resources/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod -R 755 /usr/local/bin
CMD ["/usr/local/bin/stalwart"]
VOLUME [ "/opt/stalwart" ]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENTRYPOINT ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
# *****************
# Runtime image for musl targets
# *****************
FROM --platform=$TARGETPLATFORM alpine AS musl
WORKDIR /opt/stalwart
RUN apk add --update --no-cache ca-certificates tzdata && rm -rf /var/cache/apk/*
COPY --from=builder /app/artifact/stalwart /usr/local/bin
COPY --from=builder /app/artifact/stalwart-cli /usr/local/bin
COPY ./resources/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod -R 755 /usr/local/bin
CMD ["/usr/local/bin/stalwart"]
VOLUME [ "/opt/stalwart" ]
EXPOSE 443 25 110 587 465 143 993 995 4190 8080
ENTRYPOINT ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
================================================
FILE: LICENSES/AGPL-3.0-only.txt
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based on the Program.
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.
================================================
FILE: LICENSES/LicenseRef-SEL.txt
================================================
Stalwart Enterprise License 1.0 (SELv1) Agreement
=================================================
Last Update: April 29, 2025
PLEASE CAREFULLY READ THIS STALWART ENTERPRISE LICENSE AGREEMENT ("AGREEMENT"). THIS AGREEMENT CONSTITUTES A LEGALLY BINDING AGREEMENT BETWEEN YOU AND Stalwart Labs LLC AND GOVERNS YOUR USE OF THE SOFTWARE (DEFINED BELOW). IF YOU DO NOT AGREE WITH THIS AGREEMENT, YOU MAY NOT USE THE SOFTWARE. IF YOU ARE USING THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU HAVE AUTHORITY TO AGREE TO THIS AGREEMENT ON BEHALF OF SUCH ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, DO NOT USE THE SOFTWARE IN ANY MANNER.
This Agreement is entered into by and between Stalwart Labs LLC and you, or the legal entity on behalf of whom you are acting.
1. DEFINITIONS
1.1. "Software" refers to the Stalwart Server Enterprise Edition software, including all its versions, updates, modifications, accompanying documentation, and related materials.
1.2. "Subscription" refers to the paid access to the Software provided by Licensor to Licensee.
1.3. "Licensor" refers to Stalwart Labs LLC, the entity providing the Software.
1.4. "Licensee" refers to the individual or entity installing, accessing, or using the Software with a valid Subscription.
1.5. "License Key" refers to the unique code provided by Licensor upon purchasing a Subscription which activates the full features of the Software.
1.6. "Source Code" refers to the human-readable version of the Software's code, as opposed to the compiled machine-readable version.
2. GRANT OF LICENSE
2.1. Licensor grants Licensee a revocable, non-exclusive, non-transferable, non-sublicensable, limited license to download, install, and use the Software.
2.2. The use of the Software is conditioned upon Licensee maintaining an active and valid paid subscription with Licensor. The paid subscription covers all versions of the Software and all updates and modifications.
2.3. This license grants Licensee the right to use the Software for both personal and commercial purposes. However, Licensee is expressly prohibited from reselling, leasing, sublicensing, or otherwise redistributing the Software itself.
2.4. This license is further governed by the terms and conditions set forth in any licensing agreements separately executed between Licensor and Licensee. In the event of any conflict between the terms of this Agreement and the terms of a signed licensing agreement, the terms of the signed licensing agreement shall control.
2.5. You are not granted any other rights beyond what is expressly stated herein.
3. LICENSE KEYS
3.1. The Software shall not be used without a valid License Key issued by Licensor.
3.2. Licensee is required to use valid License Keys issued by Licensor to run the Software, including any modified versions. Any attempts to bypass the License Key requirement is a violation of this Agreement.
3.3. Distribution or sharing of License Keys to third parties, not associated with Licensee, is strictly prohibited.
3.4. License Keys are bound to the subscription period. Should your subscription expire, all License Keys will become invalid after 15 days from the subscription expiration date.
3.5. Any instance of the Software using such an expired key will revert to the Community Edition functionality after the aforementioned 15-day period.
4. SOURCE CODE USAGE
4.1. Licensee is permitted to view, copy, and modify the Software's Source Code, as made available by Licensor, solely for Licensee's internal business use and in compliance with this Agreement's terms.
4.2. Any modifications to the Source Code do not grant Licensee any ownership rights to the original Software or any modifications. All rights, title, and interest to the Software and its Source Code remain exclusively with Licensor.
4.3. Licensee is strictly prohibited from altering, removing, or in any way tampering with the License Key validation system within the Software. Any such unauthorized modifications will be considered a material breach of this Agreement and may result in legal action.
4.3. Notwithstanding the availability of the Software's Source Code for review and limited modification, the Software and its Source Code are not open source and remain proprietary to Licensor. The provision of access to the Source Code does not confer any rights typically associated with open source software, including but not limited to the right to freely sublicense, or create derivative works for public distribution. All rights not expressly granted herein are reserved by Licensor.
4.4. Notwithstanding the foregoing, you may copy the Source Code for development and testing purposes, without requiring a Subscription.
5. INTELLECTUAL PROPERTY RIGHTS
5.1. The Licensor retains all rights, title, and interest in and to the Software, including all intellectual property rights therein. This Agreement does not transfer any ownership rights to the Licensee.
5.2. The Licensee must not remove, alter, or obscure any proprietary notices (including copyright and trademark notices) on the Software.
6. TERMINATION
6.1. Licensor reserves the right to terminate this Agreement immediately if the Licensee fails to comply with any terms and conditions of this Agreement.
6.2. In the event of a termination, you will be provided with a written notice, sent to the email address used during your subscription to the Software, outlining the reasons for the termination.
6.3. Upon termination, all rights granted to you under this Agreement will cease, and you must promptly cease all use of the Software.
7. LIMITATION OF LIABILITY
7.1. In no event will the Licensor be liable for any indirect, incidental, special, consequential, or punitive damages, or any loss of profits or revenues, whether incurred directly or indirectly, or any loss of data, use, goodwill, or other intangible losses, resulting from (i) your use or inability to use the Software; (ii) any unauthorized access to or use of our servers and/or any personal information stored therein.
7.2. Except for liability arising from death or personal injury caused by negligence, fraud, or willful misconduct, Licensor's total aggregate liability for any and all claims under this Agreement shall be limited to the total Subscription fees paid by Licensee to Licensor in the twelve (12) months immediately preceding the event giving rise to the claim.
8. GOVERNING LAW & JURISDICTION
This Agreement shall be governed by and construed under the laws of the United Kingdom. Any disputes arising from or related to this Agreement shall be resolved in the jurisdiction of London, UK.
9. DATA PROTECTION & PRIVACY
By using the Software, you consent to the collection, processing, and use of any personal data as required for the functionality of the Software. The specifics of data handling and storage will be outlined in the company's Privacy Policy, which can be accessed on the company's website.
10. ACCEPTANCE
By downloading, installing, or using the Software software, even without explicitly clicking on an "I Agree" button or a similar mechanism, you acknowledge that you have read, understood, and agreed to be bound by the terms and conditions of this Agreement.
11. ASSIGNMENT
This Agreement and the rights granted hereunder may not be transferred or assigned by you but may be assigned by Licensor without restriction.
12. SEVERABILITY
If any provision of this Agreement is held to be unenforceable or invalid for any reason, that provision shall be reformed to the extent necessary to make it enforceable and consistent with the intent of the parties, and the remaining provisions shall remain in full force and effect.
13. ENTIRE AGREEMENT
This Agreement constitutes the entire agreement between the Licensor and the Licensee with respect to the subject matter hereof and supersedes all prior or contemporaneous understandings regarding such subject matter. No amendment to or modification of this Agreement will be binding unless in writing and signed by the Licensor.
14. DISCLAIMERS AND WARRANTIES
The Software is provided "AS IS" and "AS AVAILABLE", without warranty of any kind, either express or implied, including, without limitation, warranties of merchantability, fitness for a particular purpose, and non-infringement. Licensor does not warrant that the Software will be error-free, that access thereto will be uninterrupted, or that defects will be corrected.
15. INDEMNIFICATION
Licensee agrees to indemnify, defend, and hold harmless Licensor, its officers, directors, employees, agents, licensors, suppliers, and any third-party information providers from and against all claims, losses, expenses, damages, and costs, including reasonable attorneys' fees, resulting from any violation of this Agreement or any activity related to your use or misuse of the Software (including negligent or wrongful conduct).
16. FORCE MAJEURE
Neither party shall be in default or otherwise liable for any delay in or failure of its performance under this Agreement if such delay or failure arises by any reason of any event beyond the reasonable control of a party, including acts of God, the elements, earthquakes, floods, fires, epidemics, riots, failures or delays in transportation or communications, or any act or failure to act by the other party or such other party’s officers, employees, agents, or contractors. The parties will promptly inform and consult with each other as to any of the above causes which, in their judgment, may or could be the cause of a delay in the performance of this Agreement.
17. CONTACT INFORMATION
If you have any questions about this Agreement, please contact Stalwart Labs LLC at:
Stalwart Labs LLC
1309 Coffeen Avenue STE 1200
Sheridan, Wyoming 82801
USA
hello@stalw.art
================================================
FILE: README.md
================================================
<p align="center">
<a href="https://stalw.art">
<img src="./img/logo-red.svg" height="150">
</a>
</p>
<h3 align="center">
Secure, scalable mail & collaboration server with comprehensive protocol support 🛡️ <br/>(IMAP, JMAP, SMTP, CalDAV, CardDAV, WebDAV)
</h3>
<br>
<p align="center">
<a href="https://github.com/stalwartlabs/stalwart/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/stalwartlabs/stalwart/ci.yml?style=flat-square" alt="continuous integration"></a>
<a href="https://www.gnu.org/licenses/agpl-3.0"><img src="https://img.shields.io/badge/License-AGPL_v3-blue.svg?label=license&style=flat-square" alt="License: AGPL v3"></a>
<a href="https://stalw.art/docs/install/get-started"><img src="https://img.shields.io/badge/read_the-docs-red?style=flat-square" alt="Documentation"></a>
</p>
<p align="center">
<a href="https://mastodon.social/@stalwartlabs"><img src="https://img.shields.io/mastodon/follow/109929667531941122?style=flat-square&logo=mastodon&color=%236364ff&label=Follow%20on%20Mastodon" alt="Mastodon"></a>
<a href="https://twitter.com/stalwartlabs"><img src="https://img.shields.io/twitter/follow/stalwartlabs?style=flat-square&logo=x&label=Follow%20on%20Twitter" alt="Twitter"></a>
</p>
<p align="center">
<a href="https://discord.com/servers/stalwart-923615863037390889"><img src="https://img.shields.io/discord/923615863037390889?label=Join%20Discord&logo=discord&style=flat-square" alt="Discord"></a>
<a href="https://www.reddit.com/r/stalwartlabs/"><img src="https://img.shields.io/reddit/subreddit-subscribers/stalwartlabs?label=Join%20%2Fr%2Fstalwartlabs&logo=reddit&style=flat-square" alt="Reddit"></a>
</p>
## Features
**Stalwart** is an open-source mail & collaboration server with JMAP, IMAP4, POP3, SMTP, CalDAV, CardDAV and WebDAV support and a wide range of modern features. It is written in Rust and designed to be secure, fast, robust and scalable.
Key features:
- **Email** server with complete protocol support:
- JMAP:
* [JMAP for Mail](https://datatracker.ietf.org/doc/html/rfc8621) server.
* [JMAP for Sieve Scripts](https://www.ietf.org/archive/id/draft-ietf-jmap-sieve-22.html).
* [WebSocket](https://datatracker.ietf.org/doc/html/rfc8887), [Blob Management](https://www.rfc-editor.org/rfc/rfc9404.html) and [Quotas](https://www.rfc-editor.org/rfc/rfc9425.html) extensions.
- IMAP:
* [IMAP4rev2](https://datatracker.ietf.org/doc/html/rfc9051) and [IMAP4rev1](https://datatracker.ietf.org/doc/html/rfc3501) server.
* [ManageSieve](https://datatracker.ietf.org/doc/html/rfc5804) server.
* Numerous [extensions](https://stalw.art/docs/development/rfcs#imap4-and-extensions) supported.
- POP3:
- [POP3](https://datatracker.ietf.org/doc/html/rfc1939) server.
- [STLS](https://datatracker.ietf.org/doc/html/rfc2595) and [SASL](https://datatracker.ietf.org/doc/html/rfc5034) support as well as other [extensions](https://datatracker.ietf.org/doc/html/rfc2449).
- SMTP:
* SMTP server with built-in [DMARC](https://datatracker.ietf.org/doc/html/rfc7489), [DKIM](https://datatracker.ietf.org/doc/html/rfc6376), [SPF](https://datatracker.ietf.org/doc/html/rfc7208) and [ARC](https://datatracker.ietf.org/doc/html/rfc8617) support for message authentication.
* Strong transport security through [DANE](https://datatracker.ietf.org/doc/html/rfc6698), [MTA-STS](https://datatracker.ietf.org/doc/html/rfc8461) and [SMTP TLS](https://datatracker.ietf.org/doc/html/rfc8460) reporting.
* Inbound throttling and filtering with granular configuration rules, sieve scripting, MTA hooks and milter integration.
* Distributed virtual queues with delayed delivery, priority delivery, quotas, routing rules and throttling support.
* Envelope rewriting and message modification.
- **Collaboration** server:
- Calendaring and scheduling:
- [CalDAV](https://datatracker.ietf.org/doc/html/rfc4791) and [CalDAV Scheduling](https://datatracker.ietf.org/doc/html/rfc6638) support.
- [JMAP for Calendars](https://datatracker.ietf.org/doc/html/draft-ietf-jmap-calendars-24) support.
- Contact management:
- [CardDAV](https://datatracker.ietf.org/doc/html/rfc6352) support.
- [JMAP for Contacts](https://datatracker.ietf.org/doc/html/rfc9610) support.
- File storage:
- [WebDAV](https://datatracker.ietf.org/doc/html/rfc4918) support.
- [JMAP for File Storage](https://datatracker.ietf.org/doc/html/draft-ietf-jmap-filenode-03) support.
- Sharing with fine-grained access controls:
- [WebDAV ACL](https://datatracker.ietf.org/doc/html/rfc3744) support.
- [JMAP Sharing](https://datatracker.ietf.org/doc/html/rfc9670) support.
- **Spam** and **Phishing** built-in filter:
- Comprehensive set of filtering **rules** on par with popular solutions.
- LLM-driven spam filtering and message analysis.
- Statistical **spam classifier** with collaborative filtering, automatic training capabilities and address book integration.
- DNS Blocklists (**DNSBLs**) checking of IP addresses, domains, and hashes.
- Collaborative digest-based spam filtering with **Pyzor**.
- **Phishing** protection against homographic URL attacks, sender spoofing and other techniques.
- Trusted **reply** tracking to recognize and prioritize genuine e-mail replies.
- Sender **reputation** monitoring by IP address, ASN, domain and email address.
- **Greylisting** to temporarily defer unknown senders.
- **Spam traps** to set up decoy email addresses that catch and analyze spam.
- **Flexible**:
- Pluggable storage backends with **RocksDB**, **FoundationDB**, **PostgreSQL**, **mySQL**, **SQLite**, **S3-Compatible**, **Azure** and **Redis** support.
- Full-text search available in 17 languages using the built-in search engine or via **Meilisearch**, **ElasticSearch**, **OpenSearch**, **PostgreSQL** or **mySQL** backends.
- Sieve scripting language with support for all [registered extensions](https://www.iana.org/assignments/sieve-extensions/sieve-extensions.xhtml).
- Email aliases, mailing lists, subaddressing and catch-all addresses support.
- Automatic account configuration and discovery with [autoconfig](https://www.ietf.org/id/draft-bucksch-autoconfig-02.html) and [autodiscover](https://learn.microsoft.com/en-us/exchange/architecture/client-access/autodiscover?view=exchserver-2019).
- Multi-tenancy support with domain and tenant isolation.
- Disk quotas per user and tenant.
- **Secure and robust**:
- Encryption at rest with **S/MIME** or **OpenPGP**.
- Automatic TLS certificate provisioning with [ACME](https://datatracker.ietf.org/doc/html/rfc8555) using `TLS-ALPN-01`, `DNS-01` or `HTTP-01` challenges.
- Automated blocking of IP addresses that attack, abuse or scan the server for exploits.
- Rate limiting.
- Security audited (read the [report](https://stalw.art/blog/security-audit)).
- Memory safe (thanks to Rust).
- **Scalable and fault-tolerant**:
- Designed to handle growth seamlessly, from small setups to large-scale deployments of thousands of nodes.
- Built with **fault tolerance** and **high availability** in mind, recovers from hardware or software failures with minimal operational impact.
- Peer-to-peer cluster coordination or with **Kafka**, **Redpanda**, **NATS** or **Redis**.
- **Kubernetes**, **Apache Mesos** and **Docker Swarm** support for automated scaling and container orchestration.
- Read replicas, sharded blob storage and in-memory data stores for high performance and low latency.
- **Authentication and Authorization**:
- **OpenID Connect** authentication.
- OAuth 2.0 authorization with [authorization code](https://www.rfc-editor.org/rfc/rfc8628) and [device authorization](https://www.rfc-editor.org/rfc/rfc8628) flows.
- **LDAP**, **OIDC**, **SQL** or built-in authentication backend support.
- Two-factor authentication with Time-based One-Time Passwords (`2FA-TOTP`)
- Application passwords (App Passwords).
- Roles and permissions.
- Access Control Lists (ACLs).
- **Observability**:
- Logging and tracing with **OpenTelemetry**, journald, log files and console support.
- Metrics with **OpenTelemetry** and **Prometheus** integration.
- Webhooks for event-driven automation.
- Alerts with email and webhook notifications.
- Live tracing and metrics.
- **Web-based administration**:
- Dashboard with real-time statistics and monitoring.
- Account, domain, group and mailing list management.
- SMTP queue management for messages and outbound DMARC and TLS reports.
- Report visualization interface for received DMARC, TLS-RPT and Failure (ARF) reports.
- Configuration of every aspect of the mail server.
- Log viewer with search and filtering capabilities.
- Self-service portal for password reset and encryption-at-rest key management.
## Screenshots
<img src="./img/screencast-setup.gif">
## Presentation
**Want a deeper dive?** Need to explain to your boss why Stalwart is the perfect fit? Whether you're evaluating options, making a case to your team, or simply curious about how it all works under the hood, these slides walk you through the key features, architecture, and benefits of Stalwart. Browse the [slides](https://stalw.art/slides) to see what makes it stand out.
## Get Started
Install Stalwart on your server by following the instructions for your platform:
- [Linux / MacOS](https://stalw.art/docs/install/platform/linux)
- [Windows](https://stalw.art/docs/install/platform/windows)
- [Docker](https://stalw.art/docs/install/platform/docker)
All documentation is available at [stalw.art/docs](https://stalw.art/docs/install/get-started).
## Support
If you are having problems running Stalwart, you found a bug or just have a question, do not hesitate to reach us on [GitHub Discussions](https://github.com/stalwartlabs/stalwart/discussions), [Reddit](https://www.reddit.com/r/stalwartlabs) or [Discord](https://discord.com/servers/stalwart-923615863037390889).
Additionally you may purchase an [Enterprise License](https://stalw.art/enterprise) to obtain priority support from Stalwart Labs LLC.
## Roadmap
Stalwart has reached an exciting point in its journey, it’s now **feature complete**. All the core functionality and open standard email and collaboration protocols that we set out to support are in place. In other words, Stalwart already does everything you’d expect from a modern, standards-compliant mail and collaboration platform.
The next major milestone is all about refinement: finalizing the database schema and focusing on performance optimizations to ensure everything runs as efficiently and reliably as possible. Once that’s done, we’ll be ready to roll out version **1.0**.
Of course, development doesn’t stop there. The community has contributed hundreds of great ideas for improvements and new features, everything from subtle usability tweaks to entirely new integrations. You can see the full list of proposals over on our [GitHub issues](https://github.com/stalwartlabs/stalwart/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement). If there’s something you’d like to see prioritized, just give it a thumbs up as we plan to implement enhancements based on the community’s votes.
## Sponsorship
Your support is crucial in helping us continue to improve the project, add new features, and maintain the highest level of quality. By [becoming a sponsor](https://opencollective.com/stalwart), you help fund the development and future of Stalwart. As a thank-you, sponsors who contribute $5 per month or more will automatically receive a [Enterprise edition](https://stalw.art/enterprise/) license. And, sponsors who contribute $30 per month or more, also have access to [Premium Support](https://stalw.art/support) from Stalwart Labs.
## Funding
Part of the development of this project was funded through:
- [NGI0 Entrust Fund](https://nlnet.nl/entrust), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 101069594.
- [NGI Zero Core](https://nlnet.nl/NGI0/), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 101092990.
If you find the project useful you can help by [becoming a sponsor](https://opencollective.com/stalwart). Thank you!
## License
This project is dual-licensed under the **GNU Affero General Public License v3.0** (AGPL-3.0; as published by the Free Software Foundation) and the **Stalwart Enterprise License v1 (SELv1)**:
- The [GNU Affero General Public License v3.0](./LICENSES/AGPL-3.0-only.txt) is a free software license that ensures your freedom to use, modify, and distribute the software, with the condition that any modified versions of the software must also be distributed under the same license.
- The [Stalwart Enterprise License v1 (SELv1)](./LICENSES/LicenseRef-SEL.txt) is a proprietary license designed for commercial use. It offers additional features and greater flexibility for businesses that do not wish to comply with the AGPL-3.0 license requirements.
Each file in this project contains a license notice at the top, indicating the applicable license(s). The license notice follows the [REUSE guidelines](https://reuse.software/) to ensure clarity and consistency. The full text of each license is available in the [LICENSES](./LICENSES/) directory.
## Copyright
Copyright (C) 2020, Stalwart Labs LLC
================================================
FILE: SECURITY.md
================================================
# Security Policy for Stalwart
## Supported Versions
We provide security updates for the following versions of Stalwart:
| Version | Supported | End of Support |
| ------- | ------------------ | -------------- |
| 0.15.x | :white_check_mark: | TBD |
| 0.14.x | :white_check_mark: | 2026-06-08 |
| 0.13.x | :white_check_mark: | 2026-03-31 |
| < 0.13 | :x: | Ended |
**Note**: We typically support the current major version and one previous major version. Users are strongly encouraged to upgrade to the latest version for the best security posture.
## Reporting a Vulnerability
We take the security of Stalwart very seriously. If you believe you've found a security vulnerability, we encourage you to inform us responsibly through coordinated disclosure.
### How to Report
**Do not report security vulnerabilities through public GitHub issues, discussions, or social media.**
Instead, please use one of these secure channels:
1. **Email** (preferred): Send details to `security@stalw.art`
2. **GitHub Security Advisories**: Use the "Report a vulnerability" button in the Security tab
3. **Backup contact**: If no response within 48 hours, email `hello@stalw.art`
### What to Include
To help us understand and address the issue quickly, please include:
**Required Information:**
- Brief description of the vulnerability type
- Affected version(s) and components
- Steps to reproduce the issue
- Impact assessment (what could an attacker achieve?)
**Helpful Additional Details:**
- Full paths of affected source files
- Specific commit/branch where the issue exists
- Required configuration to reproduce
- Proof-of-concept code (if available)
- Suggested mitigation or fix (if you have ideas)
### Our Response Process
**Timeline Commitments:**
- **Initial acknowledgment**: Within 24 hours
- **Detailed response**: Within 72 hours
- **Status updates**: Every 7 days until resolved
- **Resolution target**: 90 days for most issues
**What We'll Do:**
1. Acknowledge your report and assign a tracking ID
2. Assess the vulnerability and determine severity
3. Develop and test a fix
4. Coordinate disclosure timeline with you
5. Release security update and publish advisory
6. Credit you in our security advisory (if desired)
## Disclosure Policy
We follow responsible disclosure principles:
- **Coordinated disclosure**: We'll work with you to determine appropriate disclosure timing
- **Typical timeline**: 90 days from report to public disclosure
- **Early disclosure**: May occur if issue is being actively exploited
- **Delayed disclosure**: May be necessary for complex issues requiring significant changes
## Scope
This security policy applies to:
**In Scope:**
- Stalwart (all supported versions)
- Official Docker images
- Documentation that could lead to insecure configurations
- Dependencies with security implications
**Out of Scope:**
- Third-party integrations or plugins
- Issues requiring physical access to the server
- Social engineering attacks
- Attacks requiring compromised credentials (unless the vulnerability enables credential compromise)
- Theoretical vulnerabilities without practical exploitation
## Security Measures
**Our Commitments:**
- Regular security audits of dependencies using `cargo audit`
- Automated security scanning in CI/CD pipeline
- Following Rust security best practices
- Prompt security updates for critical dependencies
- Security-focused code review process
**User Responsibilities:**
- Keep Stalwart updated to supported versions
- Follow security configuration guidelines
- Implement proper network security (firewalls, TLS, etc.)
- Regular security monitoring and logging
- Secure credential management
## Legal Safe Harbor
We support security research conducted in good faith. If you follow these guidelines:
**We will NOT:**
- Initiate legal action against you
- Contact law enforcement about your research
- Suspend or terminate your access to Stalwart services
**You must:**
- Only test against your own Stalwart installations
- Not access, modify, or delete user data
- Not perform testing that could degrade service availability
- Not publicly disclose the issue before coordinated disclosure
- Act in good faith and not for malicious purposes
## Recognition
We believe in recognizing security researchers who help keep Stalwart secure:
- **Security Advisory Credits**: We'll credit you in our GitHub Security Advisories (unless you prefer to remain anonymous)
- **Hall of Fame**: Significant contributors may be listed in our security acknowledgments
- **Swag**: We may send Stalwart merchandise for notable contributions
## Security Updates
**Stay Informed:**
- Subscribe to our [GitHub releases](https://github.com/stalwartlabs/stalwart/releases) for security updates
- Join our community channels for security announcements
- Enable GitHub notifications for security advisories
**Update Process:**
- Security updates are published as patch releases (e.g., 0.12.1 → 0.12.2)
- Critical vulnerabilities may receive out-of-band releases
- Docker images are updated simultaneously with releases
- Security advisories are published through GitHub Security Advisories
## Contact Information
- **Security reports**: security@stalw.art
- **General inquiries**: hello@stalw.art
- **PGP Key**: Available upon request for sensitive communications
## Additional Resources
- [Stalwart Security Incident Response Process](SECURITY_PROCESS.md)
- [Security Configuration Guide](https://stalw.art/docs/install/security)
- [Rust Security Advisory Database](https://rustsec.org/)
*This security policy is effective as of June 20, 2025 and may be updated periodically. Check back regularly for updates.*
================================================
FILE: SECURITY_PROCESS.md
================================================
# Stalwart Security Incident Response Checklist
## Phase 1 : Initial Assessment & Validation
### Updates
<< Use this section to detail the report received, initial assessment, and validation results >>
Example:
I've reviewed the security report and confirmed this vulnerability exists in Stalwart version X.Y.Z.
Assessment of exploitability:
- Attack complexity: [High/Medium/Low]
- Prerequisites: [Authentication required/Network access/Specific configuration/etc.]
- User interaction required: [Yes/No]
Potential impact:
- Email data confidentiality: [At risk/Not affected]
- Server integrity: [At risk/Not affected]
- Service availability: [At risk/Not affected]
- Estimated affected installations: [Number/Percentage]
### Resources
- [Stalwart Security Policy](https://github.com/stalwartlabs/stalwart/blob/main/SECURITY.md)
- [CVE Scoring Calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator)
- [Rust Security Advisory Database](https://rustsec.org/)
### Tasks
- [ ] Reproduce the vulnerability in test environment
- [ ] Assess CVSS score and severity level
- [ ] Check if vulnerability affects current stable version
- [ ] Check if vulnerability affects LTS versions (if applicable)
- [ ] Determine if this requires immediate action or can wait for next release cycle
- [ ] Document technical details and root cause
### Assessment Summary
- **Severity Level**: `Critical|High|Medium|Low`
- **CVSS Score**: `X.X`
- **Affects versions**: `X.Y.Z to X.Y.Z`
- **Root cause**: Brief technical explanation
- **Introduced in commit/version**: `commit-hash` or `vX.Y.Z`
- **Attack vector**: `Network|Local|Physical`
- **Estimated timeline for fix**: `X days/weeks`
## Phase 2: Immediate Response & Mitigation
### Updates
<< Document immediate actions taken and mitigation strategies >>
Example:
Working on hotfix for version X.Y.Z. Temporary workaround available by disabling [feature] in configuration.
### Tasks
- [ ] Implement immediate workaround if possible
- [ ] Update security advisory draft
- [ ] Prepare patch/hotfix
- [ ] Test fix thoroughly in development environment
- [ ] Prepare updated Docker images and binaries
- [ ] Draft security advisory for GitHub Security Advisories
- [ ] Consider if coordinated disclosure timeline needs adjustment
### Mitigation Details
- **Workaround available**: `Yes|No` - If yes, describe briefly
- **Fix implemented on**: `YYYY-MM-DD`
- **Patch/hotfix version**: `vX.Y.Z`
- **GitHub Security Advisory ID**: `GHSA-XXXX-XXXX-XXXX`
## Phase 3: Impact Assessment & User Analysis
### Updates
<< Analysis of potential impact on the Stalwart deployments >>
Based on telemetry data and version statistics, approximately X installations may be affected.
### Tasks
- [ ] Analyze version adoption from update checks (if available)
- [ ] Estimate number of vulnerable installations
- [ ] Assess if default configurations are vulnerable
- [ ] Review if vulnerability has been exploited (check logs, reports)
- [ ] Determine if any user data may have been compromised
- [ ] Check for indicators of active exploitation in the wild
### Analysis Notes
_Document your impact assessment process and findings_
### Impact Summary
- **Estimated vulnerable installations**: `~X out of Y`
- **Default configuration vulnerable**: `Yes|No`
- **Evidence of exploitation**: `Found|Not found|Unknown`
- **User data potentially at risk**: `Email content|Credentials|Configuration|None`
- **Confidence in assessment**: `High|Medium|Low`
## Phase 4: Communication & Release
### Updates
<< Communication strategy and release timeline >>
Security release vX.Y.Z will be published on YYYY-MM-DD with coordinated disclosure.
### Tasks
**Pre-release preparation:**
- [ ] Finalize security patch
- [ ] Prepare release notes with security details
- [ ] Update documentation if needed
- [ ] Test automated update mechanisms
- [ ] Prepare GitHub Security Advisory
**Communication channels:**
- [ ] Draft announcement for Stalwart community forum/Discord
- [ ] Prepare release announcement for GitHub
- [ ] Draft security advisory content
- [ ] Consider notification to major distributors/packagers
**Release execution:**
- [ ] Publish patched version to GitHub releases
- [ ] Update Docker images on Docker Hub
- [ ] Publish GitHub Security Advisory
- [ ] Post to community channels (Discord/forum)
- [ ] Update project website/documentation
- [ ] Submit CVE request if warranted (CVSS ≥ 4.0)
**Post-release:**
- [ ] Monitor community channels for questions
- [ ] Track adoption of security update
- [ ] Follow up on any additional reports
- [ ] Document lessons learned
### Communication Record
- **Security release published**: `YYYY-MM-DD HH:MM UTC`
- **GitHub Security Advisory**: `GHSA-XXXX-XXXX-XXXX`
- **CVE ID** (if applicable): `CVE-YYYY-XXXXX`
- **Community announcement**: [Link to forum/Discord post]
- **Estimated time to 50% adoption**: `X days/weeks`
## Post-Incident Review
### What went well?
-
### What could be improved?
-
### Action items for future incidents:
- [ ]
- [ ]
- [ ]
### Process improvements:
- [ ]
- [ ]
## Emergency Contacts
- **Primary maintainer**: hello@stalw.art
================================================
FILE: SECURITY_TEMPLATE.md
================================================
# Stalwart Security Advisory
**CVE ID:** CVE-YYYY-NNNNN
**Publication Date:** YYYY-MM-DD
**Last Updated:** YYYY-MM-DD
## Summary
[Provide a brief, non-technical summary of the vulnerability in 1-2 sentences]
## Affected Products and Versions
**Product:** Stalwart Mail and Collaboration Server
**Affected Versions:**
- Version X.X.X through Y.Y.Y
- [List specific affected version ranges]
**Fixed Versions:**
- Version Z.Z.Z and later
- [List all versions that include the fix]
## Vulnerability Details
### Description
[Detailed technical description of the vulnerability, including how it can be exploited]
### Impact
[Describe the potential impact if this vulnerability is exploited]
### CVSS Score
**CVSS v3.1 Base Score:** X.X ([SEVERITY])
**Vector String:** CVSS:3.1/AV:X/AC:X/PR:X/UI:X/S:X/C:X/I:X/A:X
**Severity Breakdown:**
- **Attack Vector:** [Network/Adjacent/Local/Physical]
- **Attack Complexity:** [Low/High]
- **Privileges Required:** [None/Low/High]
- **User Interaction:** [None/Required]
- **Scope:** [Unchanged/Changed]
- **Confidentiality Impact:** [None/Low/High]
- **Integrity Impact:** [None/Low/High]
- **Availability Impact:** [None/Low/High]
### CWE Classification
**CWE-XXX:** [Weakness Name]
## Technical Details
### Root Cause
[Explain the underlying cause of the vulnerability]
### Attack Scenario
[Describe a realistic attack scenario or proof of concept, without providing exploit code]
### Prerequisites
[List any conditions that must be met for successful exploitation]
## Remediation
### Recommended Actions
1. **Immediate:** Upgrade to version Z.Z.Z or later
2. **Short-term:** [Any temporary mitigation measures]
3. **Long-term:** [Any additional security hardening recommendations]
### Upgrade Instructions
```bash
# Example upgrade commands
[Provide specific upgrade instructions for Stalwart]
```
### Workarounds
[If applicable, describe any temporary workarounds for systems that cannot be immediately upgraded]
**Note:** Workarounds are temporary measures and do not fully resolve the vulnerability. Upgrading is strongly recommended.
## Detection
### Indicators of Compromise
[List any logs, patterns, or indicators that may suggest exploitation attempts]
### Log Entries
```
[Example log entries that administrators should look for]
```
## Timeline
- **YYYY-MM-DD:** Vulnerability discovered [by researcher/team name]
- **YYYY-MM-DD:** Vendor notified
- **YYYY-MM-DD:** Vendor acknowledged issue
- **YYYY-MM-DD:** Fix developed and tested
- **YYYY-MM-DD:** Fixed version released
- **YYYY-MM-DD:** Public disclosure
## Credits
This vulnerability was discovered by [Researcher Name / Organization].
## References
- Stalwart Mail Server: https://stalw.art/
- CVE Entry: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-YYYY-NNNNN
- GitHub Advisory: [Link to GitHub Security Advisory if applicable]
- Release Notes: [Link to release notes with fix]
## Contact Information
For questions or concerns regarding this advisory, please contact:
**Security Team:** hello@stalw.art
**Website:** https://stalw.art
To report security vulnerabilities in Stalwart, please follow our [responsible disclosure policy](https://github.com/stalwartlabs/stalwart/security/policy).
## Disclaimer
This advisory is provided "as is" without warranty of any kind. The information contained in this advisory is subject to change without notice.
---
**Document Version:** 1.0
**Classification:** Public
================================================
FILE: UPGRADING/v0_04.md
================================================
# Upgrading from `v0.4.0` to `v0.4.x`
- Replace the binary with the new version.
- Restart the service.
# Upgrading from `v0.3.x` to `v0.4.0`
## What's changed
- **Configuration File Split:** While the `config.toml` configuration file format hasn't changed much, the new version has divided it into multiple sub-files. These sub-files are now included from the new `config.toml`. This division was implemented because the config file had grown significantly, and splitting it improves organization.
- **Changes in the Sieve Interpreter Attribute Names:**
- The configuration key prefix `jmap.sieve` (JMAP Sieve Interpreter) has been renamed to `sieve.untrusted`.
- The configuration key prefix `sieve` (SMTP Sieve Interpreter) has been renamed to `sieve.trusted`.
## What's been added
- **SPAM Filter Module:** The most notable addition in this version is the SPAM filter module. It comprises:
- A TOML configuration file located at `etc/smtp/spamfilter.toml`.
- A set of Sieve scripts in `etc/spamfilter/scripts`.
- Lookup maps in `etc/spamfilter/maps`.
- **New Configuration Key:** A new key `resolver.public-suffix` has been added. This specifies the URL of the list of public suffixes.
## Migration Steps
1. **Backup:** Ensure you have a backup of your current `config.toml` file.
2. **Download Configuration Bundle:** Fetch the new configuration bundle from [this link](https://get.stalw.art/resources/config.zip). Unpack it under `BASE_DIR/etc` (for example `/opt/stalwart-mail/etc`).
3. **Update Configuration Files:** Modify the following files with your domain name, host name, certificate paths, DKIM signatures, and so on:
- `etc/config.toml`
- `etc/jmap/store.toml`
- `etc/jmap/oauth.toml`
- `etc/smtp/signature.toml`
- `etc/common/tls.toml`
4. **Adjust included files:** If you are using an LDAP directory for authentication, edit `etc/config.toml` and replace the `etc/directory/sql.toml` include with `etc/directory/ldap.toml`.
5. **Configure the SPAM Filter Database:** Set up and configure the SPAM filter database. More details can be found [here](https://stalw.art/docs/spamfilter/settings/database).
6. **Review All TOML Files:** Navigate to every TOML file under the `etc/` directory and make necessary changes.
7. **Update Binary:** Download and substitute the v0.4.0 binary suitable for your platform from [here](https://github.com/stalwartlabs/mail-server/releases/tag/v0.4.0).
8. **Restart Service:** Conclude by restarting the Stalwart service.
### Alternative Method:
1. **Separate Installation:** Install v0.4.0 in a distinct directory. This will auto-update all configuration files and establish the spam filter database in SQLite format.
2. **Move Configuration Files:** Transfer the configuration files from `etc/` and the SQLite spam filter database from `data/` to your current installation's directory.
3. **Replace Binary:** Move the binary from the `bin/` directory to your current installation's `data/` directory.
4. **Restart Service:** Finally, restart the Stalwart service.
We apologize for the lack of an automated migration tool for this upgrade. However, we are planning on introducing an automated migration tool in the near future. Thank you for your understanding and patience.
================================================
FILE: UPGRADING/v0_05.md
================================================
# Upgrading from `v0.5.2` to `v0.5.3`
- The following configuration attributes have been renamed, see [store.toml](https://github.com/stalwartlabs/mail-server/blob/main/resources/config/common/store.toml) for an example:
- `jmap.store.data` -> `storage.data`
- `jmap.store.fts` -> `storage.fts`
- `jmap.store.blob` -> `storage.blob`
- `jmap.encryption.*` -> `storage.encryption.*`
- `jmap.spam.header` -> `storage.spam.header`
- `jmap.fts.default-language` -> `storage.fts.default-language`
- `jmap.cluster.node-id` -> `storage.cluster.node-id`
- `management.directory` and `sieve.trusted.default.directory` -> `storage.directory`
- `sieve.trusted.default.store` -> `storage.lookup`
- Proxy networks are now configured under `server.proxy.trusted-networks` rather than `server.proxy-trusted-networks`. IP addresses/masks have to be defined within a set (`{}`) rather than a list (`[]`), see [server.toml](https://github.com/stalwartlabs/mail-server/blob/main/resources/config/common/server.toml) for an example.
# Upgrading from `v0.5.1` to `v0.5.2`
- Make sure that implicit TLS is enabled for the JMAP [listener](https://stalw.art/docs/server/listener) configured under `ets/jmap/listener.toml`:
```toml
[server.listener."jmap".tls]
implicit = true
```
- Optional: Enable automatic TLS with [ACME](https://stalw.art/docs/server/tls/acme).
- Replace the binary with the new version.
- Restart the service.
# Upgrading from `v0.5.0` to `v0.5.1`
- Replace the binary with the new version.
- Restart the service.
# Upgrading from `v0.4.x` to `v0.5.0`
## What's changed
- **Database Layout**: Version 0.5.0 utilizes a different database layout which is more efficient and allows multiple backends to be supported. For this reason, the database must be migrated to the new layout.
- **Configuration file changes**: The configuration file has been updated to support multiple stores, most configuration attributes starting with `store.*` and `directory.*` need to be reviewed.
- **SPAM filter**: Sieve scripts that interact with databases need to be updated. The functions `lookup` and `lookup_map` has been renamed to `key_exists` and `key_get`. It is recommended to replace all scripts with the new versions rather than updating them manually. Additionally, the SPAM database no longer requires an SQL server, it can now be stored in Redis or any of the supported databases.
- **Directory superusers**: Due to problems and confusion with the `superuser-group` attribute, the concept of a superuser group has been removed. Instead, a new attribute `type` has been added to external directories. The value of this attribute can be `individual`, `group` or `admin`. The `admin` type is equivalent to the old superuser group. The `type` attribute is required for all principals in the directory, it defaults to `individual` if not specified.
- **Purge schedules**: The attributes `jmap.purge.schedule.db` and `jmap.purge.schedule.blobs` have been removed. Instead, the purge frequency is now specified per store in `store.<name>.purge.frequency`. The attribute `jmap.purge.schedule.sessions` has been renamed to `jmap.purge.sessions.frequency`.
## What's been added
- **Multiple stores**: The server now supports multiple stores to be defined in the configuration file under `store.<name>`. Which store to use is defined in the `jmap.store.data`, `jmap.store.fts` and `jmap.store.blob` settings.
- **More backend options**: It is now possible to use `RocksDB`, `PostgreSQL` and `MySQL` as data stores. It is also now possible to store blobs in any of the supported databases instead of being limited to the filesystem or an S3-compatible storage. Full-text indexing can now be done using `Elasticsearch` and the Spam database stored in `Redis`.
- **Internal Directory**: The server now has an internal directory that can be used to store user accounts, passwords and group membership. This directory can be used instead of an external directory such as LDAP or SQL.
- **New settings**: When running Stalwart in a cluster, `jmap.cluster.node-id` allows to specify a unique identifier for each node. Messages containing the SPAM headers defined in `jmap.spam.header` are moved automatically to the user's Junk Mail folder.
- **Default Sieve stores**: For Sieve scripts such as the Spam filter that require access to a directory and a lookup store, it is now possible to configure the default lookup store and directory using the `sieve.trusted.default.directory` and `sieve.trusted.default.store` settings.
## Migration Steps
Rather than manually updating the configuration file, it is recommended to start with a fresh configuration file and update it with the necessary settings:
- Install `v0.5.0` in a distinct directory. You now have the option to use an [internal directory](https://stalw.art/docs/directory/types/internal), which will allow you to manage users and groups directly from Stalwart server. Alternatively, you can continue to use an external directory such as LDAP or SQL.
- Update the configuration files with your previous settings. All configuration attributes are backward compatible, except those starting with `store.*`, `directory.*` and `jmap.purge.*`.
- Export each account following the procedure described in the [migration guide](https://stalw.art/docs/management/database/migrate).
- Stop the old `v0.4.x` server.
- If there are messages pending to be delivered in the SMTP queue, move the `queue` directory to the new installation.
- Start the new `v0.5.0` server.
- Import each account following the procedure described in the [migration guide](https://stalw.art/docs/management/database/migrate).
Once again, we apologize for the lack of an automated migration tool for this upgrade. However, we are planning on introducing an automated migration tool once the web-admin is released in Q1 2024. Thank you for your understanding and patience.
================================================
FILE: UPGRADING/v0_06.md
================================================
# Upgrading from `v0.5.3` to `v0.6.0`
- In order to support [expressions](https://stalw.art/docs/configuration/expressions/overview), version `0.6.0` introduces multiple breaking changes in the SMTP server configuration file. It is recommended to download the new SMTP configuration files from the [repository](https://github.com/stalwartlabs/mail-server/tree/main/resources/config/smtp), make any necessary changes and replace the old files under `INSTALL_DIR/etc/smtp` with the new ones.
- If you are using custom subaddressing of catch-all rules, you'll need to replace these rules with expressions. Check out the updated [syntax](https://stalw.art/docs/directory/addresses).
- Message queues are now distributed and stored in the backend specified by the `storage.data` and `storage.blob` settings. Make sure to flush your SMTP message queue before upgrading to `0.6.0` to avoid losing any outgoing messages pending delivery.
- Replace the binary with the new version.
- Restart the service.
================================================
FILE: UPGRADING/v0_07.md
================================================
# Upgrading from `v0.6.0` to `v0.7.0`
Version `0.7.0` of Stalwart introduces significant improvements and features that enhance performance and functionality. However, it also comes with multiple breaking changes in the configuration files and a revamped database layout optimized for accessing large mailboxes. Additionally, Stalwart now supports compression for binaries stored in the blob store, further increasing efficiency.
Due to these extensive changes, the recommended approach for upgrading is to perform a clean reinstallation of Stalwart and manually migrate your accounts to the new version.
## Pre-Upgrade Steps
- Download the `v0.7.0` mail-server and CLI binaries for your platform from the [releases page](https://github.com/stalwartlabs/mail-server/releases/latest/).
- Initialize the setup on a distinct directory using the command `sudo ./stalwart-mail --init /path/to/new-install`. This command will print the administrator password required to access the web-admin.
- Create the `bin` directory using `mkdir /path/to/new-install/bin`.
- Move the downloaded binaries to the `bin` directory using the command `mv stalwart-mail stalwart-cli /path/to/new-install/bin`.
- Open `/path/to/new-install/etc/config.toml` in a text editor and comment out all listeners except the HTTP listener for port `8080`.
- Start the new installation from the terminal using the command `sudo /path/to/new-install/bin/stalwart-mail --config /path/to/new-install/etc/config.toml`.
- Point your browser to the web-admin at `http://yourserver.org:8080` and login using the auto-generated administrator password.
- Configure the new installation with your domain, hostname, certificates, and other settings following the instructions at [stalw.art/docs/get-started](https://stalw.art/docs/get-started). Ignore the part about using the installation script, we are performing a manual installation.
- Add your user accounts.
- Configure Stalwart to run as the `stalwart-mail` user and `stalwart-mail` group from `Settings` > `Server` > `System`. This is not necessary if you are using Docker.
- Stop the new installation by pressing `Ctrl+C` in the terminal.
## Upgrade Steps
- On your `v0.6.0` installation, open in a text editor the `smtp/listener.toml`, `imap/listener.toml` files and comment out all listeners except the JMAP/HTTP listener (we are going to need it to export the user accounts) and then restart the service.
- If you are using an external store, backup the database using the appropriate method for your database system.
- Create the `~/exports` directory, here we will store the exported accounts.
- Using the existing CLI tool (not the one you just downloaded as it is not compatible), export each user account using the command `./stalwart-cli -u https://your-old-server.org -c <ADMIN_PASSWORD> export account <ACCOUNT_NAME> ~/exports`.
- Stop the `v0.6.0` installation using the command `sudo systemctl stop stalwart-mail`.
- Move the old `v0.6.0` installation to a backup directory, for example `mv /opt/stalwart-mail /opt/stalwart-mail-backup`.
- Move the new `v0.7.0` installation to the old installation directory, for example `mv /path/to/new-install /opt/stalwart-mail`.
- Set the right permissions for the new installation using the command `sudo chown -R stalwart-mail:stalwart-mail /opt/stalwart-mail`.
- Start the new installation using the command `sudo systemctl start stalwart-mail`.
- Import the accounts using the new CLI tool with the command `./stalwart-cli -u http://yourserver.org:8080 -c <ADMIN_PASSWORD> import account <ACCOUNT> ~/exports/<ACCOUNT>`.
- Using the admin tool, reactivate all the necessary listener (SMTP, IMAP, etc.)
- Restart the service using the command `sudo systemctl restart stalwart-mail`.
We apologize for the complexity of the upgrade process associated with this version of Stalwart. We understand the challenges and inconveniences that the requirement for a clean reinstallation and manual account migration poses. Moving forward, an automated migration tool will be included in any future releases that necessitate changes to the database layout, aiming to streamline the upgrade process for you. Furthermore, as we approach the milestone of version 1.0.0, we anticipate that such foundational changes will become increasingly infrequent, leading to more straightforward updates. We appreciate your patience and commitment to Stalwart during this upgrade.
================================================
FILE: UPGRADING/v0_08.md
================================================
# Upgrading from `v0.7.3` to `v0.8.0`
Version `0.8.0` includes both performance and security enhancements that require your data to be migrated to a new database layout. Luckily version `0.7.3` includes a migration tool which should make this process much easier than previous upgrades. In addition to the new layout, you will have to change the systemd service file to use the `CAP_NET_BIND_SERVICE` capability.
## Preparation
- Upgrade to version `0.7.3` if you haven't already. If you are on a version previous to `0.7.0`, you will have to do a manual migration of your data using the Command-line Interface.
- Create a directory where your data will be exported to, for example `/opt/stalwart-mail/export`.
## Systemd service upgrade (Linux only)
- Stop the `v0.7.3` installation:
```bash
$ sudo systemctl stop stalwart-mail
```
- Update your systemd file to include the `CAP_NET_BIND_SERVICE` capability. Open the file `/etc/systemd/system/stalwart-mail.service` in a text editor and add the following lines under the `[Service]` section:
```
User=stalwart-mail
Group=stalwart-mail
AmbientCapabilities=CAP_NET_BIND_SERVICE
```
- Reload the daemon:
```bash
$ systemctl daemon-reload
```
- Do not start the service yet.
## Data migration
- Stop Stalwart and export your data:
```bash
$ sudo systemctl stop stalwart-mail
$ sudo /opt/stalwart-mail/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
$ sudo chown -R stalwart-mail:stalwart-mail /opt/stalwart-mail/export
```
or, if you are using the Docker image:
```bash
$ docker stop stalwart-mail
$ docker run --rm -v <STALWART_DIR>:/opt/stalwart-mail -it stalwart-mail /opt/stalwart-mail/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
```
- Backup your `v0.7.3` installation:
- If you are using RocksDB or SQLite, simply rename the `data` directory to `data-backup`, for example:
```bash
$ mv /opt/stalwart-mail/data /opt/stalwart-mail/data-backup
$ mkdir /opt/stalwart-mail/data
$ chown stalwart-mail:stalwart-mail /opt/stalwart-mail/data
```
- If you are using PostgreSQL, rename the database and create a blank database with the same name, for example:
```sql
ALTER DATABASE stalwart RENAME TO stalwart_old;
CREATE database stalwart;
```
- If you are using MySQL, rename the database and create a blank database with the same name, for example:
```sql
CREATE DATABASE stalwart_old;
RENAME TABLE stalwart.b TO stalwart_old.b;
RENAME TABLE stalwart.v TO stalwart_old.v;
RENAME TABLE stalwart.l TO stalwart_old.l;
RENAME TABLE stalwart.i TO stalwart_old.i;
RENAME TABLE stalwart.t TO stalwart_old.t;
RENAME TABLE stalwart.c TO stalwart_old.c;
DROP DATABASE stalwart;
CREATE database stalwart;
```
- If you are using FoundationDB, backup your database and clean the entire key range.
- Download the `v0.8.0` mail-server for your platform from the [releases page](https://github.com/stalwartlabs/mail-server/releases/latest/) and replace the binary in `/opt/stalwart-mail/bin`. If you are using the Docker image, pull the latest image.
- Import your data:
```bash
$ sudo -u stalwart-mail /opt/stalwart-mail/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --import /opt/stalwart-mail/export
```
or, if you are using the Docker image:
```bash
$ docker run --rm -v <STALWART_DIR>:/opt/stalwart-mail -it stalwart-mail /opt/stalwart-mail/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --import /opt/stalwart-mail/export
```
- Start the service:
```bash
$ sudo systemctl start stalwart-mail
```
Or, if you are using the Docker image:
```bash
$ docker start stalwart-mail
```
================================================
FILE: UPGRADING/v0_09.md
================================================
# Upgrading from `v0.8.x` to `v0.9.0`
Version `0.9.0` introduces significant internal improvements while maintaining compatibility with existing database layouts and configuration file formats from version `0.8.0`. As a result, no data or configuration migration is necessary. This release focuses on enhancing performance and functionality, particularly in logging and tracing capabilities.
To upgrade to Stalwart version `0.9.0` from `0.8.x`, begin by downloading the latest version of the `stalwart-mail` binary. Once downloaded, replace the existing binary with the new version. Additionally, it's important to update the WebAdmin interface to the latest version to ensure compatibility and to access new features introduced in this release.
In terms of breaking changes, this release brings significant updates to webhooks. All webhook event names have been modified, requiring a thorough review and adjustment of existing webhook configurations. Furthermore, the update introduces hundreds of new event types, enhancing the granularity and specificity of event handling capabilities. Users should familiarize themselves with these changes to effectively integrate them into their systems.
The reason for this release being classified as a major version, despite the absence of changes to the database or configuration formats, is the complete rewrite of the logging and tracing layer. This overhaul substantially improves the efficiency and speed of generating detailed tracing and logging events, making the system more robust and facilitating easier debugging and monitoring.
================================================
FILE: UPGRADING/v0_10.md
================================================
# Upgrading from `v0.9.x` to `v0.10.0`
## Important Notes
- In version `0.10.0` accounts are associated with roles and permissions, which define what resources they can access. The concept of administrator or super user accounts no longer exists, now there is a single account type (the `individual` principal) which can be assigned the `admin` role or custom permissions to have administrator access.
- Due to the changes in the database layout in order to support roles and permissions, the database must be migrated to the new layout. The migration is automatic and should not require any manual intervention.
- While the database migration is automatic, it's recommended to **back up your data** before upgrading.
- The webadmin must be upgraded **before** the mail server to maintain access post-upgrade. This is true even if you run Stalwart in Docker.
## Step-by-Step Upgrade Process
- Upgrade the webadmin by clicking on `Manage` > `Maintenance` > `Update Webadmin`.
- Stop Stalwart and backup your data:
```bash
$ sudo systemctl stop stalwart-mail
$ sudo /opt/stalwart-mail/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
$ sudo chown -R stalwart-mail:stalwart-mail /opt/stalwart-mail/export
```
or, if you are using the Docker image:
```bash
$ docker stop stalwart-mail
$ docker run --rm -v <STALWART_DIR>:/opt/stalwart-mail -it stalwart-mail /usr/local/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
```
- Download the `v0.10.0` mail-server for your platform from the [releases page](https://github.com/stalwartlabs/mail-server/releases/latest/) and replace the binary in `/opt/stalwart-mail/bin`. If you are using the Docker image, pull the latest image.
- Start the service:
```bash
$ sudo systemctl start stalwart-mail
```
Or, if you are using the Docker image:
```bash
$ docker start stalwart-mail
```
================================================
FILE: UPGRADING/v0_11.md
================================================
# Upgrading from `v0.10.x` to `v0.11.0`
Version `0.11.0` introduces breaking changes to the spam filter configuration. Although no data migration is required, if changes were made to the previous spam filter, the configuration of the new spam filter should be reviewed. In particular:
- `lookup.spam-*` settings are no longer used, these have been replaced by `spam-filter.*` settings. Review the [updated documentation](http://stalw.art/docs/spamfilter/overview).
- Previous `spam-filter` and `track-replies` Sieve scripts cannot be used with the new version. They have been replaced by a built-in spam filter written in Rust.
- Cache settings have changed, see the [documentation](https://stalw.art/docs/server/cache) for details.
- Support for Pipes was removed in favor of MTA hooks and Milter.
- `config.resource.spam-filter` is now `spam-filter.resource`.
- `config.resource.webadmin` is now `webadmin.resource`.
- `authentication.rate-limit` was removed as security is handled by fail2ban.
================================================
FILE: UPGRADING/v0_12.md
================================================
# Upgrading from `v0.11.x` to `v0.12.x`
## Important Notes
Version `0.12.x` introduces significant improvements such as zero-copy deserialization which make the new database layout incompatible with the previous version. As a result, the database must be migrated to the new layout. The migration is done automatically on startup and should not require any manual intervention. However, it is highly recommended to **back up your data** before upgrading since it is not possible to downgrade the database once it has been migrated. You may also want to run a mock migration before upgrading to ensure that everything works as expected.
In addition to the database layout changes, multiple settings were renamed:
- `server.http.*` to `http.*`.
- `jmap.folders.*` to `email.folders.*`.
- `jmap.account.purge.frequency` to `account.purge.frequency`.
- `jmap.email.auto-expunge` to `email.auto-expunge`.
- `jmap.protocol.changes.max-history` to `changes.max-history`.
- `storage.encryption.*` to `email.encryption.*`.
## Step-by-Step Upgrade Process
- Stop Stalwart in **every single node of your cluster**. If you are using the systemd service, you can do this with the following command:
```bash
$ sudo systemctl stop stalwart-mail
```
- Backup your data following your database system's instructions. For example, if you are using RocksDB or SQLite, you can simply copy the `data` directory to a backup location. If you are using PostgreSQL or MySQL, you can use the `pg_dump` or `mysqldump` commands to create a backup of your database. If your database does not support backups, you can use the [built-in migration utility](https://stalw.art/docs/management/migration) to export your data to a file. For example:
```bash
$ sudo /opt/stalwart-mail/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
$ sudo chown -R stalwart-mail:stalwart-mail /opt/stalwart-mail/export
```
- Download the `v0.12.x` binary for your platform (which is now called `stalwart` rather than `mail-server`) from the [releases page](https://github.com/stalwartlabs/stalwart/releases/latest/) and replace the binary in `/opt/stalwart-mail/bin`. If you rename the binary from `stalwart` to `stalwart-mail`, you can keep the same systemd service file, otherwise you will need to update the service file to point to the new binary name.
- Start the service. In a cluster, you can speed up the migration process by starting all nodes at once.
```bash
$ sudo systemctl start stalwart-mail
```
- Upgrade the webadmin by clicking on `Manage` > `Maintenance` > `Update Webadmin`.
## Step-by-Step Upgrade Process (Docker)
- Stop the Stalwart container in **every single node of your cluster**. If you are using Docker, you can do this with the following command:
```bash
$ docker stop stalwart-mail
```
- Backup your data following your database system's instructions. For example, if you are using RocksDB or SQLite, you can simply copy the `data` directory to a backup location. If you are using PostgreSQL or MySQL, you can use the `pg_dump` or `mysqldump` commands to create a backup of your database. If your database does not support backups, you can use the `--export` command to export your data to a file. For example:
```bash
$ docker run --rm -v <STALWART_DIR>:/opt/stalwart-mail -it stalwart-mail /usr/local/bin/stalwart-mail --config /opt/stalwart-mail/etc/config.toml --export /opt/stalwart-mail/export
```
- The Docker image location has now changed to `stalwartlabs/stalwart` instead of `stalwartlabs/mail-server`. Pull the latest image and configure it to use your existing data directory:
```bash
$ docker run -d -ti -p 443:443 -p 8080:8080 \
-p 25:25 -p 587:587 -p 465:465 \
-p 143:143 -p 993:993 -p 4190:4190 \
-p 110:110 -p 995:995 \
-v <STALWART_DIR>:/opt/stalwart \
--name stalwart stalwartlabs/stalwart:latest
```
- Since the mount point has changed from `/opt/stalwart-mail` to `/opt/stalwart`, you will need to update your Stalwart's configuration file to reflect this change. Open the file `/opt/stalwart/etc/config.toml` and update the paths accordingly.
- Upgrade the webadmin by clicking on `Manage` > `Maintenance` > `Update Webadmin`.
================================================
FILE: UPGRADING/v0_13.md
================================================
# Upgrading from `v0.12.x` (and `v0.11.x`) to `v0.13.x`
## Important Notes
Version `0.13.x` introduces a significant redesign of the MTA’s delivery and queueing subsystem. This includes a transition to a new message queue serialization format and a move to a strategy-based configuration model for routing, scheduling, and delivery control. Upon first launch of version `0.13.0`, any messages currently in the
gitextract_l0u7gilb/
├── .dockerignore
├── .editorconfig
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── issue-triage.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── config.yml
│ │ └── confirmed_issue.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yml
│ ├── scorecard.yml
│ ├── test.yml
│ └── trivy.yml
├── .gitignore
├── CHANGELOG.md
├── CNAME
├── CONTRIBUTING.md
├── Cargo.toml
├── Dockerfile
├── Dockerfile.build
├── LICENSES/
│ ├── AGPL-3.0-only.txt
│ └── LicenseRef-SEL.txt
├── README.md
├── SECURITY.md
├── SECURITY_PROCESS.md
├── SECURITY_TEMPLATE.md
├── UPGRADING/
│ ├── v0_04.md
│ ├── v0_05.md
│ ├── v0_06.md
│ ├── v0_07.md
│ ├── v0_08.md
│ ├── v0_09.md
│ ├── v0_10.md
│ ├── v0_11.md
│ ├── v0_12.md
│ ├── v0_13.md
│ ├── v0_14.md
│ └── v0_15.md
├── api/
│ └── v1/
│ └── openapi.yml
├── crates/
│ ├── cli/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── main.rs
│ │ └── modules/
│ │ ├── account.rs
│ │ ├── cli.rs
│ │ ├── database.rs
│ │ ├── dkim.rs
│ │ ├── domain.rs
│ │ ├── export.rs
│ │ ├── group.rs
│ │ ├── import.rs
│ │ ├── list.rs
│ │ ├── mod.rs
│ │ ├── queue.rs
│ │ └── report.rs
│ ├── common/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/
│ │ ├── addresses.rs
│ │ ├── auth/
│ │ │ ├── access_token.rs
│ │ │ ├── mod.rs
│ │ │ ├── oauth/
│ │ │ │ ├── config.rs
│ │ │ │ ├── crypto.rs
│ │ │ │ ├── introspect.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── oidc.rs
│ │ │ │ ├── registration.rs
│ │ │ │ └── token.rs
│ │ │ ├── rate_limit.rs
│ │ │ ├── roles.rs
│ │ │ └── sasl.rs
│ │ ├── config/
│ │ │ ├── groupware.rs
│ │ │ ├── imap.rs
│ │ │ ├── inner.rs
│ │ │ ├── jmap/
│ │ │ │ ├── capabilities.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── settings.rs
│ │ │ ├── mod.rs
│ │ │ ├── network.rs
│ │ │ ├── scripts.rs
│ │ │ ├── server/
│ │ │ │ ├── listener.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── tls.rs
│ │ │ ├── smtp/
│ │ │ │ ├── auth.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── queue.rs
│ │ │ │ ├── report.rs
│ │ │ │ ├── resolver.rs
│ │ │ │ ├── session.rs
│ │ │ │ └── throttle.rs
│ │ │ ├── spamfilter.rs
│ │ │ ├── storage.rs
│ │ │ └── telemetry.rs
│ │ ├── core.rs
│ │ ├── dns.rs
│ │ ├── enterprise/
│ │ │ ├── alerts.rs
│ │ │ ├── config.rs
│ │ │ ├── license.rs
│ │ │ ├── llm.rs
│ │ │ ├── mod.rs
│ │ │ └── undelete.rs
│ │ ├── expr/
│ │ │ ├── eval.rs
│ │ │ ├── functions/
│ │ │ │ ├── array.rs
│ │ │ │ ├── asynch.rs
│ │ │ │ ├── email.rs
│ │ │ │ ├── misc.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── text.rs
│ │ │ ├── if_block.rs
│ │ │ ├── mod.rs
│ │ │ ├── parser.rs
│ │ │ └── tokenizer.rs
│ │ ├── i18n.rs
│ │ ├── ipc.rs
│ │ ├── lib.rs
│ │ ├── listener/
│ │ │ ├── acme/
│ │ │ │ ├── cache.rs
│ │ │ │ ├── directory.rs
│ │ │ │ ├── jose.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── order.rs
│ │ │ │ └── resolver.rs
│ │ │ ├── asn.rs
│ │ │ ├── blocked.rs
│ │ │ ├── limiter.rs
│ │ │ ├── listen.rs
│ │ │ ├── mod.rs
│ │ │ ├── stream.rs
│ │ │ └── tls.rs
│ │ ├── manager/
│ │ │ ├── backup.rs
│ │ │ ├── boot.rs
│ │ │ ├── config.rs
│ │ │ ├── console.rs
│ │ │ ├── mod.rs
│ │ │ ├── reload.rs
│ │ │ ├── restore.rs
│ │ │ └── webadmin.rs
│ │ ├── scripts/
│ │ │ ├── functions/
│ │ │ │ ├── array.rs
│ │ │ │ ├── email.rs
│ │ │ │ ├── header.rs
│ │ │ │ ├── image.rs
│ │ │ │ ├── misc.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── text.rs
│ │ │ │ ├── unicode.rs
│ │ │ │ └── url.rs
│ │ │ ├── mod.rs
│ │ │ └── plugins/
│ │ │ ├── dns.rs
│ │ │ ├── exec.rs
│ │ │ ├── headers.rs
│ │ │ ├── http.rs
│ │ │ ├── llm_prompt.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── text.rs
│ │ ├── sharing/
│ │ │ ├── acl.rs
│ │ │ ├── mod.rs
│ │ │ ├── notification.rs
│ │ │ └── resources.rs
│ │ ├── storage/
│ │ │ ├── blob.rs
│ │ │ ├── index.rs
│ │ │ ├── mod.rs
│ │ │ └── state.rs
│ │ └── telemetry/
│ │ ├── metrics/
│ │ │ ├── mod.rs
│ │ │ ├── otel.rs
│ │ │ ├── prometheus.rs
│ │ │ └── store.rs
│ │ ├── mod.rs
│ │ ├── tracers/
│ │ │ ├── journald.rs
│ │ │ ├── log.rs
│ │ │ ├── mod.rs
│ │ │ ├── otel.rs
│ │ │ ├── stdout.rs
│ │ │ └── store.rs
│ │ └── webhooks/
│ │ └── mod.rs
│ ├── dav/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── calendar/
│ │ │ ├── copy_move.rs
│ │ │ ├── delete.rs
│ │ │ ├── freebusy.rs
│ │ │ ├── get.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── proppatch.rs
│ │ │ ├── query.rs
│ │ │ ├── scheduling.rs
│ │ │ └── update.rs
│ │ ├── card/
│ │ │ ├── copy_move.rs
│ │ │ ├── delete.rs
│ │ │ ├── get.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── proppatch.rs
│ │ │ ├── query.rs
│ │ │ └── update.rs
│ │ ├── common/
│ │ │ ├── acl.rs
│ │ │ ├── lock.rs
│ │ │ ├── mod.rs
│ │ │ ├── propfind.rs
│ │ │ └── uri.rs
│ │ ├── file/
│ │ │ ├── copy_move.rs
│ │ │ ├── delete.rs
│ │ │ ├── get.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── proppatch.rs
│ │ │ └── update.rs
│ │ ├── lib.rs
│ │ ├── principal/
│ │ │ ├── matching.rs
│ │ │ ├── mod.rs
│ │ │ ├── propfind.rs
│ │ │ └── propsearch.rs
│ │ └── request.rs
│ ├── dav-proto/
│ │ ├── Cargo.toml
│ │ ├── resources/
│ │ │ ├── requests/
│ │ │ │ ├── acl-001.json
│ │ │ │ ├── acl-001.xml
│ │ │ │ ├── acl-002.json
│ │ │ │ ├── acl-002.xml
│ │ │ │ ├── acl-003.json
│ │ │ │ ├── acl-003.xml
│ │ │ │ ├── acl-004.json
│ │ │ │ ├── acl-004.xml
│ │ │ │ ├── lockinfo-001.json
│ │ │ │ ├── lockinfo-001.xml
│ │ │ │ ├── lockinfo-002.json
│ │ │ │ ├── lockinfo-002.xml
│ │ │ │ ├── mkcol-001.json
│ │ │ │ ├── mkcol-001.xml
│ │ │ │ ├── mkcol-002.json
│ │ │ │ ├── mkcol-002.xml
│ │ │ │ ├── mkcol-003.json
│ │ │ │ ├── mkcol-003.xml
│ │ │ │ ├── mkcol-004.json
│ │ │ │ ├── mkcol-004.xml
│ │ │ │ ├── propertyupdate-001.json
│ │ │ │ ├── propertyupdate-001.xml
│ │ │ │ ├── propertyupdate-002.json
│ │ │ │ ├── propertyupdate-002.xml
│ │ │ │ ├── propfind-001.json
│ │ │ │ ├── propfind-001.xml
│ │ │ │ ├── propfind-002.json
│ │ │ │ ├── propfind-002.xml
│ │ │ │ ├── propfind-003.json
│ │ │ │ ├── propfind-003.xml
│ │ │ │ ├── propfind-004.json
│ │ │ │ ├── propfind-004.xml
│ │ │ │ ├── propfind-005.json
│ │ │ │ ├── propfind-005.xml
│ │ │ │ ├── propfind-006.json
│ │ │ │ ├── propfind-006.xml
│ │ │ │ ├── propfind-007.json
│ │ │ │ ├── propfind-007.xml
│ │ │ │ ├── propfind-008.json
│ │ │ │ ├── propfind-008.xml
│ │ │ │ ├── propfind-009.json
│ │ │ │ ├── propfind-009.xml
│ │ │ │ ├── propfind-010.json
│ │ │ │ ├── propfind-010.xml
│ │ │ │ ├── report-001.json
│ │ │ │ ├── report-001.xml
│ │ │ │ ├── report-002.json
│ │ │ │ ├── report-002.xml
│ │ │ │ ├── report-003.json
│ │ │ │ ├── report-003.xml
│ │ │ │ ├── report-004.json
│ │ │ │ ├── report-004.xml
│ │ │ │ ├── report-005.json
│ │ │ │ ├── report-005.xml
│ │ │ │ ├── report-006.json
│ │ │ │ ├── report-006.xml
│ │ │ │ ├── report-007.json
│ │ │ │ ├── report-007.xml
│ │ │ │ ├── report-008.json
│ │ │ │ ├── report-008.xml
│ │ │ │ ├── report-009.json
│ │ │ │ ├── report-009.xml
│ │ │ │ ├── report-010.json
│ │ │ │ ├── report-010.xml
│ │ │ │ ├── report-011.json
│ │ │ │ ├── report-011.xml
│ │ │ │ ├── report-012.json
│ │ │ │ ├── report-012.xml
│ │ │ │ ├── report-013.json
│ │ │ │ ├── report-013.xml
│ │ │ │ ├── report-014.json
│ │ │ │ ├── report-014.xml
│ │ │ │ ├── report-015.json
│ │ │ │ ├── report-015.xml
│ │ │ │ ├── report-016.json
│ │ │ │ ├── report-016.xml
│ │ │ │ ├── report-017.json
│ │ │ │ ├── report-017.xml
│ │ │ │ ├── report-018.json
│ │ │ │ ├── report-018.xml
│ │ │ │ ├── report-019.json
│ │ │ │ ├── report-019.xml
│ │ │ │ ├── report-020.json
│ │ │ │ ├── report-020.xml
│ │ │ │ ├── report-021.json
│ │ │ │ ├── report-021.xml
│ │ │ │ ├── report-022.json
│ │ │ │ ├── report-022.xml
│ │ │ │ ├── report-023.json
│ │ │ │ ├── report-023.xml
│ │ │ │ ├── report-024.json
│ │ │ │ ├── report-024.xml
│ │ │ │ ├── report-025.json
│ │ │ │ └── report-025.xml
│ │ │ └── responses/
│ │ │ ├── 001.xml
│ │ │ ├── 002.xml
│ │ │ ├── 003.xml
│ │ │ ├── 004.xml
│ │ │ ├── 005.xml
│ │ │ ├── 006.xml
│ │ │ ├── 007.xml
│ │ │ ├── 008.xml
│ │ │ ├── 009.xml
│ │ │ ├── 010.xml
│ │ │ ├── 011.xml
│ │ │ ├── 012.xml
│ │ │ ├── 013.xml
│ │ │ ├── 014.xml
│ │ │ ├── 015.xml
│ │ │ ├── 016.xml
│ │ │ ├── 017.xml
│ │ │ ├── 018.xml
│ │ │ ├── 019.xml
│ │ │ └── 020.xml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── parser/
│ │ │ ├── header.rs
│ │ │ ├── mod.rs
│ │ │ ├── property.rs
│ │ │ └── tokenizer.rs
│ │ ├── requests/
│ │ │ ├── acl.rs
│ │ │ ├── lockinfo.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── propertyupdate.rs
│ │ │ ├── propfind.rs
│ │ │ └── report.rs
│ │ ├── responses/
│ │ │ ├── acl.rs
│ │ │ ├── error.rs
│ │ │ ├── lock.rs
│ │ │ ├── mkcol.rs
│ │ │ ├── mod.rs
│ │ │ ├── multistatus.rs
│ │ │ ├── property.rs
│ │ │ ├── propstat.rs
│ │ │ └── schedule.rs
│ │ └── schema/
│ │ ├── mod.rs
│ │ ├── property.rs
│ │ ├── request.rs
│ │ └── response.rs
│ ├── directory/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── backend/
│ │ │ ├── imap/
│ │ │ │ ├── client.rs
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── pool.rs
│ │ │ │ └── tls.rs
│ │ │ ├── internal/
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── manage.rs
│ │ │ │ └── mod.rs
│ │ │ ├── ldap/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── pool.rs
│ │ │ ├── memory/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ └── mod.rs
│ │ │ ├── mod.rs
│ │ │ ├── oidc/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ └── mod.rs
│ │ │ ├── smtp/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── pool.rs
│ │ │ └── sql/
│ │ │ ├── config.rs
│ │ │ ├── lookup.rs
│ │ │ └── mod.rs
│ │ ├── core/
│ │ │ ├── cache.rs
│ │ │ ├── config.rs
│ │ │ ├── dispatch.rs
│ │ │ ├── mod.rs
│ │ │ ├── principal.rs
│ │ │ └── secret.rs
│ │ └── lib.rs
│ ├── email/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── cache/
│ │ │ ├── email.rs
│ │ │ ├── mailbox.rs
│ │ │ └── mod.rs
│ │ ├── identity/
│ │ │ ├── index.rs
│ │ │ └── mod.rs
│ │ ├── lib.rs
│ │ ├── mailbox/
│ │ │ ├── destroy.rs
│ │ │ ├── index.rs
│ │ │ ├── manage.rs
│ │ │ └── mod.rs
│ │ ├── message/
│ │ │ ├── copy.rs
│ │ │ ├── crypto.rs
│ │ │ ├── delete.rs
│ │ │ ├── delivery.rs
│ │ │ ├── index/
│ │ │ │ ├── extractors.rs
│ │ │ │ ├── metadata.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── search.rs
│ │ │ ├── ingest.rs
│ │ │ ├── metadata.rs
│ │ │ └── mod.rs
│ │ ├── push/
│ │ │ └── mod.rs
│ │ ├── sieve/
│ │ │ ├── delete.rs
│ │ │ ├── index.rs
│ │ │ ├── ingest.rs
│ │ │ └── mod.rs
│ │ └── submission/
│ │ ├── index.rs
│ │ └── mod.rs
│ ├── groupware/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── cache/
│ │ │ ├── calcard.rs
│ │ │ ├── file.rs
│ │ │ └── mod.rs
│ │ ├── calendar/
│ │ │ ├── alarm.rs
│ │ │ ├── dates.rs
│ │ │ ├── expand.rs
│ │ │ ├── index.rs
│ │ │ ├── itip.rs
│ │ │ ├── mod.rs
│ │ │ └── storage.rs
│ │ ├── contact/
│ │ │ ├── index.rs
│ │ │ ├── mod.rs
│ │ │ └── storage.rs
│ │ ├── file/
│ │ │ ├── index.rs
│ │ │ ├── mod.rs
│ │ │ └── storage.rs
│ │ ├── lib.rs
│ │ └── scheduling/
│ │ ├── attendee.rs
│ │ ├── event_cancel.rs
│ │ ├── event_create.rs
│ │ ├── event_update.rs
│ │ ├── inbound.rs
│ │ ├── itip.rs
│ │ ├── mod.rs
│ │ ├── organizer.rs
│ │ └── snapshot.rs
│ ├── http/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── auth/
│ │ │ ├── authenticate.rs
│ │ │ ├── mod.rs
│ │ │ └── oauth/
│ │ │ ├── auth.rs
│ │ │ ├── mod.rs
│ │ │ ├── openid.rs
│ │ │ ├── registration.rs
│ │ │ └── token.rs
│ │ ├── autoconfig/
│ │ │ └── mod.rs
│ │ ├── form/
│ │ │ └── mod.rs
│ │ ├── lib.rs
│ │ ├── management/
│ │ │ ├── crypto.rs
│ │ │ ├── dkim.rs
│ │ │ ├── dns.rs
│ │ │ ├── enterprise/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── telemetry.rs
│ │ │ │ └── undelete.rs
│ │ │ ├── log.rs
│ │ │ ├── mod.rs
│ │ │ ├── principal.rs
│ │ │ ├── queue.rs
│ │ │ ├── reload.rs
│ │ │ ├── report.rs
│ │ │ ├── settings.rs
│ │ │ ├── spam.rs
│ │ │ ├── stores.rs
│ │ │ └── troubleshoot.rs
│ │ └── request.rs
│ ├── http-proto/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── context.rs
│ │ ├── lib.rs
│ │ ├── request.rs
│ │ └── response.rs
│ ├── imap/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── core/
│ │ │ ├── client.rs
│ │ │ ├── mailbox.rs
│ │ │ ├── message.rs
│ │ │ ├── mod.rs
│ │ │ └── session.rs
│ │ ├── lib.rs
│ │ └── op/
│ │ ├── acl.rs
│ │ ├── append.rs
│ │ ├── authenticate.rs
│ │ ├── capability.rs
│ │ ├── close.rs
│ │ ├── copy_move.rs
│ │ ├── create.rs
│ │ ├── delete.rs
│ │ ├── enable.rs
│ │ ├── expunge.rs
│ │ ├── fetch.rs
│ │ ├── idle.rs
│ │ ├── list.rs
│ │ ├── login.rs
│ │ ├── logout.rs
│ │ ├── mod.rs
│ │ ├── namespace.rs
│ │ ├── noop.rs
│ │ ├── quota.rs
│ │ ├── rename.rs
│ │ ├── search.rs
│ │ ├── select.rs
│ │ ├── status.rs
│ │ ├── store.rs
│ │ ├── subscribe.rs
│ │ └── thread.rs
│ ├── imap-proto/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── parser/
│ │ │ ├── acl.rs
│ │ │ ├── append.rs
│ │ │ ├── authenticate.rs
│ │ │ ├── copy_move.rs
│ │ │ ├── create.rs
│ │ │ ├── delete.rs
│ │ │ ├── enable.rs
│ │ │ ├── fetch.rs
│ │ │ ├── list.rs
│ │ │ ├── login.rs
│ │ │ ├── lsub.rs
│ │ │ ├── mod.rs
│ │ │ ├── quota.rs
│ │ │ ├── rename.rs
│ │ │ ├── search.rs
│ │ │ ├── select.rs
│ │ │ ├── sort.rs
│ │ │ ├── status.rs
│ │ │ ├── store.rs
│ │ │ ├── subscribe.rs
│ │ │ └── thread.rs
│ │ ├── protocol/
│ │ │ ├── acl.rs
│ │ │ ├── append.rs
│ │ │ ├── authenticate.rs
│ │ │ ├── capability.rs
│ │ │ ├── copy_move.rs
│ │ │ ├── create.rs
│ │ │ ├── delete.rs
│ │ │ ├── enable.rs
│ │ │ ├── expunge.rs
│ │ │ ├── fetch.rs
│ │ │ ├── list.rs
│ │ │ ├── login.rs
│ │ │ ├── mod.rs
│ │ │ ├── namespace.rs
│ │ │ ├── quota.rs
│ │ │ ├── rename.rs
│ │ │ ├── search.rs
│ │ │ ├── select.rs
│ │ │ ├── status.rs
│ │ │ ├── store.rs
│ │ │ ├── subscribe.rs
│ │ │ └── thread.rs
│ │ ├── receiver.rs
│ │ └── utf7.rs
│ ├── jmap/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── addressbook/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── api/
│ │ │ ├── acl.rs
│ │ │ ├── auth.rs
│ │ │ ├── event_source.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ ├── request.rs
│ │ │ └── session.rs
│ │ ├── blob/
│ │ │ ├── copy.rs
│ │ │ ├── download.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── upload.rs
│ │ ├── calendar/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── calendar_event/
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── calendar_event_notification/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── changes/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── state.rs
│ │ ├── contact/
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── email/
│ │ │ ├── body.rs
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── headers.rs
│ │ │ ├── import.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ ├── set.rs
│ │ │ └── snippet.rs
│ │ ├── file/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── identity/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── lib.rs
│ │ ├── mailbox/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── participant_identity/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── principal/
│ │ │ ├── availability.rs
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── query.rs
│ │ ├── push/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ ├── quota/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── query.rs
│ │ ├── share_notification/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── sieve/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ ├── set.rs
│ │ │ └── validate.rs
│ │ ├── submission/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ └── set.rs
│ │ ├── thread/
│ │ │ ├── get.rs
│ │ │ └── mod.rs
│ │ ├── vacation/
│ │ │ ├── get.rs
│ │ │ ├── mod.rs
│ │ │ └── set.rs
│ │ └── websocket/
│ │ ├── mod.rs
│ │ ├── stream.rs
│ │ └── upgrade.rs
│ ├── jmap-proto/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── error/
│ │ │ ├── method.rs
│ │ │ ├── mod.rs
│ │ │ ├── request.rs
│ │ │ └── set.rs
│ │ ├── lib.rs
│ │ ├── method/
│ │ │ ├── availability.rs
│ │ │ ├── changes.rs
│ │ │ ├── copy.rs
│ │ │ ├── get.rs
│ │ │ ├── import.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── parse.rs
│ │ │ ├── query.rs
│ │ │ ├── query_changes.rs
│ │ │ ├── search_snippet.rs
│ │ │ ├── set.rs
│ │ │ ├── upload.rs
│ │ │ └── validate.rs
│ │ ├── object/
│ │ │ ├── addressbook.rs
│ │ │ ├── blob.rs
│ │ │ ├── calendar.rs
│ │ │ ├── calendar_event.rs
│ │ │ ├── calendar_event_notification.rs
│ │ │ ├── contact.rs
│ │ │ ├── email.rs
│ │ │ ├── email_submission.rs
│ │ │ ├── file_node.rs
│ │ │ ├── identity.rs
│ │ │ ├── mailbox.rs
│ │ │ ├── mod.rs
│ │ │ ├── participant_identity.rs
│ │ │ ├── principal.rs
│ │ │ ├── push_subscription.rs
│ │ │ ├── quota.rs
│ │ │ ├── search_snippet.rs
│ │ │ ├── share_notification.rs
│ │ │ ├── sieve.rs
│ │ │ ├── thread.rs
│ │ │ └── vacation_response.rs
│ │ ├── references/
│ │ │ ├── eval.rs
│ │ │ ├── jsptr.rs
│ │ │ ├── mod.rs
│ │ │ └── resolve.rs
│ │ ├── request/
│ │ │ ├── capability.rs
│ │ │ ├── deserialize.rs
│ │ │ ├── method.rs
│ │ │ ├── mod.rs
│ │ │ ├── parser.rs
│ │ │ ├── reference.rs
│ │ │ └── websocket.rs
│ │ ├── response/
│ │ │ ├── mod.rs
│ │ │ ├── serialize.rs
│ │ │ └── status.rs
│ │ └── types/
│ │ ├── date.rs
│ │ ├── mod.rs
│ │ └── state.rs
│ ├── main/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── managesieve/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── core/
│ │ │ ├── client.rs
│ │ │ ├── mod.rs
│ │ │ └── session.rs
│ │ ├── lib.rs
│ │ └── op/
│ │ ├── authenticate.rs
│ │ ├── capability.rs
│ │ ├── checkscript.rs
│ │ ├── deletescript.rs
│ │ ├── getscript.rs
│ │ ├── havespace.rs
│ │ ├── listscripts.rs
│ │ ├── logout.rs
│ │ ├── mod.rs
│ │ ├── noop.rs
│ │ ├── putscript.rs
│ │ ├── renamescript.rs
│ │ └── setactive.rs
│ ├── migration/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── addressbook_v2.rs
│ │ ├── blob.rs
│ │ ├── calendar_v2.rs
│ │ ├── changelog.rs
│ │ ├── contact_v2.rs
│ │ ├── email_v1.rs
│ │ ├── email_v2.rs
│ │ ├── encryption_v1.rs
│ │ ├── encryption_v2.rs
│ │ ├── event_v1.rs
│ │ ├── event_v2.rs
│ │ ├── identity_v1.rs
│ │ ├── lib.rs
│ │ ├── mailbox.rs
│ │ ├── object.rs
│ │ ├── principal_v1.rs
│ │ ├── principal_v2.rs
│ │ ├── push_v1.rs
│ │ ├── push_v2.rs
│ │ ├── queue_v1.rs
│ │ ├── queue_v2.rs
│ │ ├── report.rs
│ │ ├── sieve_v1.rs
│ │ ├── sieve_v2.rs
│ │ ├── submission.rs
│ │ ├── tasks_v1.rs
│ │ ├── tasks_v2.rs
│ │ ├── threads.rs
│ │ ├── v011.rs
│ │ ├── v012.rs
│ │ ├── v013.rs
│ │ └── v014.rs
│ ├── nlp/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── classifier/
│ │ │ ├── adam.rs
│ │ │ ├── feature.rs
│ │ │ ├── ftrl.rs
│ │ │ ├── mod.rs
│ │ │ ├── model.rs
│ │ │ ├── reservoir.rs
│ │ │ ├── sgd.rs
│ │ │ └── train.rs
│ │ ├── language/
│ │ │ ├── detect.rs
│ │ │ ├── mod.rs
│ │ │ ├── search_snippet.rs
│ │ │ ├── stemmer.rs
│ │ │ └── stopwords.rs
│ │ ├── lib.rs
│ │ └── tokenizers/
│ │ ├── chinese.rs
│ │ ├── japanese.rs
│ │ ├── mod.rs
│ │ ├── space.rs
│ │ ├── stream.rs
│ │ ├── types.rs
│ │ └── word.rs
│ ├── pop3/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── client.rs
│ │ ├── lib.rs
│ │ ├── mailbox.rs
│ │ ├── op/
│ │ │ ├── authenticate.rs
│ │ │ ├── delete.rs
│ │ │ ├── fetch.rs
│ │ │ ├── list.rs
│ │ │ └── mod.rs
│ │ ├── protocol/
│ │ │ ├── mod.rs
│ │ │ ├── request.rs
│ │ │ └── response.rs
│ │ └── session.rs
│ ├── services/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── broadcast/
│ │ │ ├── mod.rs
│ │ │ ├── publisher.rs
│ │ │ └── subscriber.rs
│ │ ├── housekeeper/
│ │ │ └── mod.rs
│ │ ├── lib.rs
│ │ ├── state_manager/
│ │ │ ├── ece.rs
│ │ │ ├── http.rs
│ │ │ ├── manager.rs
│ │ │ ├── mod.rs
│ │ │ └── push.rs
│ │ └── task_manager/
│ │ ├── alarm.rs
│ │ ├── imip.rs
│ │ ├── index.rs
│ │ ├── lock.rs
│ │ ├── merge_threads.rs
│ │ └── mod.rs
│ ├── smtp/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── core/
│ │ │ ├── mod.rs
│ │ │ ├── params.rs
│ │ │ └── throttle.rs
│ │ ├── inbound/
│ │ │ ├── auth.rs
│ │ │ ├── data.rs
│ │ │ ├── ehlo.rs
│ │ │ ├── hooks/
│ │ │ │ ├── client.rs
│ │ │ │ ├── message.rs
│ │ │ │ └── mod.rs
│ │ │ ├── mail.rs
│ │ │ ├── milter/
│ │ │ │ ├── client.rs
│ │ │ │ ├── macros.rs
│ │ │ │ ├── message.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── protocol.rs
│ │ │ │ └── receiver.rs
│ │ │ ├── mod.rs
│ │ │ ├── rcpt.rs
│ │ │ ├── session.rs
│ │ │ ├── spam.rs
│ │ │ ├── spawn.rs
│ │ │ └── vrfy.rs
│ │ ├── lib.rs
│ │ ├── outbound/
│ │ │ ├── client.rs
│ │ │ ├── dane/
│ │ │ │ ├── dnssec.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── verify.rs
│ │ │ ├── delivery.rs
│ │ │ ├── local.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── mta_sts/
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── parse.rs
│ │ │ │ └── verify.rs
│ │ │ └── session.rs
│ │ ├── queue/
│ │ │ ├── dsn.rs
│ │ │ ├── manager.rs
│ │ │ ├── mod.rs
│ │ │ ├── quota.rs
│ │ │ ├── spool.rs
│ │ │ └── throttle.rs
│ │ ├── reporting/
│ │ │ ├── analysis.rs
│ │ │ ├── dkim.rs
│ │ │ ├── dmarc.rs
│ │ │ ├── mod.rs
│ │ │ ├── scheduler.rs
│ │ │ ├── spf.rs
│ │ │ └── tls.rs
│ │ └── scripts/
│ │ ├── envelope.rs
│ │ ├── event_loop.rs
│ │ ├── exec.rs
│ │ └── mod.rs
│ ├── spam-filter/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── analysis/
│ │ │ ├── classifier.rs
│ │ │ ├── date.rs
│ │ │ ├── dmarc.rs
│ │ │ ├── domain.rs
│ │ │ ├── ehlo.rs
│ │ │ ├── from.rs
│ │ │ ├── headers.rs
│ │ │ ├── html.rs
│ │ │ ├── init.rs
│ │ │ ├── ip.rs
│ │ │ ├── llm.rs
│ │ │ ├── messageid.rs
│ │ │ ├── mime.rs
│ │ │ ├── mod.rs
│ │ │ ├── pyzor.rs
│ │ │ ├── received.rs
│ │ │ ├── recipient.rs
│ │ │ ├── replyto.rs
│ │ │ ├── rules.rs
│ │ │ ├── score.rs
│ │ │ ├── subject.rs
│ │ │ └── url.rs
│ │ ├── lib.rs
│ │ └── modules/
│ │ ├── classifier.rs
│ │ ├── dnsbl.rs
│ │ ├── expression.rs
│ │ ├── html.rs
│ │ ├── mod.rs
│ │ ├── pyzor.rs
│ │ └── sanitize.rs
│ ├── store/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── backend/
│ │ │ ├── azure/
│ │ │ │ └── mod.rs
│ │ │ ├── composite/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read_replica.rs
│ │ │ │ ├── sharded_blob.rs
│ │ │ │ └── sharded_lookup.rs
│ │ │ ├── elastic/
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── search.rs
│ │ │ ├── foundationdb/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ └── write.rs
│ │ │ ├── fs/
│ │ │ │ └── mod.rs
│ │ │ ├── http/
│ │ │ │ ├── config.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ └── mod.rs
│ │ │ ├── kafka/
│ │ │ │ ├── mod.rs
│ │ │ │ └── pubsub.rs
│ │ │ ├── meili/
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── search.rs
│ │ │ ├── memory/
│ │ │ │ └── mod.rs
│ │ │ ├── mod.rs
│ │ │ ├── mysql/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ ├── search.rs
│ │ │ │ └── write.rs
│ │ │ ├── nats/
│ │ │ │ ├── mod.rs
│ │ │ │ └── pubsub.rs
│ │ │ ├── postgres/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ ├── search.rs
│ │ │ │ ├── tls.rs
│ │ │ │ └── write.rs
│ │ │ ├── redis/
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── pool.rs
│ │ │ │ └── pubsub.rs
│ │ │ ├── rocksdb/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── read.rs
│ │ │ │ └── write.rs
│ │ │ ├── s3/
│ │ │ │ └── mod.rs
│ │ │ ├── sqlite/
│ │ │ │ ├── blob.rs
│ │ │ │ ├── lookup.rs
│ │ │ │ ├── main.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── pool.rs
│ │ │ │ ├── read.rs
│ │ │ │ └── write.rs
│ │ │ └── zenoh/
│ │ │ ├── mod.rs
│ │ │ └── pubsub.rs
│ │ ├── config.rs
│ │ ├── dispatch/
│ │ │ ├── blob.rs
│ │ │ ├── lookup.rs
│ │ │ ├── mod.rs
│ │ │ ├── pubsub.rs
│ │ │ ├── search.rs
│ │ │ └── store.rs
│ │ ├── lib.rs
│ │ ├── query/
│ │ │ ├── acl.rs
│ │ │ ├── log.rs
│ │ │ └── mod.rs
│ │ ├── search/
│ │ │ ├── bm_u32.rs
│ │ │ ├── bm_u64.rs
│ │ │ ├── document.rs
│ │ │ ├── fields.rs
│ │ │ ├── index.rs
│ │ │ ├── local.rs
│ │ │ ├── mod.rs
│ │ │ ├── query.rs
│ │ │ ├── split.rs
│ │ │ └── term.rs
│ │ └── write/
│ │ ├── assert.rs
│ │ ├── batch.rs
│ │ ├── bitpack.rs
│ │ ├── blob.rs
│ │ ├── key.rs
│ │ ├── log.rs
│ │ ├── mod.rs
│ │ └── serialize.rs
│ ├── trc/
│ │ ├── Cargo.toml
│ │ ├── event-macro/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ └── src/
│ │ ├── atomics/
│ │ │ ├── array.rs
│ │ │ ├── bitset.rs
│ │ │ ├── counter.rs
│ │ │ ├── gauge.rs
│ │ │ ├── histogram.rs
│ │ │ └── mod.rs
│ │ ├── event/
│ │ │ ├── conv.rs
│ │ │ ├── description.rs
│ │ │ ├── level.rs
│ │ │ ├── metrics.rs
│ │ │ └── mod.rs
│ │ ├── ipc/
│ │ │ ├── bitset.rs
│ │ │ ├── channel.rs
│ │ │ ├── collector.rs
│ │ │ ├── metrics.rs
│ │ │ ├── mod.rs
│ │ │ └── subscriber.rs
│ │ ├── lib.rs
│ │ ├── macros.rs
│ │ └── serializers/
│ │ ├── binary.rs
│ │ ├── json.rs
│ │ ├── mod.rs
│ │ └── text.rs
│ ├── types/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── acl.rs
│ │ ├── blob.rs
│ │ ├── blob_hash.rs
│ │ ├── collection.rs
│ │ ├── dead_property.rs
│ │ ├── field.rs
│ │ ├── id.rs
│ │ ├── keyword.rs
│ │ ├── lib.rs
│ │ ├── semver.rs
│ │ ├── special_use.rs
│ │ └── type_state.rs
│ └── utils/
│ ├── Cargo.toml
│ ├── proc-macros/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── src/
│ ├── bimap.rs
│ ├── cache.rs
│ ├── chained_bytes.rs
│ ├── cheeky_hash.rs
│ ├── codec/
│ │ ├── base32_custom.rs
│ │ ├── leb128.rs
│ │ └── mod.rs
│ ├── config/
│ │ ├── cron.rs
│ │ ├── http.rs
│ │ ├── ipmask.rs
│ │ ├── mod.rs
│ │ ├── parser.rs
│ │ └── utils.rs
│ ├── glob.rs
│ ├── lib.rs
│ ├── map/
│ │ ├── bitmap.rs
│ │ ├── mod.rs
│ │ ├── mutex_map.rs
│ │ └── vec_map.rs
│ ├── snowflake.rs
│ ├── suffixlist.rs
│ ├── template.rs
│ ├── topological.rs
│ └── url_params.rs
├── docker-bake.hcl
├── install.sh
├── resources/
│ ├── apparmor.d/
│ │ └── stalwart-mail
│ ├── config/
│ │ └── config.toml
│ ├── docker/
│ │ ├── Dockerfile.fdb
│ │ ├── download.sh
│ │ └── entrypoint.sh
│ ├── html-templates/
│ │ ├── calendar-alarm.html
│ │ ├── calendar-alarm.html.min
│ │ ├── calendar-alarm.mjml
│ │ ├── calendar-invite.html
│ │ ├── calendar-invite.html.min
│ │ └── calendar-invite.mjml
│ ├── locales/
│ │ └── i18n.yml
│ ├── scripts/
│ │ └── ossify.py
│ └── systemd/
│ ├── stalwart-mail.service
│ └── stalwart.mail.plist
└── tests/
├── Cargo.toml
├── resources/
│ ├── acme/
│ │ ├── Docker.pebble
│ │ ├── config.toml
│ │ ├── docker-compose-pebble.yaml
│ │ └── test_acme.sh
│ ├── crypto/
│ │ ├── cert_mixed.pem
│ │ ├── cert_pgp.der
│ │ ├── cert_pgp.pem
│ │ ├── cert_smime.der
│ │ ├── cert_smime.pem
│ │ └── is_encrypted.txt
│ ├── imap/
│ │ ├── 000.imap
│ │ ├── 000.txt
│ │ ├── 001.imap
│ │ ├── 001.txt
│ │ ├── 002.imap
│ │ ├── 002.txt
│ │ ├── 003.imap
│ │ ├── 003.txt
│ │ ├── 004.imap
│ │ ├── 004.txt
│ │ ├── 005.imap
│ │ ├── 005.txt
│ │ ├── 006.imap
│ │ ├── 006.txt
│ │ ├── 007.imap
│ │ ├── 007.txt
│ │ ├── 008.imap
│ │ ├── 008.txt
│ │ ├── 009.imap
│ │ ├── 009.txt
│ │ ├── 010.imap
│ │ ├── 010.txt
│ │ ├── 011.imap
│ │ ├── 011.txt
│ │ ├── 012.imap
│ │ ├── 012.txt
│ │ ├── 013.imap
│ │ ├── 013.txt
│ │ ├── 014.imap
│ │ └── 014.txt
│ ├── imap-test/
│ │ ├── append
│ │ ├── append-binary
│ │ ├── atoms
│ │ ├── broken/
│ │ │ ├── search-intdate
│ │ │ └── search-intdate.mbox
│ │ ├── catenate
│ │ ├── catenate-multiappend
│ │ ├── close
│ │ ├── copy
│ │ ├── default.mbox
│ │ ├── esearch
│ │ ├── esearch-condstore
│ │ ├── esearch.mbox
│ │ ├── esort
│ │ ├── expunge
│ │ ├── expunge2
│ │ ├── fetch
│ │ ├── fetch-binary-mime
│ │ ├── fetch-binary-mime-base64
│ │ ├── fetch-binary-mime-base64.mbox
│ │ ├── fetch-binary-mime-qp
│ │ ├── fetch-binary-mime-qp.mbox
│ │ ├── fetch-binary-mime.mbox
│ │ ├── fetch-body
│ │ ├── fetch-body-message-rfc822
│ │ ├── fetch-body-message-rfc822-mime
│ │ ├── fetch-body-message-rfc822-mime.mbox
│ │ ├── fetch-body-message-rfc822-x2
│ │ ├── fetch-body-message-rfc822-x2.mbox
│ │ ├── fetch-body-message-rfc822.mbox
│ │ ├── fetch-body-mime
│ │ ├── fetch-body-mime.mbox
│ │ ├── fetch-body.mbox
│ │ ├── fetch-bodystructure
│ │ ├── fetch-bodystructure.mbox
│ │ ├── fetch-envelope
│ │ ├── fetch-envelope.mbox
│ │ ├── id
│ │ ├── list
│ │ ├── listext
│ │ ├── logout
│ │ ├── move
│ │ ├── multiappend
│ │ ├── mutf7
│ │ ├── nil
│ │ ├── nil.mbox
│ │ ├── notify
│ │ ├── pipeline
│ │ ├── search-addresses
│ │ ├── search-addresses.mbox
│ │ ├── search-body
│ │ ├── search-body.mbox
│ │ ├── search-context-update
│ │ ├── search-context-update2
│ │ ├── search-context-update3
│ │ ├── search-date
│ │ ├── search-date.mbox
│ │ ├── search-flags
│ │ ├── search-header
│ │ ├── search-header.mbox
│ │ ├── search-partial
│ │ ├── search-partial.mbox
│ │ ├── search-sets
│ │ ├── search-size
│ │ ├── search-size.mbox
│ │ ├── select
│ │ ├── select.mbox
│ │ ├── sort-addresses
│ │ ├── sort-addresses.mbox
│ │ ├── sort-arrival
│ │ ├── sort-arrival.mbox
│ │ ├── sort-date
│ │ ├── sort-date.mbox
│ │ ├── sort-display-from
│ │ ├── sort-display-from.mbox
│ │ ├── sort-display-to
│ │ ├── sort-display-to.mbox
│ │ ├── sort-partial
│ │ ├── sort-partial.mbox
│ │ ├── sort-size
│ │ ├── sort-size.mbox
│ │ ├── sort-subject
│ │ ├── sort-subject.mbox
│ │ ├── store
│ │ ├── subscribe
│ │ ├── thread
│ │ ├── thread-orderedsubject
│ │ ├── thread-orderedsubject.mbox
│ │ ├── thread-orderedsubject2
│ │ ├── thread-orderedsubject2.mbox
│ │ ├── thread.mbox
│ │ ├── thread2
│ │ ├── thread2.mbox
│ │ ├── thread3
│ │ ├── thread3.mbox
│ │ ├── thread4
│ │ ├── thread4.mbox
│ │ ├── thread5
│ │ ├── thread5.mbox
│ │ ├── thread6
│ │ ├── thread6.mbox
│ │ ├── thread7
│ │ ├── thread7.mbox
│ │ ├── thread8
│ │ ├── thread8.mbox
│ │ ├── uidplus
│ │ ├── uidvalidity
│ │ ├── uidvalidity-rename
│ │ ├── urlauth
│ │ ├── urlauth-binary
│ │ ├── urlauth-binary.mbox
│ │ └── urlauth2
│ ├── itip/
│ │ ├── google_calendar.txt
│ │ ├── itip_incoming.txt
│ │ ├── put_validation.txt
│ │ ├── rfc5546_event_recurring.txt
│ │ ├── rfc5546_event_single.txt
│ │ ├── rfc5546_todo.txt
│ │ ├── rfc6638_recurring.txt
│ │ └── rfc6638_single.txt
│ ├── jmap/
│ │ ├── email_get/
│ │ │ ├── headers.eml
│ │ │ ├── headers.json
│ │ │ ├── message_attachment.eml
│ │ │ ├── message_attachment.json
│ │ │ ├── multipart_alternative.eml
│ │ │ ├── multipart_alternative.json
│ │ │ ├── multipart_cid.eml
│ │ │ ├── multipart_cid.json
│ │ │ ├── multipart_mixed.eml
│ │ │ ├── multipart_mixed.json
│ │ │ ├── multipart_related.eml
│ │ │ ├── multipart_related.json
│ │ │ ├── rfc8621.eml
│ │ │ ├── rfc8621.json
│ │ │ ├── single_part.eml
│ │ │ ├── single_part.json
│ │ │ ├── text_body_missing.eml
│ │ │ ├── text_body_missing.json
│ │ │ ├── text_body_missing_multipart.eml
│ │ │ └── text_body_missing_multipart.json
│ │ ├── email_parse/
│ │ │ ├── attachment.eml
│ │ │ ├── attachment.json
│ │ │ ├── attachment.part1
│ │ │ ├── attachment.part2
│ │ │ ├── attachment.part3
│ │ │ ├── attachment_b64.eml
│ │ │ ├── attachment_b64.json
│ │ │ ├── attachment_b64.part1
│ │ │ ├── attachment_b64.part2
│ │ │ ├── headers.eml
│ │ │ └── headers.json
│ │ ├── email_set/
│ │ │ ├── headers.eml
│ │ │ ├── headers.jmap
│ │ │ ├── headers.json
│ │ │ ├── minimal.eml
│ │ │ ├── minimal.jmap
│ │ │ ├── minimal.json
│ │ │ ├── mixed.eml
│ │ │ ├── mixed.jmap
│ │ │ ├── mixed.json
│ │ │ ├── nested_body.eml
│ │ │ ├── nested_body.jmap
│ │ │ ├── nested_body.json
│ │ │ ├── rfc8621_1.eml
│ │ │ ├── rfc8621_1.jmap
│ │ │ ├── rfc8621_1.json
│ │ │ ├── rfc8621_2.eml
│ │ │ ├── rfc8621_2.jmap
│ │ │ └── rfc8621_2.json
│ │ ├── email_snippet/
│ │ │ ├── html.eml
│ │ │ ├── mixed.eml
│ │ │ ├── subpart.eml
│ │ │ ├── text_plain.eml
│ │ │ └── text_plain_chinese.eml
│ │ └── sieve/
│ │ ├── test_discard_reject.sieve
│ │ ├── test_include.sieve
│ │ ├── test_include_global.sieve
│ │ ├── test_include_this.sieve
│ │ ├── test_mailbox.sieve
│ │ ├── test_notify_fcc.sieve
│ │ ├── test_redirect_enclose.sieve
│ │ ├── validate_error.sieve
│ │ └── validate_ok.sieve
│ ├── ldap/
│ │ ├── ldap.cfg
│ │ └── run_glauth.sh
│ ├── otel/
│ │ ├── docker-compose.yaml
│ │ ├── otel-collector-config.yaml
│ │ └── stalwart-config.toml
│ ├── proxy-protocol/
│ │ ├── Docker.haproxy
│ │ └── haproxy.cfg
│ ├── scripts/
│ │ ├── create_test_cluster.sh
│ │ ├── create_test_env.sh
│ │ ├── create_test_users.sh
│ │ ├── imap-log-parser.py
│ │ ├── imap_import.py
│ │ ├── imap_import_single.py
│ │ ├── stress_test.py
│ │ └── stress_test_prepare.py
│ ├── smtp/
│ │ ├── antispam/
│ │ │ ├── bounce.test
│ │ │ ├── classifier.ham
│ │ │ ├── classifier.spam
│ │ │ ├── classifier.test
│ │ │ ├── classifier_features.test
│ │ │ ├── classifier_html.test
│ │ │ ├── combined.test
│ │ │ ├── date.test
│ │ │ ├── dmarc.test
│ │ │ ├── from.test
│ │ │ ├── headers.test
│ │ │ ├── helo.test
│ │ │ ├── html.test
│ │ │ ├── ip.test
│ │ │ ├── llm.test
│ │ │ ├── messageid.test
│ │ │ ├── mime.test
│ │ │ ├── pyzor.test
│ │ │ ├── rbl.test
│ │ │ ├── received.test
│ │ │ ├── recipient.test
│ │ │ ├── replyto.test
│ │ │ ├── spamtrap.test
│ │ │ ├── subject.test
│ │ │ └── url.test
│ │ ├── certs/
│ │ │ ├── tls_cert.pem
│ │ │ └── tls_privatekey.pem
│ │ ├── config/
│ │ │ ├── if-blocks.toml
│ │ │ ├── lists.toml
│ │ │ ├── rules-dynvalue.toml
│ │ │ ├── rules-eval.toml
│ │ │ ├── rules.toml
│ │ │ ├── servers.toml
│ │ │ ├── throttle.toml
│ │ │ └── toml-parser.toml
│ │ ├── dane/
│ │ │ ├── dns.txt
│ │ │ ├── internet.nl.0.cert
│ │ │ ├── internet.nl.1.cert
│ │ │ ├── mail.ietf.org.0.cert
│ │ │ ├── mail.ietf.org.1.cert
│ │ │ ├── mail.ietf.org.2.cert
│ │ │ └── mail.ietf.org.3.cert
│ │ ├── dsn/
│ │ │ ├── delay.eml
│ │ │ ├── failure.eml
│ │ │ ├── mixed.eml
│ │ │ ├── original.txt
│ │ │ └── success.eml
│ │ ├── lists/
│ │ │ ├── test-list1.txt
│ │ │ └── test-list2.txt
│ │ ├── messages/
│ │ │ ├── arc.eml
│ │ │ ├── dkim.eml
│ │ │ ├── invalid_arc.eml
│ │ │ ├── invalid_dkim.eml
│ │ │ ├── loop.eml
│ │ │ ├── multipart.eml
│ │ │ ├── no_dkim.eml
│ │ │ └── no_msgid.eml
│ │ ├── milter/
│ │ │ ├── message.eml
│ │ │ └── message.json
│ │ ├── reports/
│ │ │ ├── arf1.eml
│ │ │ ├── arf2.eml
│ │ │ ├── arf3.eml
│ │ │ ├── arf4.eml
│ │ │ ├── arf5.eml
│ │ │ ├── dmarc1.eml
│ │ │ ├── dmarc2.eml
│ │ │ ├── dmarc3.eml
│ │ │ ├── dmarc4.eml
│ │ │ ├── dmarc5.eml
│ │ │ ├── tls1.eml
│ │ │ └── tls2.eml
│ │ └── sieve/
│ │ ├── awl.sieve
│ │ ├── awl_include.sieve
│ │ ├── stage_connect.sieve
│ │ ├── stage_data.sieve
│ │ ├── stage_ehlo.sieve
│ │ ├── stage_mail.sieve
│ │ └── stage_rcpt.sieve
│ ├── tls_cert.pem
│ └── tls_privatekey.pem
└── src/
├── cluster/
│ ├── broadcast.rs
│ ├── mod.rs
│ └── stress.rs
├── directory/
│ ├── imap.rs
│ ├── internal.rs
│ ├── ldap.rs
│ ├── mod.rs
│ ├── oidc.rs
│ ├── smtp.rs
│ └── sql.rs
├── http_server.rs
├── imap/
│ ├── acl.rs
│ ├── antispam.rs
│ ├── append.rs
│ ├── basic.rs
│ ├── body_structure.rs
│ ├── condstore.rs
│ ├── copy_move.rs
│ ├── fetch.rs
│ ├── idle.rs
│ ├── mailbox.rs
│ ├── managesieve.rs
│ ├── mod.rs
│ ├── pop.rs
│ ├── search.rs
│ ├── store.rs
│ └── thread.rs
├── jmap/
│ ├── auth/
│ │ ├── limits.rs
│ │ ├── mod.rs
│ │ ├── oauth.rs
│ │ ├── permissions.rs
│ │ └── quota.rs
│ ├── calendar/
│ │ ├── acl.rs
│ │ ├── alarm.rs
│ │ ├── calendars.rs
│ │ ├── event.rs
│ │ ├── identity.rs
│ │ ├── mod.rs
│ │ └── notification.rs
│ ├── contacts/
│ │ ├── acl.rs
│ │ ├── addressbook.rs
│ │ ├── contact.rs
│ │ └── mod.rs
│ ├── core/
│ │ ├── blob.rs
│ │ ├── event_source.rs
│ │ ├── mod.rs
│ │ ├── push_subscription.rs
│ │ └── websocket.rs
│ ├── files/
│ │ ├── acl.rs
│ │ ├── mod.rs
│ │ └── node.rs
│ ├── mail/
│ │ ├── acl.rs
│ │ ├── antispam.rs
│ │ ├── changes.rs
│ │ ├── copy.rs
│ │ ├── crypto.rs
│ │ ├── delivery.rs
│ │ ├── get.rs
│ │ ├── mailbox.rs
│ │ ├── mod.rs
│ │ ├── parse.rs
│ │ ├── query.rs
│ │ ├── query_changes.rs
│ │ ├── search_snippet.rs
│ │ ├── set.rs
│ │ ├── sieve_script.rs
│ │ ├── submission.rs
│ │ ├── thread_get.rs
│ │ ├── thread_merge.rs
│ │ └── vacation_response.rs
│ ├── mod.rs
│ ├── principal/
│ │ ├── availability.rs
│ │ ├── get.rs
│ │ └── mod.rs
│ └── server/
│ ├── enterprise.rs
│ ├── mod.rs
│ ├── purge.rs
│ └── webhooks.rs
├── lib.rs
├── smtp/
│ ├── config.rs
│ ├── inbound/
│ │ ├── antispam.rs
│ │ ├── asn.rs
│ │ ├── auth.rs
│ │ ├── basic.rs
│ │ ├── data.rs
│ │ ├── dmarc.rs
│ │ ├── ehlo.rs
│ │ ├── limits.rs
│ │ ├── mail.rs
│ │ ├── milter.rs
│ │ ├── mod.rs
│ │ ├── rcpt.rs
│ │ ├── rewrite.rs
│ │ ├── scripts.rs
│ │ ├── sign.rs
│ │ ├── throttle.rs
│ │ └── vrfy.rs
│ ├── lookup/
│ │ ├── mod.rs
│ │ ├── sql.rs
│ │ └── utils.rs
│ ├── management/
│ │ ├── mod.rs
│ │ ├── queue.rs
│ │ └── report.rs
│ ├── mod.rs
│ ├── outbound/
│ │ ├── dane.rs
│ │ ├── extensions.rs
│ │ ├── fallback_relay.rs
│ │ ├── ip_lookup.rs
│ │ ├── lmtp.rs
│ │ ├── mod.rs
│ │ ├── mta_sts.rs
│ │ ├── smtp.rs
│ │ ├── throttle.rs
│ │ └── tls.rs
│ ├── queue/
│ │ ├── concurrent.rs
│ │ ├── dsn.rs
│ │ ├── manager.rs
│ │ ├── mod.rs
│ │ ├── retry.rs
│ │ └── virtualq.rs
│ ├── reporting/
│ │ ├── analyze.rs
│ │ ├── dmarc.rs
│ │ ├── mod.rs
│ │ ├── scheduler.rs
│ │ └── tls.rs
│ └── session.rs
├── store/
│ ├── blob.rs
│ ├── cleanup.rs
│ ├── import_export.rs
│ ├── lookup.rs
│ ├── mod.rs
│ ├── ops.rs
│ └── query.rs
└── webdav/
├── acl.rs
├── basic.rs
├── cal_alarm.rs
├── cal_itip.rs
├── cal_query.rs
├── cal_scheduling.rs
├── card_query.rs
├── copy_move.rs
├── lock.rs
├── mkcol.rs
├── mod.rs
├── multiget.rs
├── principals.rs
├── prop.rs
├── put_get.rs
└── sync.rs
Showing preview only (885K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (10791 symbols across 978 files)
FILE: crates/cli/src/main.rs
function main (line 30) | async fn main() -> std::io::Result<()> {
function parse_credentials (line 84) | fn parse_credentials(credentials: &str) -> Credentials {
function oauth (line 92) | async fn oauth(url: &str) -> Credentials {
type Response (line 177) | pub enum Response<T> {
type ManagementApiError (line 185) | pub enum ManagementApiError {
method into_jmap_client (line 195) | pub async fn into_jmap_client(self) -> jmap_client::client::Client {
method http_request (line 209) | pub async fn http_request<R: DeserializeOwned, B: Serialize>(
method try_http_request (line 223) | pub async fn try_http_request<R: DeserializeOwned, B: Serialize>(
method fmt (line 294) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/cli/src/modules/account.rs
method exec (line 20) | pub async fn exec(self, client: Client) {
method display_principal (line 233) | pub async fn display_principal(&self, name: &str) {
method list_principals (line 300) | pub async fn list_principals(
type ListResponse (line 350) | struct ListResponse {
method fmt (line 356) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/cli/src/modules/cli.rs
type Cli (line 16) | pub struct Cli {
type Commands (line 34) | pub enum Commands {
type Client (line 77) | pub struct Client {
type AccountCommands (line 84) | pub enum AccountCommands {
type ListCommands (line 195) | pub enum ListCommands {
type GroupCommands (line 262) | pub enum GroupCommands {
type DomainCommands (line 329) | pub enum DomainCommands {
type DkimCommands (line 358) | pub enum DkimCommands {
type ImportCommands (line 379) | pub enum ImportCommands {
type ExportCommands (line 411) | pub enum ExportCommands {
type ServerCommands (line 427) | pub enum ServerCommands {
type MailboxFormat (line 465) | pub enum MailboxFormat {
type QueueCommands (line 475) | pub enum QueueCommands {
type ReportCommands (line 549) | pub enum ReportCommands {
type ReportFormat (line 578) | pub enum ReportFormat {
function parse_datetime (line 587) | fn parse_datetime(arg: &str) -> Result<DateTime, &'static str> {
FILE: crates/cli/src/modules/database.rs
type UpdateSettings (line 19) | pub enum UpdateSettings {
method exec (line 36) | pub async fn exec(self, client: Client) {
FILE: crates/cli/src/modules/dkim.rs
type Algorithm (line 14) | pub enum Algorithm {
type DkimSignature (line 23) | struct DkimSignature {
method exec (line 36) | pub async fn exec(self, client: Client) {
FILE: crates/cli/src/modules/domain.rs
type DnsRecord (line 19) | struct DnsRecord {
method exec (line 27) | pub async fn exec(self, client: Client) {
FILE: crates/cli/src/modules/export.rs
method exec (line 32) | pub async fn exec(self, client: Client) {
function fetch_mailboxes (line 129) | pub async fn fetch_mailboxes(
function export_mailboxes (line 189) | async fn export_mailboxes(
function fetch_emails (line 205) | pub async fn fetch_emails(
function export_emails (line 266) | async fn export_emails(
function fetch_sieve_scripts (line 291) | pub async fn fetch_sieve_scripts(
function export_sieve_scripts (line 353) | async fn export_sieve_scripts(
function fetch_identities (line 377) | pub async fn fetch_identities(client: &jmap_client::client::Client) -> V...
function export_identities (line 395) | async fn export_identities(client: &jmap_client::client::Client, path: &...
function fetch_vacation_responses (line 402) | pub async fn fetch_vacation_responses(
function export_vacation_responses (line 422) | async fn export_vacation_responses(client: &jmap_client::client::Client,...
function write_file (line 434) | async fn write_file<T: Serialize>(path: &Path, name: &str, contents: Vec...
FILE: crates/cli/src/modules/group.rs
method exec (line 20) | pub async fn exec(self, client: Client) {
FILE: crates/cli/src/modules/import.rs
type Mailbox (line 44) | enum Mailbox {
type MailboxId (line 51) | enum MailboxId<'x> {
type Message (line 58) | struct Message {
method exec (line 65) | pub async fn exec(self, client: Client) {
function import_mailboxes (line 450) | async fn import_mailboxes(
function import_emails (line 567) | async fn import_emails(
function import_sieve_scripts (line 713) | async fn import_sieve_scripts(
function import_identities (line 823) | async fn import_identities(client: &jmap_client::client::Client, path: &...
function import_vacation_responses (line 897) | async fn import_vacation_responses(client: &jmap_client::client::Client,...
function build_mailbox_tree (line 950) | fn build_mailbox_tree(
function read_json (line 994) | async fn read_json<T: DeserializeOwned>(path: &Path, filename: &str) -> ...
type Item (line 1010) | type Item = io::Result<Message>;
method next (line 1012) | fn next(&mut self) -> Option<Self::Item> {
FILE: crates/cli/src/modules/list.rs
method exec (line 20) | pub async fn exec(self, client: Client) {
FILE: crates/cli/src/modules/mod.rs
constant RETRY_ATTEMPTS (line 27) | const RETRY_ATTEMPTS: usize = 5;
type Principal (line 30) | pub struct Principal {
type Type (line 66) | pub enum Type {
type PrincipalField (line 85) | pub enum PrincipalField {
type List (line 105) | pub struct List<T> {
type Response (line 111) | pub struct Response<T> {
type PrincipalUpdate (line 117) | pub struct PrincipalUpdate {
method set (line 142) | pub fn set(field: PrincipalField, value: PrincipalValue) -> PrincipalU...
method add_item (line 150) | pub fn add_item(field: PrincipalField, value: PrincipalValue) -> Princ...
method remove_item (line 158) | pub fn remove_item(field: PrincipalField, value: PrincipalValue) -> Pr...
type PrincipalAction (line 124) | pub enum PrincipalAction {
type PrincipalValue (line 135) | pub enum PrincipalValue {
type UnwrapResult (line 167) | pub trait UnwrapResult<T> {
method unwrap_result (line 168) | fn unwrap_result(self, action: &str) -> T;
function unwrap_result (line 172) | fn unwrap_result(self, message: &str) -> T {
function unwrap_result (line 184) | fn unwrap_result(self, message: &str) -> T {
function read_file (line 195) | pub fn read_file(path: &str) -> Vec<u8> {
function name_to_id (line 216) | pub async fn name_to_id(client: &Client, name: &str) -> String {
function host (line 239) | pub fn host(url: &str) -> Option<&str> {
function is_localhost (line 245) | pub fn is_localhost(url: &str) -> bool {
type OAuthResponse (line 249) | pub trait OAuthResponse {
method property (line 250) | fn property(&self, name: &str) -> &str;
method property (line 254) | fn property(&self, name: &str) -> &str {
FILE: crates/cli/src/modules/queue.rs
type Message (line 19) | pub struct Message {
type Recipient (line 34) | pub struct Recipient {
type Status (line 50) | pub enum Status {
method status_short (line 447) | fn status_short(&self) -> &str {
method status (line 456) | fn status(&self) -> &str {
method details (line 465) | fn details(&self) -> &str {
method exec (line 62) | pub async fn exec(self, client: Client) {
method query_messages (line 372) | async fn query_messages(
function deserialize_maybe_datetime (line 400) | fn deserialize_maybe_datetime<'de, D>(deserializer: D) -> Result<Option<...
function deserialize_datetime (line 417) | pub fn deserialize_datetime<'de, D>(deserializer: D) -> Result<DateTime,...
function parse_ids (line 430) | fn parse_ids(ids: &[String]) -> Vec<u64> {
FILE: crates/cli/src/modules/report.rs
type Report (line 24) | pub enum Report {
method domain (line 48) | pub fn domain(&self) -> &str {
method type_ (line 55) | pub fn type_(&self) -> &str {
method range_from (line 62) | pub fn range_from(&self) -> &DateTime {
method range_to (line 69) | pub fn range_to(&self) -> &DateTime {
method num_records (line 76) | pub fn num_records(&self) -> usize {
method exec (line 89) | pub async fn exec(self, client: Client) {
method id (line 243) | fn id(&self) -> &'static str {
FILE: crates/common/build.rs
function main (line 6) | fn main() {
function parse_yaml (line 26) | fn parse_yaml(content: &str) -> HashMap<String, HashMap<String, String>> {
function generate_locale_code (line 53) | fn generate_locale_code(locales: &HashMap<String, HashMap<String, String...
FILE: crates/common/src/addresses.rs
method email_to_id (line 20) | pub async fn email_to_id(
method rcpt (line 58) | pub async fn rcpt(
method vrfy (line 96) | pub async fn vrfy(
method expn (line 116) | pub async fn expn(
method parse (line 138) | pub fn parse(config: &mut Config, key: impl AsKey) -> Self {
type Address (line 168) | struct Address<'x>(&'x str);
method resolve_variable (line 171) | fn resolve_variable(&'_ self, _: u32) -> crate::expr::Variable<'_> {
method resolve_global (line 175) | fn resolve_global(&self, _: &str) -> Variable<'_> {
method to_subaddress (line 181) | pub async fn to_subaddress<'x, 'y: 'x>(
method to_catch_all (line 209) | pub async fn to_catch_all<'x, 'y: 'x>(
FILE: crates/common/src/auth/access_token.rs
type PrincipalOrId (line 33) | pub enum PrincipalOrId {
method from (line 385) | fn from(id: u32) -> Self {
method from (line 391) | fn from(principal: Principal) -> Self {
method id (line 397) | pub fn id(&self) -> u32 {
method build_access_token_from_principal (line 39) | async fn build_access_token_from_principal(
method build_access_token (line 220) | async fn build_access_token(&self, account_id: u32, revision: u64) -> tr...
method get_access_token (line 247) | pub async fn get_access_token(
method invalidate_principal_caches (line 282) | pub async fn invalidate_principal_caches(&self, changed_principals: Chan...
method from_id (line 406) | pub fn from_id(primary_id: u32) -> Self {
method with_access_to (line 413) | pub fn with_access_to(self, access_to: VecMap<u32, Bitmap<Collection>>) ...
method with_permission (line 417) | pub fn with_permission(mut self, permission: Permission) -> Self {
method with_tenant_id (line 422) | pub fn with_tenant_id(mut self, tenant_id: Option<u32>) -> Self {
method state (line 427) | pub fn state(&self) -> u32 {
method primary_id (line 436) | pub fn primary_id(&self) -> u32 {
method tenant_id (line 441) | pub fn tenant_id(&self) -> Option<u32> {
method secondary_ids (line 445) | pub fn secondary_ids(&self) -> impl Iterator<Item = &u32> {
method member_ids (line 451) | pub fn member_ids(&self) -> impl Iterator<Item = u32> {
method all_ids (line 457) | pub fn all_ids(&self) -> impl Iterator<Item = u32> {
method all_ids_by_collection (line 464) | pub fn all_ids_by_collection(&self, collection: Collection) -> impl Iter...
method is_member (line 477) | pub fn is_member(&self, account_id: u32) -> bool {
method is_primary_id (line 483) | pub fn is_primary_id(&self, account_id: u32) -> bool {
method has_permission (line 488) | pub fn has_permission(&self, permission: Permission) -> bool {
method assert_has_permission (line 492) | pub fn assert_has_permission(&self, permission: Permission) -> trc::Resu...
method permissions (line 502) | pub fn permissions(&self) -> Vec<Permission> {
method object_quota (line 524) | pub fn object_quota(&self, collection: Collection) -> u32 {
method is_shared (line 528) | pub fn is_shared(&self, account_id: u32) -> bool {
method shared_accounts (line 532) | pub fn shared_accounts(&self, collection: Collection) -> impl Iterator<I...
method has_access (line 544) | pub fn has_access(&self, to_account_id: u32, to_collection: impl Into<Co...
method has_account_access (line 552) | pub fn has_account_access(&self, to_account_id: u32) -> bool {
method as_resource_token (line 556) | pub fn as_resource_token(&self) -> ResourceToken {
method is_http_request_allowed (line 564) | pub fn is_http_request_allowed(&self) -> LimiterResult {
method is_imap_request_allowed (line 570) | pub fn is_imap_request_allowed(&self) -> LimiterResult {
method is_upload_allowed (line 576) | pub fn is_upload_allowed(&self) -> LimiterResult {
method update_size (line 582) | pub fn update_size(mut self) -> Self {
FILE: crates/common/src/auth/mod.rs
type AccessToken (line 28) | pub struct AccessToken {
type TenantInfo (line 48) | pub struct TenantInfo {
type ResourceToken (line 54) | pub struct ResourceToken {
type AuthRequest (line 60) | pub struct AuthRequest<'x> {
method authenticate (line 70) | pub async fn authenticate(&self, req: &AuthRequest<'_>) -> trc::Result<A...
method authenticate_credentials (line 97) | async fn authenticate_credentials(
function from_credentials (line 253) | pub fn from_credentials(
function from_plain (line 268) | pub fn from_plain(
function without_members (line 284) | pub fn without_members(mut self) -> Self {
function with_directory (line 289) | pub fn with_directory(mut self, directory: &'x Directory) -> Self {
function with_api_access (line 294) | pub fn with_api_access(mut self, allow_api_access: bool) -> Self {
method weight (line 301) | fn weight(&self) -> u64 {
type CredentialsUsername (line 306) | pub(crate) trait CredentialsUsername {
method login (line 307) | fn login(&self) -> Option<&str>;
method login (line 311) | fn login(&self) -> Option<&str> {
FILE: crates/common/src/auth/oauth/config.rs
type OAuthConfig (line 30) | pub struct OAuthConfig {
method parse (line 49) | pub fn parse(config: &mut Config) -> Self {
method default (line 199) | fn default() -> Self {
function parse_rsa_key (line 223) | fn parse_rsa_key(config: &mut Config) -> Option<(Secret, AlgorithmParame...
function parse_ecdsa_key (line 260) | fn parse_ecdsa_key(
FILE: crates/common/src/auth/oauth/crypto.rs
type SymmetricEncrypt (line 10) | pub struct SymmetricEncrypt {
constant ENCRYPT_TAG_LEN (line 17) | pub const ENCRYPT_TAG_LEN: usize = 16;
constant NONCE_LEN (line 18) | pub const NONCE_LEN: usize = 12;
method new (line 20) | pub fn new(key: &[u8], context: &str) -> Self {
method encrypt_in_place (line 31) | pub fn encrypt_in_place(&self, bytes: &mut Vec<u8>, nonce: &[u8]) -> R...
method encrypt (line 37) | pub fn encrypt(&self, bytes: &[u8], nonce: &[u8]) -> Result<Vec<u8>, S...
method decrypt (line 43) | pub fn decrypt(&self, bytes: &[u8], nonce: &[u8]) -> Result<Vec<u8>, S...
FILE: crates/common/src/auth/oauth/introspect.rs
type OAuthIntrospect (line 13) | pub struct OAuthIntrospect {
method introspect_access_token (line 51) | pub async fn introspect_access_token(
FILE: crates/common/src/auth/oauth/mod.rs
constant DEVICE_CODE_LEN (line 14) | pub const DEVICE_CODE_LEN: usize = 40;
constant USER_CODE_LEN (line 15) | pub const USER_CODE_LEN: usize = 8;
constant RANDOM_CODE_LEN (line 16) | pub const RANDOM_CODE_LEN: usize = 32;
constant CLIENT_ID_MAX_LEN (line 17) | pub const CLIENT_ID_MAX_LEN: usize = 20;
constant USER_CODE_ALPHABET (line 19) | pub const USER_CODE_ALPHABET: &[u8] = b"ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
type GrantType (line 22) | pub enum GrantType {
method as_str (line 32) | pub fn as_str(&self) -> &'static str {
method id (line 43) | pub fn id(&self) -> u8 {
method from_id (line 54) | pub fn from_id(id: u8) -> Option<Self> {
FILE: crates/common/src/auth/oauth/oidc.rs
type Userinfo (line 20) | pub struct Userinfo {
type StandardClaims (line 83) | pub struct StandardClaims {
method issue_id_token (line 102) | pub fn issue_id_token(
function any_bool (line 141) | fn any_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
FILE: crates/common/src/auth/oauth/registration.rs
type ClientRegistrationRequest (line 12) | pub struct ClientRegistrationRequest {
type ClientRegistrationResponse (line 138) | pub struct ClientRegistrationResponse {
type ApplicationType (line 161) | pub enum ApplicationType {
type SubjectType (line 168) | pub enum SubjectType {
type TokenEndpointAuthMethod (line 175) | pub enum TokenEndpointAuthMethod {
FILE: crates/common/src/auth/oauth/token.rs
type TokenInfo (line 20) | pub struct TokenInfo {
constant OAUTH_EPOCH (line 29) | const OAUTH_EPOCH: u64 = 946684800;
method encode_access_token (line 32) | pub async fn encode_access_token(
method validate_access_token (line 108) | pub async fn validate_access_token(
method password_hash (line 218) | pub async fn password_hash(&self, account_id: u32) -> trc::Result<String> {
FILE: crates/common/src/auth/rate_limit.rs
method is_http_authenticated_request_allowed (line 19) | pub async fn is_http_authenticated_request_allowed(
method is_http_anonymous_request_allowed (line 59) | pub async fn is_http_anonymous_request_allowed(&self, addr: &IpAddr) -> ...
method is_upload_allowed (line 81) | pub fn is_upload_allowed(&self, access_token: &AccessToken) -> trc::Resu...
FILE: crates/common/src/auth/roles.rs
type RolePermissions (line 18) | pub struct RolePermissions {
method union (line 151) | pub fn union(&mut self, other: &RolePermissions) {
method finalize (line 156) | pub fn finalize(mut self) -> Permissions {
method finalize_as_ref (line 161) | pub fn finalize_as_ref(&self) -> Permissions {
method get_role_permissions (line 29) | pub async fn get_role_permissions(&self, role_id: u32) -> trc::Result<Ar...
method build_role_permissions (line 53) | async fn build_role_permissions(&self, role_id: u32) -> trc::Result<Arc<...
function tenant_admin_permissions (line 168) | fn tenant_admin_permissions() -> Arc<RolePermissions> {
function user_permissions (line 181) | fn user_permissions() -> Arc<RolePermissions> {
function admin_permissions (line 194) | fn admin_permissions() -> Arc<RolePermissions> {
method weight (line 202) | fn weight(&self) -> u64 {
FILE: crates/common/src/auth/sasl.rs
function sasl_decode_challenge_plain (line 9) | pub fn sasl_decode_challenge_plain(challenge: &[u8]) -> Option<Credentia...
function sasl_decode_challenge_oauth (line 33) | pub fn sasl_decode_challenge_oauth(challenge: &[u8]) -> Option<Credentia...
function extract_oauth_bearer (line 37) | fn extract_oauth_bearer(bytes: &[u8]) -> Option<&str> {
function test_extract_oauth_bearer (line 65) | fn test_extract_oauth_bearer() {
FILE: crates/common/src/config/groupware.rs
type GroupwareConfig (line 12) | pub struct GroupwareConfig {
method parse (line 80) | pub fn parse(config: &mut Config) -> Self {
type CalendarTemplateVariable (line 57) | pub enum CalendarTemplateVariable {
type Err (line 203) | type Err = String;
method from_str (line 205) | fn from_str(s: &str) -> Result<Self, Self::Err> {
FILE: crates/common/src/config/imap.rs
type ImapConfig (line 12) | pub struct ImapConfig {
method parse (line 26) | pub fn parse(config: &mut Config) -> Self {
FILE: crates/common/src/config/inner.rs
method parse (line 35) | pub fn parse(config: &mut Config) -> Self {
method parse (line 82) | pub fn parse(config: &mut Config) -> Self {
method build_auth_parameters (line 197) | pub fn build_auth_parameters<T>(
method default (line 221) | fn default() -> Self {
method default (line 240) | fn default() -> Self {
FILE: crates/common/src/config/jmap/capabilities.rs
method add_capabilities (line 26) | pub fn add_capabilities(&mut self, config: &mut Config, groupware_config...
FILE: crates/common/src/config/jmap/settings.rs
type JmapConfig (line 20) | pub struct JmapConfig {
method parse (line 101) | pub fn parse(config: &mut Config, groupware_config: &GroupwareConfig) ...
type DefaultFolder (line 92) | pub struct DefaultFolder {
FILE: crates/common/src/config/mod.rs
constant CONNECTION_VARS (line 38) | pub(crate) const CONNECTION_VARS: &[u32; 9] = &[
method parse (line 51) | pub async fn parse(
method into_shared (line 223) | pub fn into_shared(self) -> ArcSwap<Self> {
function build_rsa_keypair (line 228) | pub fn build_rsa_keypair(pem: &str) -> Result<RsaKeyPair, String> {
function build_ecdsa_pem (line 244) | pub fn build_ecdsa_pem(
FILE: crates/common/src/config/network.rs
type Network (line 15) | pub struct Network {
method parse (line 182) | pub fn parse(config: &mut Config) -> Self {
type ContactForm (line 28) | pub struct ContactForm {
method parse (line 128) | pub fn parse(config: &mut Config) -> Option<Self> {
type ClusterRoles (line 40) | pub struct ClusterRoles {
type ClusterRole (line 55) | pub enum ClusterRole {
method is_enabled_or_sharded (line 362) | pub fn is_enabled_or_sharded(&self) -> bool {
method is_enabled_for_integer (line 366) | pub fn is_enabled_for_integer(&self, value: u32) -> bool {
method is_enabled_for_hash (line 377) | pub fn is_enabled_for_hash(&self, item: &impl std::hash::Hash) -> bool {
type AsnGeoLookupConfig (line 66) | pub enum AsnGeoLookupConfig {
method parse (line 316) | pub fn parse(config: &mut Config) -> Option<Self> {
type FieldOrDefault (line 88) | pub struct FieldOrDefault {
method parse (line 170) | pub fn parse(config: &mut Config, key: &str, default: &str) -> Self {
constant HTTP_VARS (line 93) | pub(crate) const HTTP_VARS: &[u32; 11] = &[
method default (line 108) | fn default() -> Self {
type NodeList (line 303) | struct NodeList(AHashSet<u64>);
method parse_value (line 306) | fn parse_value(value: &str) -> utils::config::Result<Self> {
FILE: crates/common/src/config/scripts.rs
type Scripting (line 24) | pub struct Scripting {
method parse (line 37) | pub async fn parse(config: &mut Config, stores: &Stores) -> Self {
method default (line 353) | fn default() -> Self {
method clone (line 380) | fn clone(&self) -> Self {
FILE: crates/common/src/config/server/listener.rs
method parse (line 35) | pub fn parse(config: &mut Config) -> Self {
method parse_server (line 54) | fn parse_server(&mut self, config: &mut Config, id_: String) {
method parse_tcp_acceptors (line 212) | pub fn parse_tcp_acceptors(&mut self, config: &mut Config, inner: Arc<In...
method parse_value (line 316) | fn parse_value(value: &str) -> Result<Self, String> {
FILE: crates/common/src/config/server/mod.rs
type Listeners (line 20) | pub struct Listeners {
type Listener (line 27) | pub struct Listener {
type TcpListener (line 37) | pub struct TcpListener {
type ServerProtocol (line 49) | pub enum ServerProtocol {
method as_str (line 60) | pub fn as_str(&self) -> &'static str {
method fmt (line 73) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/common/src/config/server/tls.rs
method parse (line 47) | pub fn parse(config: &mut Config) -> Self {
function build_dns_updater (line 188) | fn build_dns_updater(config: &mut Config, acme_id: &str) -> Option<DnsUp...
function parse_certificates (line 318) | pub(crate) fn parse_certificates(
function build_certified_key (line 417) | pub(crate) fn build_certified_key(cert: Vec<u8>, pk: Vec<u8>) -> Result<...
function build_self_signed_cert (line 444) | pub(crate) fn build_self_signed_cert(
FILE: crates/common/src/config/smtp/auth.rs
type MailAuthConfig (line 28) | pub struct MailAuthConfig {
method parse (line 170) | pub fn parse(config: &mut Config) -> Self {
type LazySignature (line 38) | pub enum LazySignature {
type ResolvedSignature (line 45) | pub struct ResolvedSignature {
type DkimAuthConfig (line 51) | pub struct DkimAuthConfig {
type ArcAuthConfig (line 58) | pub struct ArcAuthConfig {
type SpfAuthConfig (line 64) | pub struct SpfAuthConfig {
type DmarcAuthConfig (line 70) | pub struct DmarcAuthConfig {
type IpRevAuthConfig (line 75) | pub struct IpRevAuthConfig {
type VerifyStrategy (line 80) | pub enum VerifyStrategy {
type Error (line 426) | type Error = ();
method try_from (line 428) | fn try_from(value: expr::Variable<'x>) -> Result<Self, Self::Error> {
method verify (line 453) | pub fn verify(&self) -> bool {
method is_strict (line 458) | pub fn is_strict(&self) -> bool {
type DkimCanonicalization (line 88) | pub struct DkimCanonicalization {
type DkimSigner (line 93) | pub enum DkimSigner {
type ArcSealer (line 98) | pub enum ArcSealer {
method default (line 104) | fn default() -> Self {
function build_signature (line 239) | pub fn build_signature(config: &mut Config, id: &str) -> Option<(DkimSig...
function parse_pem (line 303) | fn parse_pem(config: &mut Config, key: impl AsKey) -> Option<Vec<u8>> {
function simple_pem_parse (line 312) | pub fn simple_pem_parse(contents: &str) -> Option<Vec<u8>> {
function parse_signature (line 341) | fn parse_signature<T: SigningKey, U: SigningKey<Hasher = Sha256>>(
method from (line 442) | fn from(value: VerifyStrategy) -> Self {
method parse_value (line 464) | fn parse_value(value: &str) -> Result<Self, String> {
method add_constants (line 475) | fn add_constants(token_map: &mut TokenMap) {
method parse_value (line 487) | fn parse_value(value: &str) -> Result<Self, String> {
method default (line 504) | fn default() -> Self {
FILE: crates/common/src/config/smtp/mod.rs
type SmtpConfig (line 26) | pub struct SmtpConfig {
method parse (line 154) | pub async fn parse(config: &mut Config) -> Self {
type QueueRateLimiter (line 36) | pub struct QueueRateLimiter {
constant THROTTLE_RCPT (line 43) | pub const THROTTLE_RCPT: u16 = 1 << 0;
constant THROTTLE_RCPT_DOMAIN (line 44) | pub const THROTTLE_RCPT_DOMAIN: u16 = 1 << 1;
constant THROTTLE_SENDER (line 45) | pub const THROTTLE_SENDER: u16 = 1 << 2;
constant THROTTLE_SENDER_DOMAIN (line 46) | pub const THROTTLE_SENDER_DOMAIN: u16 = 1 << 3;
constant THROTTLE_AUTH_AS (line 47) | pub const THROTTLE_AUTH_AS: u16 = 1 << 4;
constant THROTTLE_LISTENER (line 48) | pub const THROTTLE_LISTENER: u16 = 1 << 5;
constant THROTTLE_MX (line 49) | pub const THROTTLE_MX: u16 = 1 << 6;
constant THROTTLE_REMOTE_IP (line 50) | pub const THROTTLE_REMOTE_IP: u16 = 1 << 7;
constant THROTTLE_LOCAL_IP (line 51) | pub const THROTTLE_LOCAL_IP: u16 = 1 << 8;
constant THROTTLE_HELO_DOMAIN (line 52) | pub const THROTTLE_HELO_DOMAIN: u16 = 1 << 9;
constant RCPT_DOMAIN_VARS (line 54) | pub(crate) const RCPT_DOMAIN_VARS: &[u32; 1] = &[V_RECIPIENT_DOMAIN];
constant SMTP_EHLO_VARS (line 56) | pub(crate) const SMTP_EHLO_VARS: &[u32; 10] = &[
constant SMTP_MAIL_FROM_VARS (line 68) | pub(crate) const SMTP_MAIL_FROM_VARS: &[u32; 12] = &[
constant SMTP_RCPT_TO_VARS (line 82) | pub(crate) const SMTP_RCPT_TO_VARS: &[u32; 17] = &[
constant SMTP_QUEUE_HOST_VARS (line 101) | pub(crate) const SMTP_QUEUE_HOST_VARS: &[u32; 20] = &[
constant SMTP_QUEUE_RCPT_VARS (line 123) | pub(crate) const SMTP_QUEUE_RCPT_VARS: &[u32; 17] = &[
constant SMTP_QUEUE_SENDER_VARS (line 142) | pub(crate) const SMTP_QUEUE_SENDER_VARS: &[u32; 8] = &[
FILE: crates/common/src/config/smtp/queue.rs
type QueueName (line 39) | pub struct QueueName([u8; 8]);
method new (line 912) | pub fn new(name: impl AsRef<[u8]>) -> Option<Self> {
method from_bytes (line 923) | pub fn from_bytes(name: &[u8]) -> Option<Self> {
method as_str (line 927) | pub fn as_str(&self) -> &str {
method into_inner (line 933) | pub fn into_inner(self) -> [u8; 8] {
method as_slice (line 937) | pub fn as_slice(&self) -> &[u8] {
method as_ref (line 985) | fn as_ref(&self) -> &[u8] {
constant DEFAULT_QUEUE_NAME (line 41) | pub const DEFAULT_QUEUE_NAME: QueueName = QueueName([b'd', b'e', b'f', b...
type QueueConfig (line 44) | pub struct QueueConfig {
method parse (line 250) | pub fn parse(config: &mut Config) -> Self {
type RoutingStrategy (line 68) | pub enum RoutingStrategy {
type MxConfig (line 75) | pub struct MxConfig {
type Dsn (line 82) | pub struct Dsn {
type VirtualQueue (line 89) | pub struct VirtualQueue {
type QueueStrategy (line 94) | pub struct QueueStrategy {
type QueueExpiry (line 112) | pub enum QueueExpiry {
type TlsStrategy (line 118) | pub struct TlsStrategy {
method try_dane (line 855) | pub fn try_dane(&self) -> bool {
method try_start_tls (line 863) | pub fn try_start_tls(&self) -> bool {
method is_dane_required (line 871) | pub fn is_dane_required(&self) -> bool {
method try_mta_sts (line 876) | pub fn try_mta_sts(&self) -> bool {
method is_mta_sts_required (line 884) | pub fn is_mta_sts_required(&self) -> bool {
method is_tls_required (line 889) | pub fn is_tls_required(&self) -> bool {
type ConnectionStrategy (line 129) | pub struct ConnectionStrategy {
type IpAndHost (line 143) | pub struct IpAndHost {
type QueueRateLimiters (line 149) | pub struct QueueRateLimiters {
type QueueQuotas (line 156) | pub struct QueueQuotas {
type QueueQuota (line 163) | pub struct QueueQuota {
type RelayConfig (line 172) | pub struct RelayConfig {
method fmt (line 842) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type RequireOptional (line 182) | pub enum RequireOptional {
type Error (line 765) | type Error = ();
method try_from (line 767) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
method default (line 190) | fn default() -> Self {
function parse_queue_strategies (line 293) | fn parse_queue_strategies(
function parse_queue_strategy (line 315) | fn parse_queue_strategy(
function parse_virtual_queues (line 373) | fn parse_virtual_queues(config: &mut Config) -> AHashMap<QueueName, Virt...
function parse_virtual_queue (line 390) | fn parse_virtual_queue(config: &mut Config, id: &str) -> Option<VirtualQ...
function parse_routing_strategies (line 398) | fn parse_routing_strategies(config: &mut Config) -> AHashMap<String, Rou...
function parse_route (line 408) | fn parse_route(config: &mut Config, id: &str) -> Option<RoutingStrategy> {
function parse_tls_strategies (line 456) | fn parse_tls_strategies(config: &mut Config) -> AHashMap<String, TlsStra...
function parse_tls (line 475) | fn parse_tls(config: &mut Config, id: &str) -> Option<TlsStrategy> {
function parse_connection_strategies (line 498) | fn parse_connection_strategies(config: &mut Config) -> AHashMap<String, ...
function parse_connection (line 519) | fn parse_connection(config: &mut Config, id: &str) -> Option<ConnectionS...
function parse_inbound_rate_limiters (line 561) | fn parse_inbound_rate_limiters(config: &mut Config) -> QueueRateLimiters {
function parse_outbound_rate_limiters (line 608) | fn parse_outbound_rate_limiters(config: &mut Config) -> QueueRateLimiters {
function parse_queue_quota (line 646) | fn parse_queue_quota(config: &mut Config) -> QueueQuotas {
function parse_queue_quota_item (line 680) | fn parse_queue_quota_item(config: &mut Config, prefix: impl AsKey, id: &...
method parse_value (line 754) | fn parse_value(value: &str) -> Result<Self, String> {
method from (line 778) | fn from(value: RequireOptional) -> Self {
method add_constants (line 788) | fn add_constants(token_map: &mut crate::expr::tokenizer::TokenMap) {
type Error (line 801) | type Error = ();
method try_from (line 803) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
method from (line 821) | fn from(value: IpLookupStrategy) -> Self {
method add_constants (line 832) | fn add_constants(token_map: &mut crate::expr::tokenizer::TokenMap) {
method hash (line 897) | fn hash<H: Hasher>(&self, state: &mut H) {
method eq (line 904) | fn eq(&self, other: &Self) -> bool {
method as_str (line 943) | pub fn as_str(&self) -> &str {
method as_slice (line 949) | pub fn as_slice(&self) -> &[u8] {
method default (line 955) | fn default() -> Self {
method parse_value (line 961) | fn parse_value(value: &str) -> Result<Self, String> {
method fmt (line 973) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 979) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/common/src/config/smtp/report.rs
type ReportConfig (line 16) | pub struct ReportConfig {
method parse (line 71) | pub fn parse(config: &mut Config) -> Self {
type ReportAnalysis (line 28) | pub struct ReportAnalysis {
type AddressMatch (line 35) | pub enum AddressMatch {
type AggregateReport (line 42) | pub struct AggregateReport {
method parse (line 155) | pub fn parse(config: &mut Config, id: &str, token_map: &TokenMap) -> S...
type Report (line 53) | pub struct Report {
method parse (line 115) | pub fn parse(config: &mut Config, id: &str, token_map: &TokenMap) -> S...
type AggregateFrequency (line 62) | pub enum AggregateFrequency {
type Error (line 240) | type Error = ();
method try_from (line 242) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
method default (line 211) | fn default() -> Self {
method parse_value (line 217) | fn parse_value(value: &str) -> Result<Self, String> {
method from (line 229) | fn from(value: AggregateFrequency) -> Self {
method add_constants (line 254) | fn add_constants(token_map: &mut crate::expr::tokenizer::TokenMap) {
method parse_value (line 270) | fn parse_value(value: &str) -> Result<Self, String> {
FILE: crates/common/src/config/smtp/resolver.rs
type Resolvers (line 31) | pub struct Resolvers {
method parse (line 105) | pub async fn parse(config: &mut Config) -> Self {
type DnssecResolver (line 37) | pub struct DnssecResolver {
type TlsaEntry (line 42) | pub struct TlsaEntry {
type Tlsa (line 50) | pub struct Tlsa {
type Mode (line 58) | pub enum Mode {
type MxPattern (line 67) | pub enum MxPattern {
type Policy (line 73) | pub struct Policy {
method try_parse (line 248) | pub fn try_parse(config: &mut Config) -> Option<Self> {
method try_build (line 281) | pub fn try_build<I, T>(mut self, names: I) -> Option<Self>
method hash (line 308) | fn hash(&self) -> u64 {
method weight (line 81) | fn weight(&self) -> u64 {
method weight (line 91) | fn weight(&self) -> u64 {
method build_mta_sts_policy (line 318) | pub fn build_mta_sts_policy(&self) -> Option<Policy> {
method parse_value (line 342) | fn parse_value(value: &str) -> Result<Self, String> {
method default (line 353) | fn default() -> Self {
method fmt (line 378) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 401) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method clone (line 413) | fn clone(&self) -> Self {
FILE: crates/common/src/config/smtp/session.rs
type SessionConfig (line 33) | pub struct SessionConfig {
method parse (line 193) | pub fn parse(config: &mut Config) -> Self {
type Connect (line 52) | pub struct Connect {
type Ehlo (line 59) | pub struct Ehlo {
type Extensions (line 66) | pub struct Extensions {
type Auth (line 80) | pub struct Auth {
type Mail (line 90) | pub struct Mail {
type Rcpt (line 97) | pub struct Rcpt {
type AddressMapping (line 116) | pub enum AddressMapping {
type Data (line 124) | pub struct Data {
type Milter (line 144) | pub struct Milter {
type MilterVersion (line 164) | pub enum MilterVersion {
type MTAHook (line 170) | pub struct MTAHook {
type Stage (line 183) | pub enum Stage {
function parse_milter (line 451) | fn parse_milter(config: &mut Config, id: &str, token_map: &TokenMap) -> ...
function parse_hooks (line 518) | fn parse_hooks(config: &mut Config, id: &str, token_map: &TokenMap) -> O...
function parse_stages (line 592) | fn parse_stages(config: &mut Config, prefix: &str, id: &str) -> AHashSet...
method default (line 627) | fn default() -> Self {
type Mechanism (line 803) | pub struct Mechanism(u64);
type Error (line 856) | type Error = ();
method try_from (line 858) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
method from (line 901) | fn from(value: u64) -> Self {
method parse_value (line 806) | fn parse_value(value: &str) -> Result<Self, String> {
method from (line 879) | fn from(value: Mechanism) -> Self {
method add_constants (line 885) | fn add_constants(token_map: &mut crate::expr::tokenizer::TokenMap) {
function from (line 895) | fn from(value: Mechanism) -> Self {
type Error (line 907) | type Error = ();
method try_from (line 909) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
method from (line 924) | fn from(value: MtPriority) -> Self {
method add_constants (line 934) | fn add_constants(token_map: &mut TokenMap) {
FILE: crates/common/src/config/smtp/throttle.rs
function parse_queue_rate_limiter (line 13) | pub fn parse_queue_rate_limiter(
function parse_queue_rate_limiter_item (line 37) | fn parse_queue_rate_limiter_item(
function parse_queue_rate_limiter_key (line 87) | pub(crate) fn parse_queue_rate_limiter_key(value: &str) -> Result<u16, S...
FILE: crates/common/src/config/spamfilter.rs
type SpamClassifier (line 23) | pub enum SpamClassifier {
method is_active (line 558) | pub fn is_active(&self) -> bool {
type SpamFilterConfig (line 37) | pub struct SpamFilterConfig {
method parse (line 177) | pub async fn parse(config: &mut Config) -> Self {
type SpamFilterScoreConfig (line 52) | pub struct SpamFilterScoreConfig {
method parse (line 564) | pub fn parse(config: &mut Config) -> Self {
type DnsBlConfig (line 59) | pub struct DnsBlConfig {
method parse (line 266) | pub fn parse(config: &mut Config) -> Self {
type SpamFilterLists (line 68) | pub struct SpamFilterLists {
method parse (line 325) | pub fn parse(config: &mut Config) -> Self {
type SpamFilterAction (line 74) | pub enum SpamFilterAction<T> {
type ClassifierConfig (line 82) | pub struct ClassifierConfig {
method parse (line 455) | pub fn parse(config: &mut Config) -> Option<Self> {
type FtrlParameters (line 99) | pub struct FtrlParameters {
method parse (line 527) | pub fn parse(config: &mut Config, prefix: &str, default_features: usiz...
type PyzorConfig (line 108) | pub struct PyzorConfig {
method parse (line 400) | pub async fn parse(config: &mut Config) -> Option<Self> {
type SpamFilterRules (line 117) | pub struct SpamFilterRules {
method parse (line 203) | pub fn parse(config: &mut Config) -> SpamFilterRules {
type FileExtension (line 128) | pub struct FileExtension {
type Element (line 136) | pub enum Element {
method token_map (line 689) | pub fn token_map(&self) -> TokenMap {
method as_str (line 782) | pub fn as_str(&self) -> &'static str {
type Location (line 148) | pub enum Location {
method as_str (line 595) | pub fn as_str(&self) -> &'static str {
type DnsBlServer (line 169) | pub struct DnsBlServer {
method parse (line 293) | pub fn parse(config: &mut Config, id: String) -> Option<Self> {
type SpamFilterRule (line 230) | struct SpamFilterRule {
method parse (line 237) | pub fn parse(config: &mut Config, id: String) -> Option<Self> {
method parse_value (line 580) | fn parse_value(value: &str) -> utils::config::Result<Self> {
constant V_SPAM_REMOTE_IP (line 618) | pub const V_SPAM_REMOTE_IP: u32 = 100;
constant V_SPAM_REMOTE_IP_PTR (line 619) | pub const V_SPAM_REMOTE_IP_PTR: u32 = 101;
constant V_SPAM_EHLO_DOMAIN (line 620) | pub const V_SPAM_EHLO_DOMAIN: u32 = 102;
constant V_SPAM_AUTH_AS (line 621) | pub const V_SPAM_AUTH_AS: u32 = 103;
constant V_SPAM_ASN (line 622) | pub const V_SPAM_ASN: u32 = 104;
constant V_SPAM_COUNTRY (line 623) | pub const V_SPAM_COUNTRY: u32 = 105;
constant V_SPAM_IS_TLS (line 624) | pub const V_SPAM_IS_TLS: u32 = 106;
constant V_SPAM_ENV_FROM (line 625) | pub const V_SPAM_ENV_FROM: u32 = 108;
constant V_SPAM_ENV_FROM_LOCAL (line 626) | pub const V_SPAM_ENV_FROM_LOCAL: u32 = 109;
constant V_SPAM_ENV_FROM_DOMAIN (line 627) | pub const V_SPAM_ENV_FROM_DOMAIN: u32 = 110;
constant V_SPAM_ENV_TO (line 628) | pub const V_SPAM_ENV_TO: u32 = 111;
constant V_SPAM_FROM (line 629) | pub const V_SPAM_FROM: u32 = 112;
constant V_SPAM_FROM_NAME (line 630) | pub const V_SPAM_FROM_NAME: u32 = 113;
constant V_SPAM_FROM_LOCAL (line 631) | pub const V_SPAM_FROM_LOCAL: u32 = 114;
constant V_SPAM_FROM_DOMAIN (line 632) | pub const V_SPAM_FROM_DOMAIN: u32 = 115;
constant V_SPAM_REPLY_TO (line 633) | pub const V_SPAM_REPLY_TO: u32 = 116;
constant V_SPAM_REPLY_TO_NAME (line 634) | pub const V_SPAM_REPLY_TO_NAME: u32 = 117;
constant V_SPAM_REPLY_TO_LOCAL (line 635) | pub const V_SPAM_REPLY_TO_LOCAL: u32 = 118;
constant V_SPAM_REPLY_TO_DOMAIN (line 636) | pub const V_SPAM_REPLY_TO_DOMAIN: u32 = 119;
constant V_SPAM_TO (line 637) | pub const V_SPAM_TO: u32 = 120;
constant V_SPAM_TO_NAME (line 638) | pub const V_SPAM_TO_NAME: u32 = 121;
constant V_SPAM_TO_LOCAL (line 639) | pub const V_SPAM_TO_LOCAL: u32 = 122;
constant V_SPAM_TO_DOMAIN (line 640) | pub const V_SPAM_TO_DOMAIN: u32 = 123;
constant V_SPAM_CC (line 641) | pub const V_SPAM_CC: u32 = 124;
constant V_SPAM_CC_NAME (line 642) | pub const V_SPAM_CC_NAME: u32 = 125;
constant V_SPAM_CC_LOCAL (line 643) | pub const V_SPAM_CC_LOCAL: u32 = 126;
constant V_SPAM_CC_DOMAIN (line 644) | pub const V_SPAM_CC_DOMAIN: u32 = 127;
constant V_SPAM_BCC (line 645) | pub const V_SPAM_BCC: u32 = 128;
constant V_SPAM_BCC_NAME (line 646) | pub const V_SPAM_BCC_NAME: u32 = 129;
constant V_SPAM_BCC_LOCAL (line 647) | pub const V_SPAM_BCC_LOCAL: u32 = 130;
constant V_SPAM_BCC_DOMAIN (line 648) | pub const V_SPAM_BCC_DOMAIN: u32 = 131;
constant V_SPAM_BODY_TEXT (line 649) | pub const V_SPAM_BODY_TEXT: u32 = 132;
constant V_SPAM_BODY_HTML (line 650) | pub const V_SPAM_BODY_HTML: u32 = 133;
constant V_SPAM_BODY_RAW (line 651) | pub const V_SPAM_BODY_RAW: u32 = 134;
constant V_SPAM_SUBJECT (line 652) | pub const V_SPAM_SUBJECT: u32 = 135;
constant V_SPAM_SUBJECT_THREAD (line 653) | pub const V_SPAM_SUBJECT_THREAD: u32 = 136;
constant V_SPAM_LOCATION (line 654) | pub const V_SPAM_LOCATION: u32 = 137;
constant V_WORDS_SUBJECT (line 655) | pub const V_WORDS_SUBJECT: u32 = 138;
constant V_WORDS_BODY (line 656) | pub const V_WORDS_BODY: u32 = 139;
constant V_RCPT_EMAIL (line 658) | pub const V_RCPT_EMAIL: u32 = 0;
constant V_RCPT_NAME (line 659) | pub const V_RCPT_NAME: u32 = 1;
constant V_RCPT_LOCAL (line 660) | pub const V_RCPT_LOCAL: u32 = 2;
constant V_RCPT_DOMAIN (line 661) | pub const V_RCPT_DOMAIN: u32 = 3;
constant V_RCPT_DOMAIN_SLD (line 662) | pub const V_RCPT_DOMAIN_SLD: u32 = 4;
constant V_URL_FULL (line 664) | pub const V_URL_FULL: u32 = 0;
constant V_URL_PATH_QUERY (line 665) | pub const V_URL_PATH_QUERY: u32 = 1;
constant V_URL_PATH (line 666) | pub const V_URL_PATH: u32 = 2;
constant V_URL_QUERY (line 667) | pub const V_URL_QUERY: u32 = 3;
constant V_URL_SCHEME (line 668) | pub const V_URL_SCHEME: u32 = 4;
constant V_URL_AUTHORITY (line 669) | pub const V_URL_AUTHORITY: u32 = 5;
constant V_URL_HOST (line 670) | pub const V_URL_HOST: u32 = 6;
constant V_URL_HOST_SLD (line 671) | pub const V_URL_HOST_SLD: u32 = 7;
constant V_URL_PORT (line 672) | pub const V_URL_PORT: u32 = 8;
constant V_HEADER_NAME (line 674) | pub const V_HEADER_NAME: u32 = 0;
constant V_HEADER_NAME_LOWER (line 675) | pub const V_HEADER_NAME_LOWER: u32 = 1;
constant V_HEADER_VALUE (line 676) | pub const V_HEADER_VALUE: u32 = 2;
constant V_HEADER_VALUE_LOWER (line 677) | pub const V_HEADER_VALUE_LOWER: u32 = 3;
constant V_HEADER_PROPERTY (line 678) | pub const V_HEADER_PROPERTY: u32 = 4;
constant V_HEADER_RAW (line 679) | pub const V_HEADER_RAW: u32 = 5;
constant V_HEADER_RAW_LOWER (line 680) | pub const V_HEADER_RAW_LOWER: u32 = 6;
constant V_IP (line 682) | pub const V_IP: u32 = 0;
constant V_IP_REVERSE (line 683) | pub const V_IP_REVERSE: u32 = 1;
constant V_IP_OCTETS (line 684) | pub const V_IP_OCTETS: u32 = 2;
constant V_IP_IS_V4 (line 685) | pub const V_IP_IS_V4: u32 = 3;
constant V_IP_IS_V6 (line 686) | pub const V_IP_IS_V6: u32 = 4;
type IpResolver (line 795) | pub struct IpResolver {
method new (line 820) | pub fn new(ip: IpAddr) -> Self {
method resolve_variable (line 803) | fn resolve_variable(&self, variable: u32) -> Variable<'_> {
method resolve_global (line 814) | fn resolve_global(&self, _: &str) -> Variable<'_> {
method weight (line 842) | fn weight(&self) -> u64 {
function as_score (line 848) | pub fn as_score(&self) -> Option<&T> {
FILE: crates/common/src/config/storage.rs
type Storage (line 16) | pub struct Storage {
FILE: crates/common/src/config/telemetry.rs
type TelemetrySubscriber (line 26) | pub struct TelemetrySubscriber {
type TelemetrySubscriberType (line 35) | pub enum TelemetrySubscriberType {
type OtelTracer (line 51) | pub struct OtelTracer {
type OtelMetrics (line 60) | pub struct OtelMetrics {
method fmt (line 892) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type ConsoleTracer (line 68) | pub struct ConsoleTracer {
type LogTracer (line 75) | pub struct LogTracer {
type WebhookTracer (line 84) | pub struct WebhookTracer {
type StoreTracer (line 99) | pub struct StoreTracer {
type RotationStrategy (line 105) | pub enum RotationStrategy {
type Telemetry (line 113) | pub struct Telemetry {
method parse (line 138) | pub fn parse(config: &mut Config, stores: &Stores) -> Self {
type Tracers (line 119) | pub struct Tracers {
method parse (line 163) | pub fn parse(config: &mut Config, stores: &Stores) -> Self {
type Metrics (line 126) | pub struct Metrics {
method parse (line 598) | pub fn parse(config: &mut Config) -> Self {
type PrometheusMetrics (line 133) | pub struct PrometheusMetrics {
function parse_webhook (line 745) | fn parse_webhook(
type EventOrMany (line 805) | enum EventOrMany {
function apply_events (line 812) | fn apply_events(
method parse_value (line 877) | fn parse_value(value: &str) -> Result<Self, String> {
FILE: crates/common/src/core.rs
method store (line 52) | pub fn store(&self) -> &Store {
method blob_store (line 57) | pub fn blob_store(&self) -> &BlobStore {
method search_store (line 62) | pub fn search_store(&self) -> &SearchStore {
method in_memory_store (line 67) | pub fn in_memory_store(&self) -> &InMemoryStore {
method directory (line 72) | pub fn directory(&self) -> &Directory {
method get_directory (line 76) | pub fn get_directory(&self, name: &str) -> Option<&Arc<Directory>> {
method get_directory_or_default (line 80) | pub fn get_directory_or_default(&self, name: &str, session_id: u64) -> &...
method get_in_memory_store (line 94) | pub fn get_in_memory_store(&self, name: &str) -> Option<&InMemoryStore> {
method get_in_memory_store_or_default (line 98) | pub fn get_in_memory_store_or_default(&self, name: &str, session_id: u64...
method get_data_store (line 112) | pub fn get_data_store(&self, name: &str, session_id: u64) -> &Store {
method get_arc_sealer (line 126) | pub fn get_arc_sealer(&self, name: &str, session_id: u64) -> Option<Arc<...
method get_dkim_signer (line 138) | pub fn get_dkim_signer(&self, name: &str, session_id: u64) -> Option<Arc...
method resolve_signature (line 150) | fn resolve_signature(&self, name: &str) -> Option<ResolvedSignature> {
method get_trusted_sieve_script (line 173) | pub fn get_trusted_sieve_script(&self, name: &str, session_id: u64) -> O...
method get_untrusted_sieve_script (line 185) | pub fn get_untrusted_sieve_script(&self, name: &str, session_id: u64) ->...
method get_route_or_default (line 197) | pub fn get_route_or_default(&self, name: &str, session_id: u64) -> &Rout...
method get_virtual_queue_or_default (line 224) | pub fn get_virtual_queue_or_default(&self, name: &QueueName) -> &Virtual...
method get_queue_or_default (line 244) | pub fn get_queue_or_default(&self, name: &str, session_id: u64) -> &Queu...
method get_tls_or_default (line 281) | pub fn get_tls_or_default(&self, name: &str, session_id: u64) -> &TlsStr...
method get_connection_or_default (line 309) | pub fn get_connection_or_default(&self, name: &str, session_id: u64) -> ...
method get_used_quota (line 341) | pub async fn get_used_quota(&self, account_id: u32) -> trc::Result<i64> {
method has_available_quota (line 350) | pub async fn has_available_quota(
method get_resource_token (line 389) | pub async fn get_resource_token(
method archives (line 448) | pub async fn archives<I, CB>(
method all_archives (line 497) | pub async fn all_archives<CB>(
method document_ids (line 543) | pub async fn document_ids(
method document_exists (line 577) | pub async fn document_exists(
method document_ids_matching (line 619) | pub async fn document_ids_matching(
method notify_task_queue (line 664) | pub fn notify_task_queue(&self) {
method total_queued_messages (line 668) | pub async fn total_queued_messages(&self) -> trc::Result<u64> {
method generate_snowflake_id (line 689) | pub fn generate_snowflake_id(&self) -> u64 {
method commit_batch (line 693) | pub async fn commit_batch(&self, mut builder: BatchBuilder) -> trc::Resu...
method delete_changes (line 737) | pub async fn delete_changes(
method broadcast_push_notification (line 866) | pub async fn broadcast_push_notification(&self, notification: PushNotifi...
method cluster_broadcast (line 891) | pub async fn cluster_broadcast(&self, event: BroadcastEvent) {
method put_jmap_blob (line 904) | pub async fn put_jmap_blob(&self, account_id: u32, data: &[u8]) -> trc::...
method put_temporary_blob (line 971) | pub async fn put_temporary_blob(
method total_accounts (line 1033) | pub async fn total_accounts(&self) -> trc::Result<u64> {
method total_domains (line 1040) | pub async fn total_domains(&self) -> trc::Result<u64> {
method spam_model_reload (line 1047) | pub async fn spam_model_reload(&self) -> trc::Result<()> {
method logo_resource (line 1071) | pub async fn logo_resource(
type BuildServer (line 1079) | pub trait BuildServer {
method build_server (line 1080) | fn build_server(&self) -> Server;
method build_server (line 1084) | fn build_server(&self) -> Server {
FILE: crates/common/src/dns.rs
method dns_exists_mx (line 14) | pub async fn dns_exists_mx(&self, entry: &str) -> trc::Result<bool> {
method dns_exists_ip (line 29) | pub async fn dns_exists_ip(&self, entry: &str) -> trc::Result<bool> {
method dns_exists_ptr (line 50) | pub async fn dns_exists_ptr(&self, entry: &str) -> trc::Result<bool> {
method dns_exists_ipv4 (line 69) | pub async fn dns_exists_ipv4(&self, entry: &str) -> trc::Result<bool> {
method dns_exists_ipv6 (line 84) | pub async fn dns_exists_ipv6(&self, entry: &str) -> trc::Result<bool> {
FILE: crates/common/src/enterprise/alerts.rs
type AlertMessage (line 28) | pub struct AlertMessage {
type CollectorResolver (line 34) | struct CollectorResolver;
method process_alerts (line 37) | pub async fn process_alerts(&self) -> Option<Vec<AlertMessage>> {
method resolve_variable (line 111) | fn resolve_variable(&self, variable: u32) -> Variable<'_> {
method resolve_global (line 123) | fn resolve_global(&self, _: &str) -> Variable<'_> {
method build (line 129) | pub fn build(&self) -> String {
method len (line 138) | pub fn len(&self) -> usize {
method write (line 144) | fn write(&self, buf: &mut String) {
method len (line 156) | fn len(&self) -> usize {
FILE: crates/common/src/enterprise/config.rs
method parse (line 34) | pub async fn parse(
method parse (line 240) | pub fn parse(config: &mut Config, models: &AHashMap<String, Arc<AiApiCon...
function parse_metric_alerts (line 301) | pub fn parse_metric_alerts(config: &mut Config) -> Vec<MetricAlert> {
function parse_metric_alert (line 313) | fn parse_metric_alert(config: &mut Config, id: String) -> Option<MetricA...
function parse_alert_content (line 420) | fn parse_alert_content(key: impl AsKey, config: &mut Config) -> Option<A...
function sanitize_metric_name (line 474) | fn sanitize_metric_name(name: &str) -> String {
FILE: crates/common/src/enterprise/license.rs
constant LICENSING_API (line 34) | const LICENSING_API: &str = "https://license.stalw.art/api/license/";
constant RENEW_THRESHOLD (line 35) | const RENEW_THRESHOLD: u64 = 60 * 60 * 24 * 4;
type LicenseValidator (line 37) | pub struct LicenseValidator {
method new (line 71) | pub fn new() -> Self {
method try_parse (line 83) | pub fn try_parse(&self, key: impl AsRef<str>) -> Result<LicenseKey, Li...
type LicenseKey (line 42) | pub struct LicenseKey {
method new (line 154) | pub fn new(
method invalid (line 174) | pub fn invalid(domain: impl AsRef<str>) -> Self {
method try_renew (line 183) | pub async fn try_renew(&self, api_key: &str) -> Result<RenewedLicense,...
method is_near_expiration (line 230) | pub fn is_near_expiration(&self) -> bool {
method expires_in (line 235) | pub fn expires_in(&self) -> Duration {
method renew_in (line 239) | pub fn renew_in(&self) -> Duration {
method is_expired (line 243) | pub fn is_expired(&self) -> bool {
method base_domain (line 248) | pub fn base_domain(domain: impl AsRef<str>) -> Result<String, LicenseE...
type LicenseError (line 50) | pub enum LicenseError {
type RenewedLicense (line 61) | pub struct RenewedLicense {
constant U64_LEN (line 66) | const U64_LEN: usize = std::mem::size_of::<u64>();
constant U32_LEN (line 67) | const U32_LEN: usize = std::mem::size_of::<u32>();
method fmt (line 259) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
FILE: crates/common/src/enterprise/llm.rs
type AiApiConfig (line 17) | pub struct AiApiConfig {
method send_request (line 87) | pub async fn send_request(
method post_api (line 100) | async fn post_api(
method parse (line 202) | pub fn parse(config: &mut Config, id: &str) -> Option<Self> {
type ApiType (line 29) | pub enum ApiType {
type ChatCompletionRequest (line 35) | pub struct ChatCompletionRequest {
type Message (line 42) | pub struct Message {
type ChatCompletionResponse (line 48) | pub struct ChatCompletionResponse {
type ChatCompletionChoice (line 57) | pub struct ChatCompletionChoice {
type TextCompletionRequest (line 64) | pub struct TextCompletionRequest {
type TextCompletionResponse (line 71) | pub struct TextCompletionResponse {
type TextCompletionChoice (line 80) | pub struct TextCompletionChoice {
FILE: crates/common/src/enterprise/mod.rs
type Enterprise (line 36) | pub struct Enterprise {
type SpamFilterLlmConfig (line 51) | pub struct SpamFilterLlmConfig {
type Undelete (line 64) | pub struct Undelete {
type TraceStore (line 69) | pub struct TraceStore {
type MetricStore (line 75) | pub struct MetricStore {
type MetricAlert (line 82) | pub struct MetricAlert {
type AlertMethod (line 89) | pub enum AlertMethod {
type AlertContent (line 103) | pub struct AlertContent(pub Vec<AlertContentToken>);
type AlertContentToken (line 106) | pub enum AlertContentToken {
method is_enterprise_edition (line 113) | pub fn is_enterprise_edition(&self) -> bool {
method is_enterprise_edition (line 131) | pub fn is_enterprise_edition(&self) -> bool {
method licensed_accounts (line 135) | pub fn licensed_accounts(&self) -> u32 {
method log_license_details (line 142) | pub fn log_license_details(&self) {
method can_create_account (line 156) | pub async fn can_create_account(&self) -> trc::Result<bool> {
method logo_resource (line 180) | pub async fn logo_resource(&self, domain: &str) -> trc::Result<Option<Re...
method default_logo_url (line 267) | fn default_logo_url(&self) -> Option<String> {
FILE: crates/common/src/enterprise/undelete.rs
type DeletedBlob (line 19) | pub struct DeletedBlob {
type DeletedItem (line 26) | pub struct DeletedItem {
type DeletedItemType (line 33) | pub enum DeletedItemType {
method list_deleted (line 55) | pub async fn list_deleted(&self, account_id: u32) -> trc::Result<Vec<Del...
FILE: crates/common/src/expr/eval.rs
method eval_if (line 23) | pub async fn eval_if<'x, R: TryFrom<Variable<'x>>, V: ResolveVariable>(
method eval_expr (line 85) | pub async fn eval_expr<'x, R: TryFrom<Variable<'x>>, V: ResolveVariable>(
type EvalContext (line 142) | struct EvalContext<'x, V: ResolveVariable, T, C> {
function eval (line 151) | async fn eval(&mut self) -> trc::Result<Variable<'x>> {
function eval (line 189) | async fn eval(&mut self) -> trc::Result<Variable<'x>> {
method is_empty (line 325) | pub fn is_empty(&self) -> bool {
method items (line 329) | pub fn items(&self) -> &[ExpressionItem] {
function op_add (line 335) | pub fn op_add(self, other: Variable<'x>) -> Variable<'x> {
function op_subtract (line 367) | pub fn op_subtract(self, other: Variable<'x>) -> Variable<'x> {
function op_multiply (line 380) | pub fn op_multiply(self, other: Variable<'x>) -> Variable<'x> {
function op_divide (line 390) | pub fn op_divide(self, other: Variable<'x>) -> Variable<'x> {
function op_and (line 408) | pub fn op_and(self, other: Variable) -> Variable {
function op_or (line 412) | pub fn op_or(self, other: Variable) -> Variable {
function op_xor (line 416) | pub fn op_xor(self, other: Variable) -> Variable {
function op_eq (line 420) | pub fn op_eq(self, other: Variable) -> Variable {
function op_ne (line 424) | pub fn op_ne(self, other: Variable) -> Variable {
function op_lt (line 428) | pub fn op_lt(self, other: Variable) -> Variable {
function op_le (line 432) | pub fn op_le(self, other: Variable) -> Variable {
function op_gt (line 436) | pub fn op_gt(self, other: Variable) -> Variable {
function op_ge (line 440) | pub fn op_ge(self, other: Variable) -> Variable {
function op_not (line 444) | pub fn op_not(self) -> Variable<'static> {
function op_minus (line 448) | pub fn op_minus(self) -> Variable<'static> {
function parse_number (line 456) | pub fn parse_number(&self) -> Variable<'static> {
function array (line 475) | fn array(num_items: usize) -> Vec<Variable<'static>> {
function to_ref (line 483) | pub fn to_ref<'y: 'x>(&'y self) -> Variable<'x> {
function to_bool (line 492) | pub fn to_bool(&self) -> bool {
function to_string (line 501) | pub fn to_string(&'_ self) -> StringCow<'_> {
function into_string (line 524) | pub fn into_string(self) -> StringCow<'x> {
function to_integer (line 547) | pub fn to_integer(&self) -> Option<i64> {
function to_usize (line 556) | pub fn to_usize(&self) -> Option<usize> {
function len (line 565) | pub fn len(&self) -> usize {
function is_empty (line 573) | pub fn is_empty(&self) -> bool {
function as_array (line 580) | pub fn as_array(&'_ self) -> Option<&'_ [Variable<'_>]> {
function into_array (line 587) | pub fn into_array(self) -> Vec<Variable<'x>> {
function to_array (line 595) | pub fn to_array(&self) -> Vec<Variable<'_>> {
function into_owned (line 603) | pub fn into_owned(self) -> Variable<'static> {
method eq (line 614) | fn eq(&self, other: &Self) -> bool {
method partial_cmp (line 634) | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
method cmp (line 655) | fn cmp(&self, other: &Self) -> std::cmp::Ordering {
method fmt (line 661) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
function from (line 680) | fn from(value: &'x Constant) -> Self {
type Error (line 690) | type Error = ();
method try_from (line 692) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 705) | type Error = ();
method try_from (line 707) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
function from (line 720) | fn from(val: Variable<'x>) -> Self {
type Error (line 726) | type Error = ();
function try_from (line 728) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 734) | type Error = ();
function try_from (line 736) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 742) | type Error = ();
function try_from (line 744) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 750) | type Error = ();
method try_from (line 752) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
FILE: crates/common/src/expr/functions/array.rs
function fn_count (line 9) | pub(crate) fn fn_count(v: Vec<Variable>) -> Variable {
function fn_sort (line 23) | pub(crate) fn fn_sort(mut v: Vec<Variable>) -> Variable {
function fn_dedup (line 34) | pub(crate) fn fn_dedup(mut v: Vec<Variable>) -> Variable {
function fn_is_intersect (line 47) | pub(crate) fn fn_is_intersect(v: Vec<Variable>) -> Variable {
function fn_winnow (line 56) | pub(crate) fn fn_winnow(mut v: Vec<Variable>) -> Variable {
FILE: crates/common/src/expr/functions/asynch.rs
method eval_fnc (line 20) | pub(crate) async fn eval_fnc<'x>(
method sql_query (line 111) | async fn sql_query<'x>(
method dns_query (line 173) | async fn dns_query<'x>(&self, mut arguments: FncParams<'x>) -> trc::Resu...
type FncParams (line 289) | struct FncParams<'x> {
function new (line 294) | pub fn new(params: Vec<Variable<'x>>) -> Self {
function next_as_string (line 300) | pub fn next_as_string(&mut self) -> StringCow<'x> {
function next_as_integer (line 304) | pub fn next_as_integer(&mut self) -> i64 {
function next (line 308) | pub fn next(&mut self) -> Variable<'x> {
type VariableWrapper (line 314) | struct VariableWrapper(Variable<'static>);
method from (line 317) | fn from(value: i64) -> Self {
method from (line 331) | fn from(value: store::Value<'static>) -> Self {
method into_inner (line 347) | pub fn into_inner(self) -> Variable<'static> {
method deserialize (line 323) | fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
function to_store_value (line 352) | fn to_store_value(value: Variable) -> Value {
function into_variable (line 361) | fn into_variable(value: Value) -> Variable {
FILE: crates/common/src/expr/functions/email.rs
function fn_is_email (line 11) | pub(crate) fn fn_is_email(v: Vec<Variable>) -> Variable {
function fn_email_part (line 81) | pub(crate) fn fn_email_part(v: Vec<Variable>) -> Variable {
FILE: crates/common/src/expr/functions/misc.rs
function fn_is_empty (line 14) | pub(crate) fn fn_is_empty(v: Vec<Variable>) -> Variable {
function fn_is_number (line 23) | pub(crate) fn fn_is_number(v: Vec<Variable>) -> Variable {
function fn_is_ip_addr (line 27) | pub(crate) fn fn_is_ip_addr(v: Vec<Variable>) -> Variable {
function fn_is_ipv4_addr (line 35) | pub(crate) fn fn_is_ipv4_addr(v: Vec<Variable>) -> Variable {
function fn_is_ipv6_addr (line 43) | pub(crate) fn fn_is_ipv6_addr(v: Vec<Variable>) -> Variable {
function fn_ip_reverse_name (line 51) | pub(crate) fn fn_ip_reverse_name(v: Vec<Variable>) -> Variable {
function fn_if_then (line 62) | pub(crate) fn fn_if_then(v: Vec<Variable>) -> Variable {
FILE: crates/common/src/expr/functions/mod.rs
type ResolveVariable (line 15) | pub trait ResolveVariable: Sync + Send {
method resolve_variable (line 16) | fn resolve_variable(&self, variable: u32) -> Variable<'_>;
method resolve_global (line 17) | fn resolve_global(&self, variable: &str) -> Variable<'_>;
function transform (line 21) | fn transform(self, f: impl Fn(StringCow<'x>) -> Variable<'x>) -> Variabl...
constant FUNCTIONS (line 38) | pub(crate) const FUNCTIONS: &[(&str, fn(Vec<Variable>) -> Variable, u32)...
constant F_IS_LOCAL_DOMAIN (line 84) | pub const F_IS_LOCAL_DOMAIN: u32 = 0;
constant F_IS_LOCAL_ADDRESS (line 85) | pub const F_IS_LOCAL_ADDRESS: u32 = 1;
constant F_KEY_GET (line 86) | pub const F_KEY_GET: u32 = 2;
constant F_KEY_EXISTS (line 87) | pub const F_KEY_EXISTS: u32 = 3;
constant F_KEY_SET (line 88) | pub const F_KEY_SET: u32 = 4;
constant F_COUNTER_INCR (line 89) | pub const F_COUNTER_INCR: u32 = 5;
constant F_COUNTER_GET (line 90) | pub const F_COUNTER_GET: u32 = 6;
constant F_SQL_QUERY (line 91) | pub const F_SQL_QUERY: u32 = 7;
constant F_DNS_QUERY (line 92) | pub const F_DNS_QUERY: u32 = 8;
constant ASYNC_FUNCTIONS (line 94) | pub const ASYNC_FUNCTIONS: &[(&str, u32, u32)] = &[
FILE: crates/common/src/expr/functions/text.rs
function fn_trim (line 13) | pub(crate) fn fn_trim(mut v: Vec<Variable>) -> Variable {
function fn_trim_end (line 20) | pub(crate) fn fn_trim_end(mut v: Vec<Variable>) -> Variable {
function fn_trim_start (line 27) | pub(crate) fn fn_trim_start(mut v: Vec<Variable>) -> Variable {
function fn_len (line 34) | pub(crate) fn fn_len(v: Vec<Variable>) -> Variable {
function fn_to_lowercase (line 43) | pub(crate) fn fn_to_lowercase(mut v: Vec<Variable>) -> Variable {
function fn_to_uppercase (line 48) | pub(crate) fn fn_to_uppercase(mut v: Vec<Variable>) -> Variable {
function fn_is_uppercase (line 53) | pub(crate) fn fn_is_uppercase(mut v: Vec<Variable>) -> Variable {
function fn_is_lowercase (line 63) | pub(crate) fn fn_is_lowercase(mut v: Vec<Variable>) -> Variable {
function fn_has_digits (line 73) | pub(crate) fn fn_has_digits(mut v: Vec<Variable>) -> Variable {
function fn_split_words (line 78) | pub(crate) fn fn_split_words(v: Vec<Variable>) -> Variable {
function fn_count_spaces (line 88) | pub(crate) fn fn_count_spaces(v: Vec<Variable>) -> Variable {
function fn_count_uppercase (line 97) | pub(crate) fn fn_count_uppercase(v: Vec<Variable>) -> Variable {
function fn_count_lowercase (line 106) | pub(crate) fn fn_count_lowercase(v: Vec<Variable>) -> Variable {
function fn_count_chars (line 115) | pub(crate) fn fn_count_chars(v: Vec<Variable>) -> Variable {
function fn_eq_ignore_case (line 119) | pub(crate) fn fn_eq_ignore_case(v: Vec<Variable>) -> Variable {
function fn_contains (line 126) | pub(crate) fn fn_contains(v: Vec<Variable>) -> Variable {
function fn_contains_ignore_case (line 135) | pub(crate) fn fn_contains_ignore_case(v: Vec<Variable>) -> Variable {
function fn_starts_with (line 151) | pub(crate) fn fn_starts_with(v: Vec<Variable>) -> Variable {
function fn_ends_with (line 158) | pub(crate) fn fn_ends_with(v: Vec<Variable>) -> Variable {
function fn_lines (line 165) | pub(crate) fn fn_lines(mut v: Vec<Variable>) -> Variable {
function fn_substring (line 177) | pub(crate) fn fn_substring(v: Vec<Variable>) -> Variable {
function fn_strip_prefix (line 187) | pub(crate) fn fn_strip_prefix(v: Vec<Variable>) -> Variable {
function fn_strip_suffix (line 204) | pub(crate) fn fn_strip_suffix(v: Vec<Variable>) -> Variable {
function fn_split (line 221) | pub(crate) fn fn_split(v: Vec<Variable>) -> Variable {
function fn_rsplit (line 240) | pub(crate) fn fn_rsplit(v: Vec<Variable>) -> Variable {
function fn_split_n (line 259) | pub(crate) fn fn_split_n(v: Vec<Variable>) -> Variable {
function fn_split_once (line 289) | pub(crate) fn fn_split_once(v: Vec<Variable>) -> Variable {
function fn_rsplit_once (line 311) | pub(crate) fn fn_rsplit_once(v: Vec<Variable>) -> Variable {
function fn_hash (line 333) | pub(crate) fn fn_hash(v: Vec<Variable>) -> Variable {
FILE: crates/common/src/expr/if_block.rs
type IfThen (line 19) | pub struct IfThen {
type IfBlock (line 25) | pub struct IfBlock {
method new (line 32) | pub fn new<T: ConstantValue>(
method empty (line 54) | pub fn empty(key: impl Into<String>) -> Self {
method is_empty (line 64) | pub fn is_empty(&self) -> bool {
method try_parse (line 96) | pub fn try_parse(
method into_default (line 217) | pub fn into_default(self, key: impl Into<String>) -> IfBlock {
method default_string (line 225) | pub fn default_string(&self) -> Option<&str> {
method into_default_string (line 235) | pub fn into_default_string(self) -> Option<CompactString> {
method try_parse (line 70) | pub fn try_parse(
method parse (line 88) | fn parse(token_map: &TokenMap, expr: &str) -> Self {
FILE: crates/common/src/expr/mod.rs
constant V_RECIPIENT (line 18) | pub const V_RECIPIENT: u32 = 0;
constant V_RECIPIENT_DOMAIN (line 19) | pub const V_RECIPIENT_DOMAIN: u32 = 1;
constant V_SENDER (line 20) | pub const V_SENDER: u32 = 2;
constant V_SENDER_DOMAIN (line 21) | pub const V_SENDER_DOMAIN: u32 = 3;
constant V_MX (line 22) | pub const V_MX: u32 = 4;
constant V_HELO_DOMAIN (line 23) | pub const V_HELO_DOMAIN: u32 = 5;
constant V_AUTHENTICATED_AS (line 24) | pub const V_AUTHENTICATED_AS: u32 = 6;
constant V_LISTENER (line 25) | pub const V_LISTENER: u32 = 7;
constant V_REMOTE_IP (line 26) | pub const V_REMOTE_IP: u32 = 8;
constant V_REMOTE_PORT (line 27) | pub const V_REMOTE_PORT: u32 = 9;
constant V_LOCAL_IP (line 28) | pub const V_LOCAL_IP: u32 = 10;
constant V_LOCAL_PORT (line 29) | pub const V_LOCAL_PORT: u32 = 11;
constant V_PRIORITY (line 30) | pub const V_PRIORITY: u32 = 12;
constant V_PROTOCOL (line 31) | pub const V_PROTOCOL: u32 = 13;
constant V_TLS (line 32) | pub const V_TLS: u32 = 14;
constant V_RECIPIENTS (line 33) | pub const V_RECIPIENTS: u32 = 15;
constant V_QUEUE_RETRY_NUM (line 34) | pub const V_QUEUE_RETRY_NUM: u32 = 16;
constant V_QUEUE_NOTIFY_NUM (line 35) | pub const V_QUEUE_NOTIFY_NUM: u32 = 17;
constant V_QUEUE_EXPIRES_IN (line 36) | pub const V_QUEUE_EXPIRES_IN: u32 = 18;
constant V_QUEUE_LAST_STATUS (line 37) | pub const V_QUEUE_LAST_STATUS: u32 = 19;
constant V_QUEUE_LAST_ERROR (line 38) | pub const V_QUEUE_LAST_ERROR: u32 = 20;
constant V_URL (line 39) | pub const V_URL: u32 = 21;
constant V_URL_PATH (line 40) | pub const V_URL_PATH: u32 = 22;
constant V_HEADERS (line 41) | pub const V_HEADERS: u32 = 23;
constant V_METHOD (line 42) | pub const V_METHOD: u32 = 24;
constant V_ASN (line 43) | pub const V_ASN: u32 = 25;
constant V_COUNTRY (line 44) | pub const V_COUNTRY: u32 = 26;
constant V_RECEIVED_VIA_PORT (line 45) | pub const V_RECEIVED_VIA_PORT: u32 = 27;
constant V_RECEIVED_FROM_IP (line 46) | pub const V_RECEIVED_FROM_IP: u32 = 28;
constant V_QUEUE_NAME (line 47) | pub const V_QUEUE_NAME: u32 = 29;
constant V_SOURCE (line 48) | pub const V_SOURCE: u32 = 30;
constant V_SIZE (line 49) | pub const V_SIZE: u32 = 31;
constant V_QUEUE_AGE (line 50) | pub const V_QUEUE_AGE: u32 = 32;
constant VARIABLES_MAP (line 52) | pub const VARIABLES_MAP: &[(&str, u32)] = &[
type Expression (line 95) | pub struct Expression {
method from (line 325) | fn from(value: T) -> Self {
type ExpressionItem (line 100) | pub enum ExpressionItem {
type Variable (line 116) | pub enum Variable<'x> {
type StringCow (line 124) | pub enum StringCow<'x> {
method default (line 130) | fn default() -> Self {
type Constant (line 136) | pub enum Constant {
method from (line 145) | fn from(value: CompactString) -> Self {
method from (line 151) | fn from(value: bool) -> Self {
method from (line 157) | fn from(value: i64) -> Self {
method from (line 163) | fn from(value: i32) -> Self {
method from (line 169) | fn from(value: i16) -> Self {
method from (line 175) | fn from(value: f64) -> Self {
method from (line 181) | fn from(value: usize) -> Self {
method from (line 408) | fn from(_: ()) -> Self {
method from (line 514) | fn from(value: Duration) -> Self {
type BinaryOperator (line 187) | pub enum BinaryOperator {
type UnaryOperator (line 206) | pub enum UnaryOperator {
type Token (line 212) | pub enum Token {
type Setting (line 234) | pub enum Setting {
method from (line 242) | fn from(value: CompactString) -> Self {
function from (line 253) | fn from(value: usize) -> Self {
function from (line 259) | fn from(value: i64) -> Self {
function from (line 265) | fn from(value: u64) -> Self {
function from (line 271) | fn from(value: i32) -> Self {
function from (line 277) | fn from(value: u32) -> Self {
function from (line 283) | fn from(value: u16) -> Self {
function from (line 289) | fn from(value: i16) -> Self {
function from (line 295) | fn from(value: f64) -> Self {
function from (line 301) | fn from(value: &'x str) -> Self {
function from (line 307) | fn from(value: CompactString) -> Self {
function from (line 313) | fn from(value: Vec<Variable<'x>>) -> Self {
function from (line 319) | fn from(value: bool) -> Self {
method eq (line 333) | fn eq(&self, other: &Self) -> bool {
method eq (line 369) | fn eq(&self, other: &Self) -> bool {
type NoConstants (line 395) | pub struct NoConstants;
type ConstantValue (line 397) | pub trait ConstantValue:
method add_constants (line 400) | fn add_constants(token_map: &mut TokenMap);
method add_constants (line 404) | fn add_constants(_: &mut TokenMap) {}
method add_constants (line 422) | fn add_constants(_: &mut TokenMap) {}
type Error (line 414) | type Error = ();
function try_from (line 416) | fn try_from(_: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 426) | type Error = ();
method try_from (line 428) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
function as_str (line 441) | pub fn as_str(&self) -> &str {
function as_bytes (line 448) | pub fn as_bytes(&self) -> &[u8] {
function is_empty (line 455) | pub fn is_empty(&self) -> bool {
function len (line 462) | pub fn len(&self) -> usize {
function into_owned (line 469) | pub fn into_owned(self) -> CompactString {
function from (line 478) | fn from(value: Cow<'x, str>) -> Self {
function from (line 487) | fn from(value: CompactString) -> Self {
function as_ref (line 493) | fn as_ref(&self) -> &str {
function as_ref (line 499) | fn as_ref(&self) -> &[u8] {
method fmt (line 505) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
type Error (line 520) | type Error = ();
method try_from (line 522) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 543) | type Error = ();
method try_from (line 545) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 554) | type Error = ();
method try_from (line 556) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 565) | type Error = ();
method try_from (line 567) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
type Error (line 579) | type Error = ();
function try_from (line 581) | fn try_from(value: Variable<'x>) -> Result<Self, Self::Error> {
FILE: crates/common/src/expr/parser.rs
type ExpressionParser (line 9) | pub struct ExpressionParser<'x> {
constant ID_ARRAY_ACCESS (line 16) | pub(crate) const ID_ARRAY_ACCESS: u32 = u32::MAX;
constant ID_ARRAY_BUILD (line 17) | pub(crate) const ID_ARRAY_BUILD: u32 = u32::MAX - 1;
function new (line 20) | pub fn new(tokenizer: Tokenizer<'x>) -> Self {
function parse (line 29) | pub fn parse(mut self) -> Result<Expression, String> {
function inc_arg_count (line 234) | fn inc_arg_count(&mut self) {
function dec_arg_count (line 247) | fn dec_arg_count(&mut self) {
function update_jmp_pos (line 253) | fn update_jmp_pos(&mut self, jmp_pos: Option<usize>) {
method precedence (line 267) | fn precedence(&self) -> i32 {
FILE: crates/common/src/expr/tokenizer.rs
type Tokenizer (line 18) | pub struct Tokenizer<'x> {
type TokenMap (line 32) | pub struct TokenMap {
method with_all_variables (line 348) | pub fn with_all_variables(self) -> Self {
method with_variables (line 381) | pub fn with_variables(mut self, variables: &[u32]) -> Self {
method with_variables_map (line 392) | pub fn with_variables_map<I, V>(mut self, vars: I) -> Self
method set_constants (line 404) | pub fn set_constants<I, T>(mut self, consts: I) -> Self
method with_constants (line 417) | pub fn with_constants<T: ConstantValue>(mut self) -> Self {
method add_constant (line 422) | pub fn add_constant(&mut self, name: &'static str, constant: impl Into...
function new (line 38) | pub fn new(expr: &'x str, token_map: &'x TokenMap) -> Self {
function next (line 54) | pub fn next(&mut self) -> Result<Option<Token>, String> {
function find_char (line 218) | fn find_char(&mut self, chars: &[u8]) -> Result<u8, String> {
function parse_string (line 236) | fn parse_string(&mut self, stop_ch: u8) -> Result<CompactString, String> {
function parse_buf (line 276) | fn parse_buf(&mut self) -> Result<Token, String> {
FILE: crates/common/src/i18n.rs
function locale_or_default (line 9) | pub fn locale_or_default(name: &str) -> &'static Locale {
function calendar_templates_include_minutes (line 20) | fn calendar_templates_include_minutes() {
FILE: crates/common/src/ipc.rs
type HousekeeperEvent (line 30) | pub enum HousekeeperEvent {
type PurgeType (line 40) | pub enum PurgeType {
type PushEvent (line 57) | pub enum PushEvent {
type PushNotification (line 79) | pub enum PushNotification {
method account_id (line 262) | pub fn account_id(&self) -> u32 {
method filter_types (line 270) | pub fn filter_types(&self, types: &Bitmap<DataType>) -> Option<PushNot...
type EmailPush (line 86) | pub struct EmailPush {
method to_state_change (line 312) | pub fn to_state_change(&self) -> StateChange {
type CalendarAlert (line 93) | pub struct CalendarAlert {
type BroadcastEvent (line 102) | pub enum BroadcastEvent {
type QueueEvent (line 113) | pub enum QueueEvent {
type QueueEventStatus (line 126) | pub enum QueueEventStatus {
type ReportingEvent (line 133) | pub enum ReportingEvent {
method from (line 216) | fn from(value: DmarcEvent) -> Self {
method from (line 222) | fn from(value: TlsEvent) -> Self {
type DmarcEvent (line 140) | pub struct DmarcEvent {
type TlsEvent (line 148) | pub struct TlsEvent {
type PolicyType (line 157) | pub enum PolicyType {
method from (line 228) | fn from(value: Arc<Tlsa>) -> Self {
method from (line 234) | fn from(value: Arc<Policy>) -> Self {
method from (line 240) | fn from(value: &Arc<Tlsa>) -> Self {
method from (line 246) | fn from(value: &Arc<Policy>) -> Self {
method from (line 252) | fn from(value: (&Option<Arc<Policy>>, &Option<Arc<Tlsa>>)) -> Self {
type TrainTaskController (line 163) | pub struct TrainTaskController {
method try_run (line 178) | pub fn try_run(&self) -> Option<SemaphorePermit<'_>> {
method is_running (line 186) | pub fn is_running(&self) -> bool {
method stop (line 190) | pub fn stop(&self) {
method should_stop (line 194) | pub fn should_stop(&self) -> bool {
method default (line 169) | fn default() -> Self {
type ToHash (line 199) | pub trait ToHash {
method to_hash (line 200) | fn to_hash(&self) -> u64;
method to_hash (line 204) | fn to_hash(&self) -> u64 {
method to_hash (line 210) | fn to_hash(&self) -> u64 {
FILE: crates/common/src/lib.rs
constant DATABASE_SCHEMA_VERSION (line 96) | pub const DATABASE_SCHEMA_VERSION: u32 = 5;
constant LONG_1D_SLUMBER (line 98) | pub const LONG_1D_SLUMBER: Duration = Duration::from_secs(60 * 60 * 24);
constant LONG_1Y_SLUMBER (line 99) | pub const LONG_1Y_SLUMBER: Duration = Duration::from_secs(60 * 60 * 24 *...
constant IPC_CHANNEL_BUFFER (line 101) | pub const IPC_CHANNEL_BUFFER: usize = 1024;
constant KV_ACME (line 103) | pub const KV_ACME: u8 = 0;
constant KV_OAUTH (line 104) | pub const KV_OAUTH: u8 = 1;
constant KV_RATE_LIMIT_RCPT (line 105) | pub const KV_RATE_LIMIT_RCPT: u8 = 2;
constant KV_RATE_LIMIT_SCAN (line 106) | pub const KV_RATE_LIMIT_SCAN: u8 = 3;
constant KV_RATE_LIMIT_LOITER (line 107) | pub const KV_RATE_LIMIT_LOITER: u8 = 4;
constant KV_RATE_LIMIT_AUTH (line 108) | pub const KV_RATE_LIMIT_AUTH: u8 = 5;
constant KV_RATE_LIMIT_SMTP (line 109) | pub const KV_RATE_LIMIT_SMTP: u8 = 6;
constant KV_RATE_LIMIT_CONTACT (line 110) | pub const KV_RATE_LIMIT_CONTACT: u8 = 7;
constant KV_RATE_LIMIT_HTTP_AUTHENTICATED (line 111) | pub const KV_RATE_LIMIT_HTTP_AUTHENTICATED: u8 = 8;
constant KV_RATE_LIMIT_HTTP_ANONYMOUS (line 112) | pub const KV_RATE_LIMIT_HTTP_ANONYMOUS: u8 = 9;
constant KV_RATE_LIMIT_IMAP (line 113) | pub const KV_RATE_LIMIT_IMAP: u8 = 10;
constant KV_GREYLIST (line 114) | pub const KV_GREYLIST: u8 = 16;
constant KV_LOCK_PURGE_ACCOUNT (line 115) | pub const KV_LOCK_PURGE_ACCOUNT: u8 = 20;
constant KV_LOCK_QUEUE_MESSAGE (line 116) | pub const KV_LOCK_QUEUE_MESSAGE: u8 = 21;
constant KV_LOCK_QUEUE_REPORT (line 117) | pub const KV_LOCK_QUEUE_REPORT: u8 = 22;
constant KV_LOCK_TASK (line 118) | pub const KV_LOCK_TASK: u8 = 23;
constant KV_LOCK_HOUSEKEEPER (line 119) | pub const KV_LOCK_HOUSEKEEPER: u8 = 24;
constant KV_LOCK_DAV (line 120) | pub const KV_LOCK_DAV: u8 = 25;
constant KV_SIEVE_ID (line 121) | pub const KV_SIEVE_ID: u8 = 26;
type Server (line 124) | pub struct Server {
type Inner (line 129) | pub struct Inner {
type Data (line 136) | pub struct Data {
type Caches (line 157) | pub struct Caches {
type CacheSwap (line 179) | pub struct CacheSwap<T>(pub Arc<ArcSwap<T>>);
type MessageStoreCache (line 182) | pub struct MessageStoreCache {
type MailboxesCache (line 191) | pub struct MailboxesCache {
type MessagesCache (line 199) | pub struct MessagesCache {
type MessageCache (line 208) | pub struct MessageCache {
type MessageUidCache (line 218) | pub struct MessageUidCache {
type MailboxCache (line 224) | pub struct MailboxCache {
method parent_id (line 909) | pub fn parent_id(&self) -> Option<u32> {
method sort_order (line 917) | pub fn sort_order(&self) -> Option<u32> {
method is_root (line 925) | pub fn is_root(&self) -> bool {
type HttpAuthCache (line 237) | pub struct HttpAuthCache {
type Ipc (line 243) | pub struct Ipc {
type TlsConnectors (line 253) | pub struct TlsConnectors {
type NameWrapper (line 258) | pub struct NameWrapper(pub String);
type DavResources (line 261) | pub struct DavResources {
method by_path (line 571) | pub fn by_path(&self, name: &str) -> Option<DavResourcePath<'_>> {
method container_resource_by_id (line 578) | pub fn container_resource_by_id(&self, id: u32) -> Option<&DavResource> {
method container_resource_path_by_id (line 584) | pub fn container_resource_path_by_id(&self, id: u32) -> Option<DavReso...
method any_resource_path_by_id (line 597) | pub fn any_resource_path_by_id(&self, id: u32) -> Option<DavResourcePa...
method subtree (line 610) | pub fn subtree(&self, search_path: &str) -> impl Iterator<Item = DavRe...
method subtree_with_depth (line 624) | pub fn subtree_with_depth(
method tree_with_depth (line 647) | pub fn tree_with_depth(&self, depth: usize) -> impl Iterator<Item = Da...
method children (line 660) | pub fn children(&self, parent_id: u32) -> impl Iterator<Item = DavReso...
method children_ids (line 670) | pub fn children_ids(&self, parent_id: u32) -> impl Iterator<Item = u32> {
method format_resource (line 677) | pub fn format_resource(&self, resource: DavResourcePath<'_>) -> String {
method format_collection (line 685) | pub fn format_collection(&self, name: &str) -> String {
method format_item (line 689) | pub fn format_item(&self, name: &str) -> String {
type DavPath (line 273) | pub struct DavPath {
method borrow (line 852) | fn borrow(&self) -> &str {
type DavResource (line 281) | pub struct DavResource {
method is_child_of (line 697) | pub fn is_child_of(&self, parent_id: u32) -> bool {
method parent_id (line 713) | pub fn parent_id(&self) -> Option<u32> {
method child_names (line 727) | pub fn child_names(&self) -> Option<&[DavName]> {
method container_name (line 738) | pub fn container_name(&self) -> Option<&str> {
method has_hierarchy_changes (line 754) | pub fn has_hierarchy_changes(&self, other: &DavResource) -> bool {
method event_time_range (line 792) | pub fn event_time_range(&self) -> Option<(i64, i64)> {
method calendar_preferences (line 801) | pub fn calendar_preferences(&self, account_id: u32) -> Option<&TinyCal...
method is_container (line 811) | pub fn is_container(&self) -> bool {
method size (line 820) | pub fn size(&self) -> Option<u32> {
method acls (line 827) | pub fn acls(&self) -> Option<&[AclGrant]> {
method hash (line 858) | fn hash<H: Hasher>(&self, state: &mut H) {
method borrow (line 872) | fn borrow(&self) -> &u32 {
type DavResourcePath (line 287) | pub struct DavResourcePath<'x> {
type DavResourceMetadata (line 293) | pub enum DavResourceMetadata {
type TinyCalendarPreferences (line 323) | pub struct TinyCalendarPreferences {
type DavName (line 333) | pub struct DavName {
method new (line 878) | pub fn new(name: String, parent_id: u32) -> Self {
method new_with_rand_name (line 882) | pub fn new_with_rand_name(parent_id: u32) -> Self {
type Core (line 339) | pub struct Core {
method weight (line 361) | fn weight(&self) -> u64 {
method weight (line 367) | fn weight(&self) -> u64 {
method weight (line 373) | fn weight(&self) -> u64 {
method weight (line 379) | fn weight(&self) -> u64 {
type IntoString (line 384) | pub trait IntoString: Sized {
method into_string (line 385) | fn into_string(self) -> String;
method into_string (line 389) | fn into_string(self) -> String {
type ThrottleKey (line 396) | pub struct ThrottleKey {
method hash (line 407) | fn hash<H: Hasher>(&self, state: &mut H) {
method as_ref (line 413) | fn as_ref(&self) -> &[u8] {
method eq (line 401) | fn eq(&self, other: &Self) -> bool {
type ThrottleKeyHasher (line 419) | pub struct ThrottleKeyHasher {
method finish (line 424) | fn finish(&self) -> u64 {
method write (line 428) | fn write(&mut self, bytes: &[u8]) {
type ThrottleKeyHasherBuilder (line 440) | pub struct ThrottleKeyHasherBuilder {}
type Hasher (line 443) | type Hasher = ThrottleKeyHasher;
method build_hasher (line 445) | fn build_hasher(&self) -> Self::Hasher {
method default (line 453) | fn default() -> Self {
method default (line 464) | fn default() -> Self {
method default (line 477) | fn default() -> Self {
method default (line 501) | fn default() -> Self {
function ip_to_bytes (line 514) | pub fn ip_to_bytes(ip: &IpAddr) -> Vec<u8> {
function ip_to_bytes_prefix (line 521) | pub fn ip_to_bytes_prefix(prefix: u8, ip: &IpAddr) -> Vec<u8> {
function document_id (line 540) | pub fn document_id(&self) -> u32 {
function parent_id (line 545) | pub fn parent_id(&self) -> Option<u32> {
function path (line 550) | pub fn path(&self) -> &str {
function is_container (line 555) | pub fn is_container(&self) -> bool {
function hierarchy_seq (line 560) | pub fn hierarchy_seq(&self) -> u32 {
function size (line 565) | pub fn size(&self) -> u32 {
constant SCHEDULE_INBOX_ID (line 694) | const SCHEDULE_INBOX_ID: u32 = u32::MAX - 1;
method hash (line 838) | fn hash<H: Hasher>(&self, state: &mut H) {
method eq (line 844) | fn eq(&self, other: &Self) -> bool {
method eq (line 864) | fn eq(&self, other: &Self) -> bool {
function new (line 895) | pub fn new(value: Arc<T>) -> Self {
function load_full (line 899) | pub fn load_full(&self) -> Arc<T> {
function update (line 903) | pub fn update(&self, value: Arc<T>) {
constant DEFAULT_LOGO_RAW (line 930) | pub const DEFAULT_LOGO_RAW: &str = r#"<svg xmlns="http://www.w3.org/2000...
constant DEFAULT_LOGO_BASE64 (line 940) | pub const DEFAULT_LOGO_BASE64: &str =
FILE: crates/common/src/listener/acme/cache.rs
method load_cert (line 16) | pub(crate) async fn load_cert(&self, provider: &AcmeProvider) -> trc::Re...
method store_cert (line 25) | pub(crate) async fn store_cert(&self, provider: &AcmeProvider, cert: &[u...
method load_account (line 34) | pub(crate) async fn load_account(
method store_account (line 46) | pub(crate) async fn store_account(
method read_if_exists (line 64) | async fn read_if_exists(
method write (line 91) | async fn write(
method build_key (line 111) | fn build_key(&self, provider: &AcmeProvider, class: &str, _: &[String]) ...
FILE: crates/common/src/listener/acme/directory.rs
constant LETS_ENCRYPT_STAGING_DIRECTORY (line 23) | pub const LETS_ENCRYPT_STAGING_DIRECTORY: &str =
constant LETS_ENCRYPT_PRODUCTION_DIRECTORY (line 25) | pub const LETS_ENCRYPT_PRODUCTION_DIRECTORY: &str =
constant ACME_TLS_ALPN_NAME (line 27) | pub const ACME_TLS_ALPN_NAME: &[u8] = b"acme-tls/1";
type Account (line 30) | pub struct Account {
method generate_key_pair (line 49) | pub fn generate_key_pair() -> Vec<u8> {
method create (line 56) | pub async fn create(directory: Directory, provider: &AcmeProvider) -> ...
method create_with_keypair (line 60) | pub async fn create_with_keypair(
method request (line 105) | async fn request(
method new_order (line 126) | pub async fn new_order(&self, domains: Vec<String>) -> trc::Result<(St...
method auth (line 145) | pub async fn auth(&self, url: impl AsRef<str>) -> trc::Result<Auth> {
method challenge (line 151) | pub async fn challenge(&self, url: impl AsRef<str>) -> trc::Result<()> {
method order (line 155) | pub async fn order(&self, url: impl AsRef<str>) -> trc::Result<Order> {
method finalize (line 161) | pub async fn finalize(&self, url: impl AsRef<str>, csr: Vec<u8>) -> tr...
method certificate (line 168) | pub async fn certificate(&self, url: impl AsRef<str>) -> trc::Result<S...
method http_proof (line 172) | pub fn http_proof(&self, challenge: &Challenge) -> trc::Result<Vec<u8>> {
method dns_proof (line 176) | pub fn dns_proof(&self, challenge: &Challenge) -> trc::Result<String> {
method tls_alpn_key (line 180) | pub fn tls_alpn_key(&self, challenge: &Challenge, domain: String) -> t...
type NewAccountPayload (line 37) | pub struct NewAccountPayload<'x> {
type SerializedCert (line 207) | pub struct SerializedCert {
type Directory (line 214) | pub struct Directory {
method discover (line 221) | pub async fn discover(url: impl AsRef<str>) -> trc::Result<Self> {
method nonce (line 231) | pub async fn nonce(&self) -> trc::Result<String> {
type ChallengeType (line 240) | pub enum ChallengeType {
method as_str (line 366) | pub fn as_str(&self) -> &'static str {
type Order (line 253) | pub struct Order {
type OrderStatus (line 263) | pub enum OrderStatus {
type Auth (line 273) | pub struct Auth {
type AuthStatus (line 282) | pub enum AuthStatus {
method as_str (line 377) | pub fn as_str(&self) -> &'static str {
type Identifier (line 293) | pub enum Identifier {
type Challenge (line 298) | pub struct Challenge {
type Problem (line 308) | pub struct Problem {
function https (line 315) | async fn https(
function get_header (line 352) | fn get_header(response: &Response, header: &'static str) -> trc::Result<...
FILE: crates/common/src/listener/acme/jose.rs
function sign (line 11) | pub(crate) fn sign(
function eab_sign (line 41) | pub(crate) fn eab_sign(
function key_authorization (line 62) | pub(crate) fn key_authorization(key: &EcdsaKeyPair, token: &str) -> trc:...
function key_authorization_sha256 (line 70) | pub(crate) fn key_authorization_sha256(key: &EcdsaKeyPair, token: &str) ...
function key_authorization_sha256_base64 (line 74) | pub(crate) fn key_authorization_sha256_base64(
type Body (line 82) | pub(crate) struct Body {
type Protected (line 89) | struct Protected<'a> {
function encode (line 101) | fn encode(
type Jwk (line 121) | struct Jwk {
method new (line 132) | pub(crate) fn new(key: &EcdsaKeyPair) -> Self {
method base64 (line 144) | pub(crate) fn base64(&self) -> trc::Result<String> {
method thumb_sha256_base64 (line 150) | pub(crate) fn thumb_sha256_base64(&self) -> trc::Result<String> {
type JwkThumb (line 165) | struct JwkThumb<'a> {
FILE: crates/common/src/listener/acme/mod.rs
type AcmeProvider (line 23) | pub struct AcmeProvider {
method new (line 60) | pub fn new(
type EabSettings (line 36) | pub struct EabSettings {
type ChallengeSettings (line 42) | pub enum ChallengeSettings {
method challenge_type (line 130) | pub fn challenge_type(&self) -> ChallengeType {
type StaticResolver (line 54) | pub struct StaticResolver {
method init_acme (line 94) | pub async fn init_acme(&self, provider: &AcmeProvider) -> trc::Result<Du...
method has_acme_tls_providers (line 112) | pub fn has_acme_tls_providers(&self) -> bool {
method has_acme_http_providers (line 120) | pub fn has_acme_http_providers(&self) -> bool {
method fmt (line 140) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method clone (line 146) | fn clone(&self) -> Self {
FILE: crates/common/src/listener/acme/order.rs
method process_cert (line 26) | pub(crate) async fn process_cert(
method renew (line 58) | pub async fn renew(&self, provider: &AcmeProvider) -> trc::Result<Durati...
method order (line 87) | async fn order(&self, provider: &AcmeProvider) -> trc::Result<Vec<u8>> {
method authorize (line 173) | async fn authorize(
function parse_cert (line 395) | fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime<Utc>; ...
FILE: crates/common/src/listener/acme/resolver.rs
method set_cert (line 27) | pub(crate) fn set_cert(&self, provider: &AcmeProvider, cert: Arc<Certifi...
method build_acme_certificate (line 48) | pub(crate) async fn build_acme_certificate(&self, domain: &str) -> Optio...
method resolve (line 102) | fn resolve(&self, _: ClientHello) -> Option<Arc<CertifiedKey>> {
function build_acme_static_resolver (line 107) | pub(crate) fn build_acme_static_resolver(key: Option<Arc<CertifiedKey>>)...
type IsTlsAlpnChallenge (line 115) | pub trait IsTlsAlpnChallenge {
method is_tls_alpn_challenge (line 116) | fn is_tls_alpn_challenge(&self) -> bool;
method is_tls_alpn_challenge (line 120) | fn is_tls_alpn_challenge(&self) -> bool {
FILE: crates/common/src/listener/asn.rs
type AsnGeoLookupData (line 21) | pub struct AsnGeoLookupData {
type AsnData (line 29) | pub struct AsnData {
type AsnGeoLookupResult (line 35) | pub struct AsnGeoLookupResult {
type Data (line 40) | struct Data<T> {
type IpRange (line 45) | pub struct IpRange<I: Ord, T> {
method lookup_asn_country (line 52) | pub async fn lookup_asn_country(&self, ip: IpAddr) -> AsnGeoLookupResult {
method refresh_asn_geo_tables (line 138) | fn refresh_asn_geo_tables(&self) {
function new (line 316) | fn new() -> Self {
function lookup (line 323) | pub fn lookup(&self, ip: IpAddr) -> Option<&T> {
function insert (line 358) | pub fn insert(&mut self, from_ip: IpAddr, to_ip: IpAddr, data: T) -> bool {
function sorted (line 380) | pub fn sorted(mut self) -> Self {
function is_empty (line 386) | pub fn is_empty(&self) -> bool {
method default (line 392) | fn default() -> Self {
FILE: crates/common/src/listener/blocked.rs
type Security (line 25) | pub struct Security {
method parse (line 52) | pub fn parse(config: &mut Config) -> Self {
constant BLOCKED_IP_KEY (line 41) | pub const BLOCKED_IP_KEY: &str = "server.blocked-ip";
constant BLOCKED_IP_PREFIX (line 42) | pub const BLOCKED_IP_PREFIX: &str = "server.blocked-ip.";
constant ALLOWED_IP_KEY (line 43) | pub const ALLOWED_IP_KEY: &str = "server.allowed-ip";
constant ALLOWED_IP_PREFIX (line 44) | pub const ALLOWED_IP_PREFIX: &str = "server.allowed-ip.";
type BlockedIps (line 46) | pub struct BlockedIps {
method parse (line 283) | pub fn parse(config: &mut Config) -> Self {
method is_rcpt_fail2banned (line 140) | pub async fn is_rcpt_fail2banned(&self, ip: IpAddr, rcpt: &str) -> trc::...
method is_scanner_fail2banned (line 162) | pub async fn is_scanner_fail2banned(&self, ip: IpAddr) -> trc::Result<bo...
method is_http_banned_path (line 179) | pub async fn is_http_banned_path(&self, path: &str, ip: IpAddr) -> trc::...
method is_loiter_fail2banned (line 189) | pub async fn is_loiter_fail2banned(&self, ip: IpAddr) -> trc::Result<boo...
method is_auth_fail2banned (line 206) | pub async fn is_auth_fail2banned(&self, ip: IpAddr, login: Option<&str>)...
method block_ip (line 229) | pub async fn block_ip(&self, ip: IpAddr) -> trc::Result<()> {
method has_auth_fail2ban (line 253) | pub fn has_auth_fail2ban(&self) -> bool {
method is_ip_blocked (line 257) | pub fn is_ip_blocked(&self, ip: &IpAddr) -> bool {
method is_ip_allowed (line 269) | pub fn is_ip_allowed(&self, ip: &IpAddr) -> bool {
method default (line 314) | fn default() -> Self {
FILE: crates/common/src/listener/limiter.rs
type ConcurrencyLimiter (line 13) | pub struct ConcurrencyLimiter {
method new (line 36) | pub fn new(max_concurrent: u64) -> Self {
method is_allowed (line 43) | pub fn is_allowed(&self) -> LimiterResult {
method check_is_allowed (line 55) | pub fn check_is_allowed(&self) -> bool {
method is_active (line 59) | pub fn is_active(&self) -> bool {
type InFlight (line 19) | pub struct InFlight {
method num_concurrent (line 65) | pub fn num_concurrent(&self) -> u64 {
type LimiterResult (line 23) | pub enum LimiterResult {
method drop (line 30) | fn drop(&mut self) {
function from (line 71) | fn from(result: LimiterResult) -> Self {
FILE: crates/common/src/listener/listen.rs
method spawn (line 32) | pub fn spawn(
type BuildSession (line 199) | trait BuildSession {
method build_session (line 200) | fn build_session<T: SessionStream>(
method build_session (line 210) | fn build_session<T: SessionStream>(
type SocketOpts (line 266) | pub struct SocketOpts {
method apply (line 273) | pub fn apply(&self, stream: &TcpStream) {
method bind_and_drop_priv (line 304) | pub fn bind_and_drop_priv(&self, config: &mut Config) {
method spawn (line 334) | pub fn spawn(
method listen (line 353) | pub fn listen(self) -> Result<tokio::net::TcpListener, String> {
method tls_accept (line 361) | pub async fn tls_accept<T: SessionStream>(
FILE: crates/common/src/listener/mod.rs
type ServerInstance (line 36) | pub struct ServerInstance {
type TcpAcceptor (line 47) | pub enum TcpAcceptor {
type TcpAcceptorResult (line 58) | pub enum TcpAcceptorResult<IO>
type SessionData (line 67) | pub struct SessionData<T: SessionStream> {
type SessionStream (line 79) | pub trait SessionStream: AsyncRead + AsyncWrite + Unpin + 'static + Sync...
method is_tls (line 80) | fn is_tls(&self) -> bool;
method tls_version_and_cipher (line 81) | fn tls_version_and_cipher(&self) -> (Cow<'static, str>, Cow<'static, s...
type SessionResult (line 85) | pub enum SessionResult {
type SessionManager (line 91) | pub trait SessionManager: Sync + Send + 'static + Clone {
method spawn (line 92) | fn spawn<T: SessionStream>(
method handle (line 216) | fn handle<T: SessionStream>(
method shutdown (line 221) | fn shutdown(&self) -> impl std::future::Future<Output = ()> + Send;
method resolve_variable (line 225) | fn resolve_variable(&self, variable: u32) -> crate::expr::Variable<'_> {
method resolve_global (line 238) | fn resolve_global(&self, _: &str) -> Variable<'_> {
method fmt (line 244) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/common/src/listener/stream.rs
method is_tls (line 19) | fn is_tls(&self) -> bool {
method tls_version_and_cipher (line 23) | fn tls_version_and_cipher(&self) -> (Cow<'static, str>, Cow<'static, str...
method is_tls (line 29) | fn is_tls(&self) -> bool {
method tls_version_and_cipher (line 33) | fn tls_version_and_cipher(&self) -> (Cow<'static, str>, Cow<'static, str...
method is_tls (line 68) | fn is_tls(&self) -> bool {
method tls_version_and_cipher (line 74) | fn tls_version_and_cipher(&self) -> (Cow<'static, str>, Cow<'static, str...
type NullIo (line 88) | pub struct NullIo {
method poll_write (line 93) | fn poll_write(
method poll_flush (line 102) | fn poll_flush(
method poll_shutdown (line 109) | fn poll_shutdown(
method poll_read (line 118) | fn poll_read(
method is_tls (line 128) | fn is_tls(&self) -> bool {
method tls_version_and_cipher (line 132) | fn tls_version_and_cipher(
FILE: crates/common/src/listener/tls.rs
type AcmeProviders (line 37) | pub struct AcmeProviders {
type CertificateResolver (line 42) | pub struct CertificateResolver {
method new (line 47) | pub fn new(inner: Arc<Inner>) -> Self {
method resolve_certificate (line 59) | pub(crate) fn resolve_certificate(&self, name: Option<&str>) -> Option...
method fmt (line 208) | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
method resolve (line 53) | fn resolve(&self, hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
method accept (line 103) | pub async fn accept<IO>(
method is_tls (line 190) | pub fn is_tls(&self) -> bool {
function unwrap_tls (line 199) | pub fn unwrap_tls(self) -> Accept<IO> {
FILE: crates/common/src/manager/backup.rs
constant MAGIC_MARKER (line 22) | pub(super) const MAGIC_MARKER: u8 = 123;
type Family (line 25) | pub(super) enum Family {
method subspaces (line 308) | pub fn subspaces(&self) -> &'static [u8] {
method parse (line 328) | pub fn parse(family: &str) -> Result<Self, String> {
type TaskHandle (line 37) | type TaskHandle = (tokio::task::JoinHandle<()>, std::thread::JoinHandle<...
type BackupParams (line 40) | pub struct BackupParams {
method new (line 278) | pub fn new(dest: PathBuf) -> Self {
method parse_families (line 291) | fn parse_families(&mut self, families: &str) {
method backup (line 46) | pub async fn backup(&self, mut params: BackupParams) {
method backup_blobs (line 102) | fn backup_blobs(&self, dest: &Path, subspace: u8, schema_version: u32) -...
method backup_subspace (line 162) | fn backup_subspace(&self, dest: &Path, subspace: u8, schema_version: u32...
function spawn_writer (line 239) | fn spawn_writer(
FILE: crates/common/src/manager/boot.rs
type BootManager (line 40) | pub struct BootManager {
method init (line 182) | pub async fn init() -> Self {
type IpcReceivers (line 47) | pub struct IpcReceivers {
constant HELP (line 55) | const HELP: &str = concat!(
type StoreOp (line 74) | enum StoreOp {
constant DEFAULT_SETTINGS (line 81) | pub const DEFAULT_SETTINGS: &[(&str, &str)] = &[
function build_ipc (line 553) | pub fn build_ipc(has_pubsub: bool) -> (Ipc, IpcReceivers) {
function quickstart (line 580) | fn quickstart(path: impl Into<PathBuf>) {
constant QUICKSTART_CONFIG (line 618) | const QUICKSTART_CONFIG: &str = r#"[server.listener.smtp]
constant QUICKSTART_CONFIG (line 693) | const QUICKSTART_CONFIG: &str = r#"[server.listener.smtp]
FILE: crates/common/src/manager/config.rs
type ConfigManager (line 27) | pub struct ConfigManager {
method build_config (line 60) | pub async fn build_config(&self, prefix: &str) -> trc::Result<Config> {
method extend_config (line 71) | pub(crate) async fn extend_config(&self, config: &mut Config, prefix: ...
method get (line 79) | pub async fn get(&self, key: impl AsRef<str>) -> trc::Result<Option<St...
method list (line 93) | pub async fn list(
method group (line 110) | pub async fn group(
method db_list (line 136) | pub async fn db_list(
method set (line 176) | pub async fn set<I, T>(&self, keys: I, overwrite: bool) -> trc::Result...
method clear (line 226) | pub async fn clear(&self, key: impl AsRef<str>) -> trc::Result<()> {
method clear_prefix (line 243) | pub async fn clear_prefix(&self, key: impl AsRef<str>) -> trc::Result<...
method update_local (line 269) | async fn update_local(&self, map: BTreeMap<String, String>) -> trc::Re...
method update_spam_rules (line 332) | pub async fn update_spam_rules(
method fetch_spam_rules (line 405) | pub(crate) async fn fetch_spam_rules(&self) -> Result<ExternalSpamRule...
method get_services (line 446) | pub async fn get_services(&self) -> trc::Result<Vec<(String, u16, bool...
type Patterns (line 35) | pub struct Patterns {
method parse (line 493) | pub fn parse(config: &mut Config) -> Self {
method is_local_key (line 554) | pub fn is_local_key(&self, key: &str) -> bool {
type Pattern (line 40) | enum Pattern {
type MatchType (line 46) | pub enum MatchType {
method parse (line 577) | pub fn parse(value: &str) -> Self {
method matches (line 591) | pub fn matches(&self, value: &str) -> bool {
type ExternalSpamRules (line 54) | pub(crate) struct ExternalSpamRules {
method clone (line 603) | fn clone(&self) -> Self {
FILE: crates/common/src/manager/console.rs
constant HELP (line 14) | const HELP: &str = concat!(
function store_console (line 23) | pub async fn store_console(store: Store) {
function parse_key (line 220) | fn parse_key(input: &str) -> Option<Vec<u8>> {
function parse_value (line 234) | fn parse_value(input: &str) -> Vec<u8> {
function base64_decode (line 242) | fn base64_decode(input: &str) -> Vec<u8> {
function parse_binary (line 248) | fn parse_binary(input: &str) -> Vec<u8> {
function print_escaped (line 286) | fn print_escaped(bytes: &[u8]) {
function print_help (line 296) | fn print_help() {
type RawValue (line 308) | struct RawValue(Vec<u8>);
method deserialize (line 311) | fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
FILE: crates/common/src/manager/mod.rs
constant DEFAULT_SPAMFILTER_URL (line 21) | const DEFAULT_SPAMFILTER_URL: &str =
constant WEBADMIN_KEY (line 23) | pub const WEBADMIN_KEY: &[u8] = "STALWART_WEBADMIN".as_bytes();
constant SPAM_TRAINER_KEY (line 24) | pub const SPAM_TRAINER_KEY: &[u8] = "STALWART_SPAM_TRAIN_DATA.lz4".as_by...
constant SPAM_CLASSIFIER_KEY (line 25) | pub const SPAM_CLASSIFIER_KEY: &[u8] = "STALWART_SPAM_CLASSIFIER_MODEL.l...
constant DEFAULT_WEBADMIN_URL (line 31) | const DEFAULT_WEBADMIN_URL: &str =
constant DEFAULT_WEBADMIN_URL (line 36) | const DEFAULT_WEBADMIN_URL: &str =
method fetch_resource (line 40) | pub async fn fetch_resource(&self, resource_id: &str) -> Result<Vec<u8>,...
constant MAX_SIZE (line 75) | const MAX_SIZE: usize = 100 * 1024 * 1024;
function fetch_resource (line 77) | pub async fn fetch_resource(
function is_localhost_url (line 117) | pub fn is_localhost_url(url: &str) -> bool {
FILE: crates/common/src/manager/reload.rs
type ReloadResult (line 23) | pub struct ReloadResult {
method from (line 144) | fn from(config: Config) -> Self {
method reload_blocked_ips (line 30) | pub async fn reload_blocked_ips(&self) -> trc::Result<ReloadResult> {
method reload_certificates (line 42) | pub async fn reload_certificates(&self) -> trc::Result<ReloadResult> {
method reload_lookups (line 53) | pub async fn reload_lookups(&self) -> trc::Result<ReloadResult> {
method reload (line 70) | pub async fn reload(&self) -> trc::Result<ReloadResult> {
FILE: crates/common/src/manager/restore.rs
method restore (line 23) | pub async fn restore(&self, src: PathBuf) {
function restore_file (line 49) | async fn restore_file(store: Store, blob_store: BlobStore, path: &Path) {
type KeyValueReader (line 146) | struct KeyValueReader {
method new (line 152) | fn new(path: &Path) -> Self {
method next (line 182) | fn next(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
method read_size (line 194) | fn read_size(&mut self) -> Option<u32> {
method expect_sized_bytes (line 219) | fn expect_sized_bytes(&mut self) -> Vec<u8> {
FILE: crates/common/src/manager/webadmin.rs
type WebAdminManager (line 21) | pub struct WebAdminManager {
method new (line 42) | pub fn new(base_path: PathBuf) -> Self {
method get (line 49) | pub async fn get(&self, path: &str) -> trc::Result<Resource<Vec<u8>>> {
method unpack (line 69) | pub async fn unpack(&self, blob_store: &BlobStore) -> trc::Result<()> {
method update (line 146) | pub async fn update(&self, core: &Core) -> trc::Result<()> {
method update_and_unpack (line 161) | pub async fn update_and_unpack(&self, core: &Core) -> trc::Result<()> {
type Resource (line 27) | pub struct Resource<T> {
function new (line 33) | pub fn new(content_type: impl Into<Cow<'static, str>>, contents: T) -> S...
function is_empty (line 168) | pub fn is_empty(&self) -> bool {
type TempDir (line 173) | pub struct TempDir {
method new (line 178) | pub fn new(path: PathBuf) -> TempDir {
method clean (line 184) | pub async fn clean(&self) -> io::Result<()> {
function unpack_error (line 192) | fn unpack_error(err: std::io::Error) -> trc::Error {
method default (line 199) | fn default() -> Self {
method default (line 205) | fn default() -> Self {
method drop (line 211) | fn drop(&mut self) {
FILE: crates/common/src/scripts/functions/array.rs
function fn_count (line 11) | pub fn fn_count<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_sort (line 25) | pub fn fn_sort<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_dedup (line 36) | pub fn fn_dedup<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_cosine_similarity (line 49) | pub fn fn_cosine_similarity<'x>(_: &'x Context<'x>, v: Vec<Variable>) ->...
function cosine_similarity (line 85) | pub fn cosine_similarity(a: &[&str], b: &[&str]) -> f64 {
function fn_jaccard_similarity (line 111) | pub fn fn_jaccard_similarity<'x>(_: &'x Context<'x>, v: Vec<Variable>) -...
function fn_is_intersect (line 140) | pub fn fn_is_intersect<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_winnow (line 149) | pub fn fn_winnow<'x>(_: &'x Context<'x>, mut v: Vec<Variable>) -> Variab...
FILE: crates/common/src/scripts/functions/email.rs
function fn_is_email (line 11) | pub fn fn_is_email<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_email_part (line 81) | pub fn fn_email_part<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variab...
FILE: crates/common/src/scripts/functions/header.rs
function fn_received_part (line 12) | pub fn fn_received_part<'x>(ctx: &'x Context<'x>, v: Vec<Variable>) -> V...
function fn_is_encoding_problem (line 31) | pub fn fn_is_encoding_problem<'x>(ctx: &'x Context<'x>, _: Vec<Variable>...
function fn_is_attachment (line 39) | pub fn fn_is_attachment<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> V...
function fn_is_body (line 43) | pub fn fn_is_body<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> Variable {
function fn_attachment_name (line 48) | pub fn fn_attachment_name<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) ->...
function fn_mime_part_len (line 56) | pub fn fn_mime_part_len<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> V...
function fn_thread_name (line 64) | pub fn fn_thread_name<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Varia...
function fn_is_header_utf8_valid (line 68) | pub fn fn_is_header_utf8_valid<'x>(ctx: &'x Context<'x>, v: Vec<Variable...
FILE: crates/common/src/scripts/functions/image.rs
function fn_img_metadata (line 9) | pub fn fn_img_metadata<'x>(ctx: &'x Context<'x>, v: Vec<Variable>) -> Va...
FILE: crates/common/src/scripts/functions/misc.rs
function fn_is_empty (line 16) | pub fn fn_is_empty<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_is_number (line 25) | pub fn fn_is_number<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_is_ip_addr (line 29) | pub fn fn_is_ip_addr<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variab...
function fn_is_ipv4_addr (line 33) | pub fn fn_is_ipv4_addr<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_is_ipv6_addr (line 40) | pub fn fn_is_ipv6_addr<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_ip_reverse_name (line 47) | pub fn fn_ip_reverse_name<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> V...
function fn_detect_file_type (line 55) | pub fn fn_detect_file_type<'x>(ctx: &'x Context<'x>, v: Vec<Variable>) -...
function fn_hash (line 72) | pub fn fn_hash<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_get_var_names (line 97) | pub fn fn_get_var_names<'x>(ctx: &'x Context<'x>, _: Vec<Variable>) -> V...
FILE: crates/common/src/scripts/functions/mod.rs
function register_functions_trusted (line 20) | pub fn register_functions_trusted() -> FunctionMap {
function register_functions_untrusted (line 89) | pub fn register_functions_untrusted() -> FunctionMap {
type ApplyString (line 136) | pub trait ApplyString<'x> {
method transform (line 137) | fn transform(&self, f: impl Fn(&'_ str) -> Variable) -> Variable;
method transform (line 141) | fn transform(&self, f: impl Fn(&'_ str) -> Variable) -> Variable {
FILE: crates/common/src/scripts/functions/text.rs
function fn_trim (line 12) | pub fn fn_trim<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_trim_end (line 16) | pub fn fn_trim_end<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_trim_start (line 20) | pub fn fn_trim_start<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variab...
function fn_len (line 24) | pub fn fn_len<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_to_lowercase (line 33) | pub fn fn_to_lowercase<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_to_uppercase (line 37) | pub fn fn_to_uppercase<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_is_uppercase (line 41) | pub fn fn_is_uppercase<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_is_lowercase (line 50) | pub fn fn_is_lowercase<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_has_digits (line 59) | pub fn fn_has_digits<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variab...
function tokenize_words (line 63) | pub fn tokenize_words(v: &Variable) -> Variable {
function fn_count_spaces (line 72) | pub fn fn_count_spaces<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_count_uppercase (line 81) | pub fn fn_count_uppercase<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> V...
function fn_count_lowercase (line 90) | pub fn fn_count_lowercase<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> V...
function fn_count_chars (line 99) | pub fn fn_count_chars<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Varia...
function fn_eq_ignore_case (line 103) | pub fn fn_eq_ignore_case<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Va...
function fn_contains (line 109) | pub fn fn_contains<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_contains_ignore_case (line 118) | pub fn fn_contains_ignore_case<'x>(_: &'x Context<'x>, v: Vec<Variable>)...
function fn_starts_with (line 131) | pub fn fn_starts_with<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Varia...
function fn_ends_with (line 137) | pub fn fn_ends_with<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_lines (line 141) | pub fn fn_lines<'x>(_: &'x Context<'x>, mut v: Vec<Variable>) -> Variable {
function fn_substring (line 152) | pub fn fn_substring<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_strip_prefix (line 161) | pub fn fn_strip_prefix<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_strip_suffix (line 170) | pub fn fn_strip_suffix<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
function fn_split (line 179) | pub fn fn_split<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_rsplit (line 187) | pub fn fn_rsplit<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_split_n (line 195) | pub fn fn_split_n<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_split_once (line 214) | pub fn fn_split_once<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variab...
function fn_rsplit_once (line 225) | pub fn fn_rsplit_once<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Varia...
function fn_levenshtein_distance (line 243) | pub fn fn_levenshtein_distance<'x>(_: &'x Context<'x>, v: Vec<Variable>)...
function levenshtein_distance (line 250) | pub fn levenshtein_distance(a: &str, b: &str) -> usize {
function fn_detect_language (line 308) | pub fn fn_detect_language<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> V...
function fn_html_to_text (line 315) | pub fn fn_html_to_text<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
FILE: crates/common/src/scripts/functions/unicode.rs
function fn_is_ascii (line 11) | pub fn fn_is_ascii<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_has_zwsp (line 23) | pub fn fn_has_zwsp<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_has_obscured (line 35) | pub fn fn_has_obscured<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Vari...
type CharUtils (line 47) | pub trait CharUtils {
method is_zwsp (line 48) | fn is_zwsp(&self) -> bool;
method is_obscured (line 49) | fn is_obscured(&self) -> bool;
method is_zwsp (line 53) | fn is_zwsp(&self) -> bool {
method is_obscured (line 60) | fn is_obscured(&self) -> bool {
function fn_cure_text (line 71) | pub fn fn_cure_text<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_unicode_skeleton (line 78) | pub fn fn_unicode_skeleton<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> ...
function fn_is_mixed_charset (line 84) | pub fn fn_is_mixed_charset<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> ...
FILE: crates/common/src/scripts/functions/url.rs
function fn_uri_part (line 12) | pub fn fn_uri_part<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
function fn_puny_decode (line 35) | pub fn fn_puny_decode<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Varia...
FILE: crates/common/src/scripts/mod.rs
type ScriptModification (line 21) | pub enum ScriptModification {
function into_sieve_value (line 32) | pub fn into_sieve_value(value: Value) -> Variable {
function into_store_value (line 43) | pub fn into_store_value(value: Variable) -> Value<'static> {
function to_store_value (line 52) | pub fn to_store_value(value: &Variable) -> Value<'static> {
type IsMixedCharset (line 61) | pub trait IsMixedCharset {
method is_mixed_charset (line 62) | fn is_mixed_charset(&self) -> bool;
method is_mixed_charset (line 66) | fn is_mixed_charset(&self) -> bool {
FILE: crates/common/src/scripts/plugins/dns.rs
function register (line 14) | pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
function register_exists (line 18) | pub fn register_exists(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec (line 22) | pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
function exec_exists (line 158) | pub async fn exec_exists(ctx: PluginContext<'_>) -> trc::Result<Variable> {
type ShortError (line 186) | trait ShortError {
method short_error (line 187) | fn short_error(&self) -> &'static str;
method short_error (line 191) | fn short_error(&self) -> &'static str {
FILE: crates/common/src/scripts/plugins/exec.rs
function register (line 13) | pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec (line 17) | pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
FILE: crates/common/src/scripts/plugins/headers.rs
function register (line 13) | pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec (line 17) | pub fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
FILE: crates/common/src/scripts/plugins/http.rs
function register_header (line 14) | pub fn register_header(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec_header (line 18) | pub async fn exec_header(ctx: PluginContext<'_>) -> trc::Result<Variable> {
FILE: crates/common/src/scripts/plugins/llm_prompt.rs
function register (line 15) | pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec (line 19) | pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
FILE: crates/common/src/scripts/plugins/lookup.rs
function register (line 12) | pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
function register_get (line 16) | pub fn register_get(plugin_id: u32, fnc_map: &mut FunctionMap) {
function register_set (line 20) | pub fn register_set(plugin_id: u32, fnc_map: &mut FunctionMap) {
function register_local_domain (line 24) | pub fn register_local_domain(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec (line 28) | pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
function exec_get (line 54) | pub async fn exec_get(ctx: PluginContext<'_>) -> trc::Result<Variable> {
function exec_set (line 69) | pub async fn exec_set(ctx: PluginContext<'_>) -> trc::Result<Variable> {
function exec_local_domain (line 101) | pub async fn exec_local_domain(ctx: PluginContext<'_>) -> trc::Result<Va...
type VariableWrapper (line 125) | pub struct VariableWrapper(Variable);
method from (line 140) | fn from(value: i64) -> Self {
method into_inner (line 146) | pub fn into_inner(self) -> Variable {
method from (line 152) | fn from(value: Value<'static>) -> Self {
method deserialize (line 128) | fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
FILE: crates/common/src/scripts/plugins/mod.rs
type RegisterPluginFnc (line 23) | type RegisterPluginFnc = fn(u32, &mut FunctionMap) -> ();
type PluginContext (line 25) | pub struct PluginContext<'x> {
constant PLUGINS_REGISTER (line 34) | const PLUGINS_REGISTER: [RegisterPluginFnc; 13] = [
type RegisterSievePlugins (line 50) | pub trait RegisterSievePlugins {
method register_plugins_trusted (line 51) | fn register_plugins_trusted(self) -> Self;
method register_plugins_untrusted (line 52) | fn register_plugins_untrusted(self) -> Self;
method register_plugins_trusted (line 56) | fn register_plugins_trusted(mut self) -> Self {
method register_plugins_untrusted (line 68) | fn register_plugins_untrusted(mut self) -> Self {
method run_plugin (line 75) | pub async fn run_plugin(&self, id: u32, ctx: PluginContext<'_>) -> Input {
function test_print (line 110) | pub fn test_print(ctx: PluginContext<'_>) -> Input {
FILE: crates/common/src/scripts/plugins/query.rs
function register (line 15) | pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec (line 19) | pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
FILE: crates/common/src/scripts/plugins/text.rs
function register_tokenize (line 14) | pub fn register_tokenize(plugin_id: u32, fnc_map: &mut FunctionMap) {
function register_domain_part (line 18) | pub fn register_domain_part(plugin_id: u32, fnc_map: &mut FunctionMap) {
function exec_tokenize (line 22) | pub fn exec_tokenize(ctx: PluginContext<'_>) -> trc::Result<Variable> {
type DomainPart (line 54) | enum DomainPart {
function exec_domain_part (line 60) | pub fn exec_domain_part(ctx: PluginContext<'_>) -> trc::Result<Variable> {
FILE: crates/common/src/sharing/acl.rs
method refresh_acls (line 15) | pub async fn refresh_acls(&self, acl_changes: &[AclGrant], current: Opti...
method refresh_archived_acls (line 64) | pub async fn refresh_archived_acls(
FILE: crates/common/src/sharing/mod.rs
type EffectiveAcl (line 16) | pub trait EffectiveAcl {
method effective_acl (line 17) | fn effective_acl(&self, access_token: &AccessToken) -> Bitmap<Acl>;
method effective_acl (line 21) | fn effective_acl(&self, access_token: &AccessToken) -> Bitmap<Acl> {
method effective_acl (line 27) | fn effective_acl(&self, access_token: &AccessToken) -> Bitmap<Acl> {
method effective_acl (line 40) | fn effective_acl(&self, access_token: &AccessToken) -> Bitmap<Acl> {
FILE: crates/common/src/sharing/notification.rs
type ShareNotification (line 12) | pub struct ShareNotification {
method deserialize_from_slice (line 44) | fn deserialize_from_slice(bytes: &[u8]) -> Option<Self> {
method serialize (line 23) | fn serialize(&self) -> Vec<u8> {
method deserialize (line 37) | fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
FILE: crates/common/src/sharing/resources.rs
method shared_containers (line 13) | pub fn shared_containers(
method shared_items (line 39) | pub fn shared_items(
method has_access_to_container (line 64) | pub fn has_access_to_container(
method container_acl (line 90) | pub fn container_acl(&self, access_token: &AccessToken, document_id: u32...
method document_ids (line 109) | pub fn document_ids(&self, is_container: bool) -> impl Iterator<Item = u...
method has_container_id (line 119) | pub fn has_container_id(&self, id: &u32) -> bool {
method has_item_id (line 125) | pub fn has_item_id(&self, id: &u32) -> bool {
FILE: crates/common/src/storage/blob.rs
method get_blob_section (line 15) | pub async fn get_blob_section(
FILE: crates/common/src/storage/index.rs
type IndexValue (line 30) | pub enum IndexValue<'x> {
type IndexItem (line 66) | pub enum IndexItem<'x> {
function as_slice (line 76) | pub fn as_slice(&self) -> &[u8] {
function into_owned (line 87) | pub fn into_owned(self) -> Vec<u8> {
function is_empty (line 98) | pub fn is_empty(&self) -> bool {
function is_none (line 107) | pub fn is_none(&self) -> bool {
function is_some (line 111) | pub fn is_some(&self) -> bool {
method eq (line 117) | fn eq(&self, other: &Self) -> bool {
function hash (line 125) | fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
function from (line 138) | fn from(value: u32) -> Self {
function from (line 144) | fn from(value: &u32) -> Self {
function from (line 150) | fn from(value: u64) -> Self {
function from (line 156) | fn from(value: i64) -> Self {
function from (line 162) | fn from(value: &'x [u8]) -> Self {
function from (line 168) | fn from(value: Vec<u8>) -> Self {
function from (line 174) | fn from(value: &'x str) -> Self {
function from (line 180) | fn from(value: &'x String) -> Self {
function from (line 186) | fn from(value: String) -> Self {
function from (line 192) | fn from(value: &'x ArchivedString) -> Self {
function from (line 198) | fn from(value: ArchivedU32) -> Self {
function from (line 204) | fn from(value: &ArchivedU32) -> Self {
function from (line 210) | fn from(value: ArchivedU64) -> Self {
function from (line 216) | fn from(value: Option<T>) -> Self {
function from (line 225) | fn from(value: ArchivedOption<T>) -> Self {
type IndexableObject (line 233) | pub trait IndexableObject: Sync + Send {
method index_values (line 234) | fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>>;
method index_values (line 770) | fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
type IndexableAndSerializableObject (line 237) | pub trait IndexableAndSerializableObject:
method is_versioned (line 248) | fn is_versioned() -> bool;
method is_versioned (line 776) | fn is_versioned() -> bool {
type ObjectIndexBuilder (line 252) | pub struct ObjectIndexBuilder<C: IndexableObject, N: IndexableAndSeriali...
method default (line 260) | fn default() -> Self {
function new (line 266) | pub fn new() -> Self {
function with_current (line 275) | pub fn with_current(mut self, current: Archive<C>) -> Self {
function with_changes (line 280) | pub fn with_changes(mut self, changes: N) -> Self {
function with_current_opt (line 285) | pub fn with_current_opt(mut self, current: Option<Archive<C>>) -> Self {
function changes (line 290) | pub fn changes(&self) -> Option<&N> {
function changes_mut (line 294) | pub fn changes_mut(&mut self) -> Option<&mut N> {
function current (line 298) | pub fn current(&self) -> Option<&Archive<C>> {
function with_access_token (line 302) | pub fn with_access_token(mut self, access_token: &AccessToken) -> Self {
function with_tenant_id (line 308) | pub fn with_tenant_id(mut self, tenant_id: Option<u32>) -> Self {
method build (line 317) | fn build(self, batch: &mut BatchBuilder) -> trc::Result<()> {
function build_index (line 403) | fn build_index(
function merge_index (line 538) | fn merge_index(
FILE: crates/common/src/storage/state.rs
method subscribe_push_manager (line 17) | pub async fn subscribe_push_manager(
FILE: crates/common/src/telemetry/metrics/otel.rs
method push_metrics (line 20) | pub async fn push_metrics(&self, is_enterprise: bool, start_time: System...
method enable_errors (line 105) | pub fn enable_errors() {
FILE: crates/common/src/telemetry/metrics/prometheus.rs
method export_prometheus_metrics (line 16) | pub async fn export_prometheus_metrics(&self) -> trc::Result<String> {
function metric_name (line 65) | fn metric_name(id: impl AsRef<str>) -> String {
function new_counter (line 78) | fn new_counter(value: u64) -> Metric {
function new_gauge (line 86) | fn new_gauge(value: u64) -> Metric {
function new_histogram (line 94) | fn new_histogram(histogram: &AtomicHistogram<12>) -> Metric {
FILE: crates/common/src/telemetry/metrics/store.rs
type MetricsStore (line 29) | pub trait MetricsStore: Sync + Send {
method write_metrics (line 30) | fn write_metrics(
method query_metrics (line 36) | fn query_metrics(
method purge_metrics (line 41) | fn purge_metrics(&self, period: Duration) -> impl Future<Output = trc:...
method write_metrics (line 85) | async fn write_metrics(
method query_metrics (line 197) | async fn query_metrics(
method purge_metrics (line 281) | async fn purge_metrics(&self, period: Duration) -> trc::Result<()> {
type MetricsHistory (line 45) | pub struct MetricsHistory {
method init (line 300) | pub fn init() -> SharedMetricHistory {
type HistogramHistory (line 51) | struct HistogramHistory {
type Metric (line 59) | pub enum Metric<CI, MI, T> {
type SharedMetricHistory (line 78) | pub type SharedMetricHistory = Arc<Mutex<MetricsHistory>>;
constant TYPE_COUNTER (line 80) | const TYPE_COUNTER: u64 = 0x00;
constant TYPE_HISTOGRAM (line 81) | const TYPE_HISTOGRAM: u64 = 0x01;
constant TYPE_GAUGE (line 82) | const TYPE_GAUGE: u64 = 0x02;
FILE: crates/common/src/telemetry/mod.rs
method enable (line 20) | pub fn enable(self, is_enterprise: bool) {
method update (line 38) | pub fn update(self, is_enterprise: bool) {
method test_tracer (line 74) | pub fn test_tracer(level: trc::Level) {
method spawn (line 99) | pub fn spawn(self, builder: SubscriberBuilder, is_enterprise: bool) {
FILE: crates/common/src/telemetry/tracers/journald.rs
function spawn_journald_tracer (line 12) | pub(crate) fn spawn_journald_tracer(builder: SubscriberBuilder, subscrib...
constant JOURNALD_PATH (line 84) | const JOURNALD_PATH: &str = "/run/systemd/journal/socket";
constant CMSG_BUFSIZE (line 85) | const CMSG_BUFSIZE: usize = 64;
type Subscriber (line 87) | pub struct Subscriber {
method send_event (line 24) | fn send_event(&self, event: &Event<EventDetails>) {
method new (line 178) | pub fn new() -> io::Result<Self> {
method with_priority_mappings (line 207) | pub fn with_priority_mappings(mut self, mappings: PriorityMappings) ->...
method with_syslog_identifier (line 228) | pub fn with_syslog_identifier(mut self, identifier: String) -> Self {
method syslog_identifier (line 234) | pub fn syslog_identifier(&self) -> &str {
method send_payload (line 239) | fn send_payload(&self, _opayload: &[u8]) -> io::Result<()> {
method send_payload (line 247) | fn send_payload(&self, payload: &[u8]) -> io::Result<usize> {
method send_large_payload (line 260) | fn send_large_payload(&self, _payload: &[u8]) -> io::Result<usize> {
method send_large_payload (line 268) | fn send_large_payload(&self, payload: &[u8]) -> io::Result<usize> {
method fmt (line 303) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type PriorityMappings (line 95) | pub struct PriorityMappings {
method new (line 285) | pub fn new() -> PriorityMappings {
type Priority (line 116) | pub enum Priority {
method default (line 297) | fn default() -> Self {
function put_field_length_encoded (line 321) | fn put_field_length_encoded(buf: &mut Vec<u8>, name: &str, write_value: ...
function put_field_wellformed (line 340) | fn put_field_wellformed(buf: &mut Vec<u8>, name: &str, value: &[u8]) {
function put_value (line 351) | fn put_value(buf: &mut Vec<u8>, value: &[u8]) {
function assert_cmsg_bufsize (line 357) | fn assert_cmsg_bufsize() {
function send_one_fd_to (line 366) | pub fn send_one_fd_to<P: AsRef<Path>>(socket: &UnixDatagram, fd: RawFd, ...
function create (line 421) | fn create(flags: c_uint) -> Result<File> {
function memfd_create_syscall (line 437) | fn memfd_create_syscall(flags: c_uint) -> c_int {
function create_sealable (line 448) | pub fn create_sealable() -> Result<File> {
function seal_fully (line 453) | pub fn seal_fully(fd: RawFd) -> Result<()> {
FILE: crates/common/src/telemetry/tracers/log.rs
function spawn_log_tracer (line 18) | pub(crate) fn spawn_log_tracer(builder: SubscriberBuilder, settings: Log...
method build_writer (line 70) | pub async fn build_writer(&self) -> Option<BufWriter<File>> {
method next_rotation (line 118) | pub fn next_rotation(&self) -> u64 {
FILE: crates/common/src/telemetry/tracers/otel.rs
constant MAX_EVENTS (line 24) | const MAX_EVENTS: usize = 2048;
function spawn_otel_tracer (line 26) | pub(crate) fn spawn_otel_tracer(builder: SubscriberBuilder, mut otel: Ot...
function build_span_data (line 137) | fn build_span_data<I, T>(
method build_log_record (line 187) | fn build_log_record(&self, event: &Event<EventDetails>) -> SdkLogRecord {
function build_key_value (line 212) | fn build_key_value(key_value: &(trc::Key, trc::Value)) -> Option<KeyValu...
function build_key (line 237) | fn build_key(key: &trc::Key) -> Key {
function build_any_value (line 241) | fn build_any_value(value: &trc::Value) -> AnyValue {
FILE: crates/common/src/telemetry/tracers/stdout.rs
function spawn_console_tracer (line 18) | pub(crate) fn spawn_console_tracer(builder: SubscriberBuilder, settings:...
constant BUFFER_CAPACITY (line 41) | const BUFFER_CAPACITY: usize = 4096;
type StdErrWriter (line 43) | pub struct StdErrWriter {
method poll_write (line 48) | fn poll_write(
method poll_flush (line 73) | fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Res...
method poll_shutdown (line 83) | fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Resu...
method default (line 89) | fn default() -> Self {
FILE: crates/common/src/telemetry/tracers/store.rs
constant MAX_EVENTS (line 27) | const MAX_EVENTS: usize = 2048;
function spawn_store_tracer (line 29) | pub(crate) fn spawn_store_tracer(builder: SubscriberBuilder, settings: S...
type TracingStore (line 88) | pub trait TracingStore: Sync + Send {
method get_span (line 89) | fn get_span(
method get_raw_span (line 93) | fn get_raw_span(
method purge_spans (line 97) | fn purge_spans(
method get_span (line 105) | async fn get_span(&self, span_id: u64) -> trc::Result<Vec<Event<EventD...
method get_raw_span (line 114) | async fn get_raw_span(&self, span_id: u64) -> trc::Result<Option<Vec<u...
method purge_spans (line 123) | async fn purge_spans(
method default_events (line 158) | pub fn default_events() -> impl IntoIterator<Item = EventType> {
type RawSpan (line 223) | struct RawSpan(Vec<u8>);
type Span (line 224) | struct Span(Vec<Event<EventDetails>>);
method deserialize (line 227) | fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
method deserialize (line 233) | fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
function build_span_document (line 238) | pub fn build_span_document(
FILE: crates/common/src/telemetry/webhooks/mod.rs
function spawn_webhook_tracer (line 27) | pub(crate) fn spawn_webhook_tracer(builder: SubscriberBuilder, settings:...
type EventWrapper (line 98) | struct EventWrapper {
function spawn_webhook_handler (line 102) | fn spawn_webhook_handler(
function post_webhook_events (line 130) | async fn post_webhook_events(
FILE: crates/dav-proto/src/lib.rs
function xml_pretty_print (line 16) | pub fn xml_pretty_print(xml_string: &str) -> String {
type RequestHeaders (line 37) | pub struct RequestHeaders<'x> {
type ResourceState (line 54) | pub struct ResourceState<T: AsRef<str>> {
type Return (line 61) | pub enum Return {
type If (line 69) | pub struct If<'x> {
type Condition (line 75) | pub enum Condition<'x> {
type Timeout (line 84) | pub enum Timeout {
type Depth (line 93) | pub enum Depth {
method from (line 102) | fn from(headers: &RequestHeaders<'_>) -> Self {
FILE: crates/dav-proto/src/parser/header.rs
function new (line 11) | pub fn new(uri: &'x str) -> Self {
function parse (line 18) | pub fn parse(&mut self, key: &str, value: &'x str) -> bool {
function has_if (line 115) | pub fn has_if(&self) -> bool {
function eval_if_resources (line 119) | pub fn eval_if_resources(&self) -> impl Iterator<Item = &str> {
function eval_if (line 123) | pub fn eval_if<T>(&self, resources: &[ResourceState<T>]) -> bool
function parse_if (line 173) | fn parse_if(&mut self, value: &'x str) {
function parse_if_match (line 251) | pub fn parse_if_match(&mut self, value: &'x str, is_not: bool) {
function base_uri (line 282) | pub fn base_uri(&self) -> Option<&str> {
function dav_base_uri (line 287) | pub fn dav_base_uri(uri: &str) -> Option<&str> {
method parse (line 319) | pub fn parse(value: &[u8]) -> Option<Self> {
function try_unwrap_coded_url (line 329) | fn try_unwrap_coded_url(url: &str) -> &str {
function base_uri (line 340) | fn base_uri() {
function eval_if_header (line 390) | fn eval_if_header() {
function parse_headers (line 469) | fn parse_headers() {
FILE: crates/dav-proto/src/parser/mod.rs
type Error (line 22) | pub enum Error {
type UnexpectedToken (line 28) | pub struct UnexpectedToken {
type Result (line 33) | pub type Result<T> = std::result::Result<T, Error>;
type Token (line 36) | pub enum Token<'x> {
type RawElement (line 49) | pub struct RawElement<'x> {
type DavParser (line 54) | pub trait DavParser: Sized {
method parse (line 55) | fn parse(stream: &mut Tokenizer<'_>) -> Result<Self>;
type XmlValueParser (line 58) | pub trait XmlValueParser: Sized {
method parse_bytes (line 59) | fn parse_bytes(bytes: &[u8]) -> Option<Self>;
method parse_str (line 60) | fn parse_str(text: &str) -> Option<Self>;
method dav (line 64) | pub fn dav(element: Element) -> NamedElement {
method caldav (line 71) | pub fn caldav(element: Element) -> NamedElement {
method carddav (line 78) | pub fn carddav(element: Element) -> NamedElement {
method calendarserver (line 85) | pub fn calendarserver(element: Element) -> NamedElement {
function into_owned (line 94) | pub fn into_owned(self) -> Token<'static> {
function into_unexpected (line 108) | pub fn into_unexpected(self) -> Error {
function new (line 117) | pub fn new(element: BytesStart<'x>) -> Self {
function with_namespace (line 124) | pub fn with_namespace(self, namespace: quick_xml::name::Namespace<'_>) -...
function with_namespace_static (line 131) | pub fn with_namespace_static(self, namespace: &'static [u8]) -> Self {
function into_owned (line 138) | pub fn into_owned(self) -> RawElement<'static> {
method eq (line 148) | fn eq(&self, other: &Self) -> bool {
method into_unexpected (line 179) | pub fn into_unexpected(self) -> Error {
method default (line 191) | fn default() -> Self {
method fmt (line 197) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
FILE: crates/dav-proto/src/parser/property.rs
function collect_properties (line 27) | pub(crate) fn collect_properties(
function collect_calendar_data (line 77) | pub(crate) fn collect_calendar_data(&mut self) -> crate::parser::Result<...
function collect_address_data (line 224) | pub(crate) fn collect_address_data(
function collect_property_values (line 287) | pub(crate) fn collect_property_values(
type TimeRangeFromRaw (line 385) | pub(crate) trait TimeRangeFromRaw {
method from_raw (line 386) | fn from_raw(raw: &RawElement<'_>) -> super::Result<Option<TimeRange>>;
method from_raw (line 390) | fn from_raw(raw: &RawElement<'_>) -> super::Result<Option<Self>> {
method from_element (line 421) | pub(crate) fn from_element(element: NamedElement) -> Option<Self> {
type Error (line 591) | type Error = ();
method try_from (line 593) | fn try_from(value: NamedElement) -> Result<Self, Self::Error> {
type ICalendarDateTime (line 606) | struct ICalendarDateTime(i64);
method from_str (line 609) | fn from_str(s: &str) -> Option<Self>
method from_str (line 620) | fn from_str(s: &str) -> Option<Self>
method from_str (line 629) | fn from_str(s: &str) -> Option<Self>
method from_str (line 640) | fn from_str(s: &str) -> Option<Self>
method from_str (line 649) | fn from_str(s: &str) -> Option<Self>
method from_str (line 672) | fn from_str(s: &str) -> Option<Self>
method parse_bytes (line 681) | fn parse_bytes(bytes: &[u8]) -> Option<Self> {
method parse_str (line 691) | fn parse_str(text: &str) -> Option<Self> {
method parse_bytes (line 702) | fn parse_bytes(bytes: &[u8]) -> Option<Self> {
method parse_str (line 706) | fn parse_str(text: &str) -> Option<Self> {
method parse_bytes (line 712) | fn parse_bytes(bytes: &[u8]) -> Option<Self> {
method parse_str (line 716) | fn parse_str(text: &str) -> Option<Self> {
method parse_bytes (line 722) | fn parse_bytes(bytes: &[u8]) -> Option<Self> {
method parse_str (line 728) | fn parse_str(text: &str) -> Option<Self> {
FILE: crates/dav-proto/src/parser/tokenizer.rs
type Tokenizer (line 15) | pub struct Tokenizer<'x> {
function new (line 21) | pub fn new(input: &'x [u8]) -> Self {
function token (line 30) | pub fn token(&'_ mut self) -> super::Result<Token<'_>> {
function unwrap_named_element (line 110) | pub fn unwrap_named_element(&mut self) -> super::Result<NamedElement> {
function expect_named_element (line 120) | pub fn expect_named_element(&mut self, expected: NamedElement) -> super:...
function expect_named_element_or_eof (line 134) | pub fn expect_named_element_or_eof(&mut self, expected: NamedElement) ->...
function expect_element_end (line 149) | pub fn expect_element_end(&mut self) -> super::Result<()> {
function seek_element_end (line 159) | pub fn seek_element_end(&mut self) -> super::Result<()> {
function collect_string_value (line 176) | pub fn collect_string_value(&mut self) -> super::Result<Option<String>> {
function parse_value (line 210) | pub fn parse_value<T: XmlValueParser>(&mut self) -> super::Result<Option...
function collect_elements (line 244) | pub fn collect_elements<T>(&mut self) -> super::Result<Vec<T>>
function attributes (line 280) | pub fn attributes<T: AttributeValue>(
method from (line 294) | fn from(err: quick_xml::Error) -> Self {
method from (line 300) | fn from(err: AttrError) -> Self {
type TestToken (line 315) | pub enum TestToken<'x> {
function test_tokenizer (line 324) | fn test_tokenizer() {
FILE: crates/dav-proto/src/requests/acl.rs
method parse (line 21) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 55) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 151) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
function collect_privileges (line 205) | pub fn collect_privileges(&mut self) -> crate::parser::Result<Vec<Privil...
method from_element (line 239) | pub fn from_element(element: NamedElement) -> Option<Self> {
method parse (line 277) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 309) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 367) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 426) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Option<Sel...
FILE: crates/dav-proto/src/requests/lockinfo.rs
method parse (line 19) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 74) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 98) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
FILE: crates/dav-proto/src/requests/mkcol.rs
method parse (line 13) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
FILE: crates/dav-proto/src/requests/mod.rs
method parse (line 21) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
type NsDeadProperty (line 56) | pub trait NsDeadProperty {
method single_with_ns (line 57) | fn single_with_ns(namespace: Namespace, name: &str) -> Self;
method single_with_ns (line 61) | fn single_with_ns(namespace: Namespace, name: &str) -> Self {
method from (line 73) | fn from(raw: &RawElement<'_>) -> Self {
function parse_requests (line 120) | fn parse_requests() {
FILE: crates/dav-proto/src/requests/propertyupdate.rs
method parse (line 13) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
FILE: crates/dav-proto/src/requests/propfind.rs
method parse (line 13) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
FILE: crates/dav-proto/src/requests/report.rs
method parse (line 31) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 85) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 253) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 386) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 402) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 452) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 510) | fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
method parse (line 571) | fn parse(raw: RawElement<'_>) -> crate::parser::Result<Self> {
function from_parts (line 599) | fn from_parts(comp: A, prop: Option<B>, param: Option<C>, op: FilterOp) ...
function components (line 613) | fn components(&self) -> Option<&A> {
function parse (line 622) | fn parse(raw: RawElement<'_>) -> crate::parser::Result<Option<Self>> {
method parse_bytes (line 634) | fn parse_bytes(bytes: &[u8]) -> Option<Self> {
method parse_str (line 638) | fn parse_str(text: &str) -> Option<Self> {
FILE: crates/dav-proto/src/responses/acl.rs
method fmt (line 22) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 38) | pub fn new(privilege: Privilege, description: impl Into<String>) -> Self {
method with_abstract (line 47) | pub fn with_abstract(mut self) -> Self {
method with_supported_privilege (line 52) | pub fn with_supported_privilege(mut self, supported_privilege: Supported...
method with_opt_supported_privilege (line 57) | pub fn with_opt_supported_privilege(
method all_privileges (line 67) | pub fn all_privileges(is_calendar: bool) -> SupportedPrivilege {
method all_scheduling_privileges (line 108) | pub fn all_scheduling_privileges(is_inbox: bool) -> SupportedPrivilege {
method fmt (line 163) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 186) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 204) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 221) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 239) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 258) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 299) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 309) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 320) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 335) | pub fn new(href: impl Into<String>, privilege: Privilege) -> Self {
method new (line 344) | pub fn new(properties: Vec<PrincipalSearchProperty>) -> Self {
method with_namespace (line 351) | pub fn with_namespace(mut self, namespace: Namespace) -> Self {
method new (line 358) | pub fn new(name: impl Into<DavProperty>, description: impl Into<String>)...
method new (line 367) | pub fn new(principal: Principal, grant_deny: GrantDeny) -> Self {
method with_invert (line 377) | pub fn with_invert(mut self) -> Self {
method with_protected (line 382) | pub fn with_protected(mut self) -> Self {
method with_inherited (line 387) | pub fn with_inherited(mut self, inherited: impl Into<String>) -> Self {
method grant (line 394) | pub fn grant(privileges: Vec<Privilege>) -> Self {
method deny (line 398) | pub fn deny(privileges: Vec<Privilege>) -> Self {
method new (line 404) | pub fn new() -> Self {
method with_grant_only (line 408) | pub fn with_grant_only(mut self) -> Self {
method with_no_invert (line 413) | pub fn with_no_invert(mut self) -> Self {
method with_deny_before_grant (line 418) | pub fn with_deny_before_grant(mut self) -> Self {
method with_required_principal (line 423) | pub fn with_required_principal(mut self, required_principal: RequiredPri...
FILE: crates/dav-proto/src/responses/error.rs
method fmt (line 15) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 33) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 47) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 92) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 148) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method from (line 173) | fn from(error: CalCondition) -> Self {
method from (line 179) | fn from(error: CardCondition) -> Self {
method from (line 185) | fn from(error: BaseCondition) -> Self {
method new (line 191) | pub fn new(error: impl Into<Condition>) -> Self {
method with_namespace (line 198) | pub fn with_namespace(mut self, namespace: impl Into<Namespace>) -> Self {
FILE: crates/dav-proto/src/responses/lock.rs
method fmt (line 22) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 28) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 34) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 62) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 73) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 83) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 97) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 107) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 116) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 125) | pub fn new(href: impl Into<String>, lock_scope: LockScope) -> Self {
method with_depth (line 137) | pub fn with_depth(mut self, depth: Depth) -> Self {
method with_timeout (line 142) | pub fn with_timeout(mut self, timeout: u64) -> Self {
method with_owner_opt (line 147) | pub fn with_owner_opt(mut self, owner: Option<DeadProperty>) -> Self {
method with_owner (line 152) | pub fn with_owner(mut self, owner: DeadProperty) -> Self {
method with_lock_token (line 157) | pub fn with_lock_token(mut self, token: impl Into<String>) -> Self {
method default (line 164) | fn default() -> Self {
FILE: crates/dav-proto/src/responses/mkcol.rs
method fmt (line 15) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 34) | pub fn new(propstat: Vec<PropStat>) -> Self {
method with_mkcalendar (line 42) | pub fn with_mkcalendar(mut self, mkcalendar: bool) -> Self {
method with_namespace (line 50) | pub fn with_namespace(mut self, namespace: Namespace) -> Self {
FILE: crates/dav-proto/src/responses/mod.rs
type XmlEscape (line 25) | trait XmlEscape {
method write_escaped_to (line 26) | fn write_escaped_to(&self, out: &mut impl Write) -> std::fmt::Result;
method write_escaped_to (line 34) | fn write_escaped_to(&self, out: &mut impl Write) -> std::fmt::Result {
type XmlCdataEscape (line 29) | trait XmlCdataEscape {
method write_cdata_escaped_to (line 30) | fn write_cdata_escaped_to(&self, out: &mut impl Write) -> std::fmt::Re...
method write_cdata_escaped_to (line 53) | fn write_cdata_escaped_to(&self, out: &mut impl Write) -> std::fmt::Re...
method fmt (line 77) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 93) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 101) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 111) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 119) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 127) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 135) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 143) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 149) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 162) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type DeadPropertyFormat (line 172) | pub trait DeadPropertyFormat {
method fmt (line 173) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
method fmt (line 177) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
function new (line 234) | pub fn new(vec: impl IntoIterator<Item = T>) -> Self {
method from (line 240) | fn from(v: ICalendar) -> Self {
method from (line 246) | fn from(v: VCard) -> Self {
function parse_responses (line 252) | fn parse_responses() {
function escape_cdata (line 716) | fn escape_cdata() {
FILE: crates/dav-proto/src/responses/multistatus.rs
method fmt (line 20) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 39) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 57) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 69) | pub fn new(response: Vec<Response>) -> Self {
method with_response (line 78) | pub fn with_response(mut self, response: Response) -> Self {
method not_found (line 83) | pub fn not_found(href: impl Into<String>) -> Self {
method add_response (line 92) | pub fn add_response(&mut self, response: Response) {
method with_response_description (line 96) | pub fn with_response_description(mut self, response_description: impl In...
method with_namespace (line 101) | pub fn with_namespace(mut self, namespace: Namespace) -> Self {
method set_namespace (line 106) | pub fn set_namespace(&mut self, namespace: Namespace) {
method with_sync_token (line 110) | pub fn with_sync_token(mut self, sync_token: impl Into<String>) -> Self {
method set_sync_token (line 115) | pub fn set_sync_token(&mut self, sync_token: impl Into<String>) {
method new_propstat (line 121) | pub fn new_propstat(href: impl Into<Href>, propstat: Vec<PropStat>) -> S...
method new_status (line 131) | pub fn new_status<T, H>(href: T, status: StatusCode) -> Self
method with_error (line 149) | pub fn with_error(mut self, error: impl Into<Condition>) -> Self {
method with_response_description (line 154) | pub fn with_response_description(mut self, response_description: impl In...
method with_location (line 159) | pub fn with_location(mut self, location: impl Into<String>) -> Self {
FILE: crates/dav-proto/src/responses/property.rs
method fmt (line 30) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 40) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 58) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 78) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method all_calendar_components (line 130) | pub fn all_calendar_components() -> Self {
method tag_name (line 150) | fn tag_name(&self) -> (&str, Option<&str>) {
method namespace (line 227) | pub fn namespace(&self) -> Namespace {
method as_ref (line 246) | fn as_ref(&self) -> &str {
method fmt (line 252) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 274) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 285) | pub fn new(properties: Vec<DavPropertyValue>) -> Self {
method with_namespace (line 292) | pub fn with_namespace(mut self, namespace: Namespace) -> Self {
method from (line 299) | fn from(prop: WebDavProperty) -> Self {
method from (line 305) | fn from(prop: CardDavProperty) -> Self {
method from (line 311) | fn from(prop: CalDavProperty) -> Self {
method from (line 317) | fn from(v: String) -> Self {
method from (line 323) | fn from(v: &str) -> Self {
method from (line 329) | fn from(v: u64) -> Self {
method from (line 335) | fn from(v: DateTime) -> Self {
method from (line 341) | fn from(v: Vec<ResourceType>) -> Self {
method from (line 347) | fn from(v: Vec<ReportSet>) -> Self {
method from (line 353) | fn from(v: Vec<Comp>) -> Self {
method from (line 359) | fn from(v: Vec<SupportedCollation>) -> Self {
method from (line 365) | fn from(v: SupportedLock) -> Self {
method from (line 371) | fn from(v: Vec<LockEntry>) -> Self {
method from (line 377) | fn from(v: Vec<ActiveLock>) -> Self {
method from (line 383) | fn from(v: LockDiscovery) -> Self {
method from (line 389) | fn from(v: Vec<SupportedPrivilege>) -> Self {
method from (line 395) | fn from(v: Vec<Privilege>) -> Self {
method from (line 401) | fn from(v: Vec<Href>) -> Self {
method from (line 407) | fn from(v: Vec<Ace>) -> Self {
method from (line 413) | fn from(v: AclRestrictions) -> Self {
method from (line 419) | fn from(v: DeadProperty) -> Self {
method new (line 425) | pub fn new(property: impl Into<DavProperty>, value: impl Into<DavValue>)...
method empty (line 432) | pub fn empty(property: impl Into<DavProperty>) -> Self {
FILE: crates/dav-proto/src/responses/propstat.rs
method fmt (line 17) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 32) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 39) | pub(crate) fn new(prop: impl Into<DavPropertyValue>) -> Self {
method new_list (line 48) | pub fn new_list(props: Vec<DavPropertyValue>) -> Self {
method with_prop (line 57) | pub fn with_prop(mut self, prop: impl Into<DavPropertyValue>) -> Self {
method with_status (line 62) | pub fn with_status(mut self, status: StatusCode) -> Self {
method with_error (line 67) | pub fn with_error(mut self, error: impl Into<Condition>) -> Self {
method with_response_description (line 72) | pub fn with_response_description(mut self, response_description: impl In...
FILE: crates/dav-proto/src/responses/schedule.rs
constant NAMESPACE (line 16) | const NAMESPACE: Namespaces = Namespaces {
method fmt (line 23) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method fmt (line 34) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/dav-proto/src/schema/mod.rs
type NamedElement (line 16) | pub struct NamedElement {
type Namespace (line 24) | pub enum Namespace {
method try_parse (line 51) | pub fn try_parse(value: &[u8]) -> Option<Self> {
method prefix (line 61) | pub fn prefix(&self) -> &str {
method namespace (line 70) | pub fn namespace(&self) -> &'static str {
method as_ref (line 81) | fn as_ref(&self) -> &str {
type Namespaces (line 33) | pub struct Namespaces {
method set (line 40) | pub fn set(&mut self, ns: Namespace) {
type Element (line 88) | pub enum Element {
method try_parse (line 466) | pub fn try_parse(value: &[u8]) -> Option<&Self> {
method as_ref (line 848) | fn as_ref(&self) -> &str {
type Attribute (line 1233) | pub enum Attribute<T: AttributeValue> {
type AttributeValue (line 1252) | pub trait AttributeValue {
method from_str (line 1253) | fn from_str(s: &str) -> Option<Self>
method from_str (line 1344) | fn from_str(s: &str) -> Option<Self> {
function from_param (line 1259) | pub fn from_param(param: &[u8], value: Cow<'_, str>) -> Option<Attribute...
type Collation (line 1351) | pub enum Collation {
method try_parse (line 1359) | pub fn try_parse(s: &str) -> Option<Self> {
method as_str (line 1368) | pub fn as_str(&self) -> &'static str {
type MatchType (line 1380) | pub enum MatchType {
method try_parse (line 1388) | pub fn try_parse(s: &str) -> Option<Self> {
type XsiType (line 1399) | pub enum XsiType {
method from_str (line 1423) | fn from_str(s: &str) -> Option<Self> {
type YesNo (line 1448) | struct YesNo;
method from_str (line 1451) | fn from_str(s: &str) -> Option<bool> {
method matches (line 1460) | pub fn matches(&self, text: &str) -> bool {
FILE: crates/dav-proto/src/schema/property.rs
type DavProperty (line 25) | pub enum DavProperty {
constant ALL_PROPS (line 365) | pub const ALL_PROPS: [DavProperty; 11] = [
method is_all_prop (line 379) | pub fn is_all_prop(&self) -> bool {
type WebDavProperty (line 36) | pub enum WebDavProperty {
type CardDavProperty (line 70) | pub enum CardDavProperty {
type CardDavPropertyName (line 80) | pub struct CardDavPropertyName {
type CalDavProperty (line 89) | pub enum CalDavProperty {
type PrincipalProperty (line 111) | pub enum PrincipalProperty {
type CalendarData (line 127) | pub struct CalendarData {
type CalDavPropertyName (line 136) | pub struct CalDavPropertyName {
type Rfc1123DateTime (line 145) | pub struct Rfc1123DateTime(pub(crate) i64);
method new (line 359) | pub fn new(timestamp: i64) -> Self {
type DavValue (line 149) | pub enum DavValue {
type ReportSet (line 177) | pub enum ReportSet {
method calendar (line 399) | pub fn calendar() -> Vec<ReportSet> {
method addressbook (line 411) | pub fn addressbook() -> Vec<ReportSet> {
method file (line 422) | pub fn file() -> Vec<ReportSet> {
method principal (line 430) | pub fn principal() -> Vec<ReportSet> {
type Comp (line 193) | pub struct Comp(pub ICalendarComponentType);
type SupportedCollation (line 197) | pub struct SupportedCollation {
type ResourceType (line 204) | pub enum ResourceType {
type LockDiscovery (line 215) | pub struct LockDiscovery(pub List<ActiveLock>);
type ActiveLock (line 219) | pub struct ActiveLock {
type SupportedLock (line 231) | pub struct SupportedLock(pub List<LockEntry>);
type LockEntry (line 235) | pub struct LockEntry {
type LockType (line 242) | pub enum LockType {
type LockScope (line 249) | pub enum LockScope {
type Privilege (line 256) | pub enum Privilege {
method all (line 280) | pub fn all(is_calendar: bool) -> Vec<Privilege> {
method scheduling (line 313) | pub fn scheduling(is_inbox: bool, is_owner: bool) -> Vec<Privilege> {
method from (line 350) | fn from(value: DavProperty) -> Self {
FILE: crates/dav-proto/src/schema/request.rs
type PropFind (line 25) | pub enum PropFind {
type PropertyUpdate (line 34) | pub struct PropertyUpdate {
method has_changes (line 232) | pub fn has_changes(&self) -> bool {
type DavPropertyValue (line 42) | pub struct DavPropertyValue {
type MkCol (line 49) | pub struct MkCol {
type LockInfo (line 56) | pub struct LockInfo {
type Report (line 65) | pub enum Report {
type ExpandProperty (line 81) | pub struct ExpandProperty {
type ExpandPropertyItem (line 87) | pub struct ExpandPropertyItem {
type AddressbookQuery (line 94) | pub struct AddressbookQuery {
type VCardPropertyWithGroup (line 102) | pub struct VCardPropertyWithGroup {
type CalendarQuery (line 109) | pub struct CalendarQuery {
type Timezone (line 119) | pub enum Timezone {
type FreeBusyQuery (line 127) | pub struct FreeBusyQuery {
method new (line 238) | pub fn new(start: i64, end: i64) -> Self {
type MultiGet (line 133) | pub struct MultiGet {
type SyncCollection (line 140) | pub struct SyncCollection {
type Filter (line 150) | pub enum Filter<A, B, C> {
type FilterOp (line 173) | pub enum FilterOp {
type TextMatch (line 183) | pub struct TextMatch {
type Acl (line 192) | pub struct Acl {
type AclPrincipalPropSet (line 198) | pub struct AclPrincipalPropSet {
type PrincipalMatch (line 204) | pub struct PrincipalMatch {
type PrincipalMatchProperties (line 211) | pub enum PrincipalMatchProperties {
type PrincipalPropertySearch (line 218) | pub struct PrincipalPropertySearch {
type PropertySearch (line 226) | pub struct PropertySearch {
type DavDeadProperty (line 245) | pub trait DavDeadProperty {
method to_dav_values (line 246) | fn to_dav_values(&self, output: &mut Vec<DavPropertyValue>);
method to_dav_values (line 250) | fn to_dav_values(&self, output: &mut Vec<DavPropertyValue>) {
function is_none_match (line 289) | pub fn is_none_match(&self) -> bool {
FILE: crates/dav-proto/src/schema/response.rs
type MultiStatus (line 21) | pub struct MultiStatus {
method is_empty (line 307) | pub fn is_empty(&self) -> bool {
type Response (line 30) | pub struct Response {
type ResponseType (line 40) | pub enum ResponseType {
type Status (line 47) | pub struct Status(pub StatusCode);
method deserialize (line 417) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
type Location (line 52) | pub struct Location(pub Href);
type ResponseDescription (line 57) | pub struct ResponseDescription(pub String);
type SyncToken (line 60) | pub struct SyncToken(pub String);
type Href (line 65) | pub struct Href(pub String);
method from (line 295) | fn from(value: String) -> Self {
method from (line 301) | fn from(value: &str) -> Self {
type List (line 70) | pub struct List<T: Display>(pub Vec<T>);
type MkColResponse (line 72) | pub struct MkColResponse {
type PropStat (line 80) | pub struct PropStat {
type Prop (line 90) | pub struct Prop(pub List<DavPropertyValue>);
type PropResponse (line 92) | pub struct PropResponse {
type ScheduleResponse (line 98) | pub struct ScheduleResponse {
type ScheduleResponseItem (line 103) | pub struct ScheduleResponseItem {
type SupportedPrivilege (line 111) | pub struct SupportedPrivilege {
type Ace (line 120) | pub struct Ace {
type GrantDeny (line 130) | pub enum GrantDeny {
type Principal (line 137) | pub enum Principal {
type AclRestrictions (line 150) | pub struct AclRestrictions {
type RequiredPrincipal (line 159) | pub enum RequiredPrincipal {
type PrincipalSearchPropertySet (line 170) | pub struct PrincipalSearchPropertySet {
type PrincipalSearchProperty (line 177) | pub struct PrincipalSearchProperty {
type ErrorResponse (line 182) | pub struct ErrorResponse {
type Condition (line 189) | pub enum Condition {
method display_name (line 391) | pub fn display_name(&self) -> &'static str {
type BaseCondition (line 197) | pub enum BaseCondition {
method status (line 277) | pub fn status(&self) -> StatusCode {
method display_name (line 313) | pub fn display_name(&self) -> &'static str {
type Resource (line 227) | pub struct Resource {
type CalCondition (line 234) | pub enum CalCondition {
method display_name (line 345) | pub fn display_name(&self) -> &'static str {
type CardCondition (line 265) | pub enum CardCondition {
method display_name (line 376) | pub fn display_name(&self) -> &'static str {
method serialize (line 407) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
FILE: crates/dav/src/calendar/copy_move.rs
type CalendarCopyMoveRequestHandler (line 37) | pub(crate) trait CalendarCopyMoveRequestHandler: Sync + Send {
method handle_calendar_copy_move_request (line 38) | fn handle_calendar_copy_move_request(
method handle_calendar_copy_move_request (line 47) | async fn handle_calendar_copy_move_request(
function copy_event (line 450) | async fn copy_event(
function move_event (line 576) | async fn move_event(
function rename_event (line 746) | async fn rename_event(
function copy_container (line 796) | async fn copy_container(
function rename_container (line 1016) | async fn rename_container(
FILE: crates/dav/src/calendar/delete.rs
type CalendarDeleteRequestHandler (line 37) | pub(crate) trait CalendarDeleteRequestHandler: Sync + Send {
method handle_calendar_delete_request (line 38) | fn handle_calendar_delete_request(
method handle_calendar_delete_request (line 46) | async fn handle_calendar_delete_request(
FILE: crates/dav/src/calendar/freebusy.rs
type CalendarFreebusyRequestHandler (line 40) | pub(crate) trait CalendarFreebusyRequestHandler: Sync + Send {
method handle_calendar_freebusy_request (line 41) | fn handle_calendar_freebusy_request(
method build_freebusy_object (line 48) | fn build_freebusy_object(
method handle_calendar_freebusy_request (line 59) | async fn handle_calendar_freebusy_request(
method build_freebusy_object (line 95) | async fn build_freebusy_object(
function merge_intervals (line 309) | fn merge_intervals(mut intervals: Vec<(i64, i64)>) -> Vec<ICalendarValue> {
function build_ical_value (line 337) | fn build_ical_value(from: i64, to: i64) -> ICalendarValue {
function freebusy_in_range (line 344) | pub(crate) fn freebusy_in_range(
function freebusy_in_range_utc (line 371) | fn freebusy_in_range_utc(
FILE: crates/dav/src/calendar/get.rs
type CalendarGetRequestHandler (line 30) | pub(crate) trait CalendarGetRequestHandler: Sync + Send {
method handle_calendar_get_request (line 31) | fn handle_calendar_get_request(
method handle_calendar_get_request (line 40) | async fn handle_calendar_get_request(
FILE: crates/dav/src/calendar/mkcol.rs
type CalendarMkColRequestHandler (line 31) | pub(crate) trait CalendarMkColRequestHandler: Sync + Send {
method handle_calendar_mkcol_request (line 32) | fn handle_calendar_mkcol_request(
method handle_calendar_mkcol_request (line 41) | async fn handle_calendar_mkcol_request(
FILE: crates/dav/src/calendar/mod.rs
function assert_is_unique_uid (line 90) | pub(crate) async fn assert_is_unique_uid(
type ItipPrecondition (line 123) | pub(crate) trait ItipPrecondition {
method failed_precondition (line 124) | fn failed_precondition(&self) -> Option<CalCondition>;
method failed_precondition (line 128) | fn failed_precondition(&self) -> Option<CalCondition> {
FILE: crates/dav/src/calendar/proppatch.rs
type CalendarPropPatchRequestHandler (line 45) | pub(crate) trait CalendarPropPatchRequestHandler: Sync + Send {
method handle_calendar_proppatch_request (line 46) | fn handle_calendar_proppatch_request(
method apply_calendar_properties (line 53) | fn apply_calendar_properties(
method apply_event_properties (line 62) | fn apply_event_properties(
method handle_calendar_proppatch_request (line 72) | async fn handle_calendar_proppatch_request(
method apply_calendar_properties (line 249) | fn apply_calendar_properties(
method apply_event_properties (line 425) | fn apply_event_properties(
function remove_event_properties (line 492) | fn remove_event_properties(
function remove_calendar_properties (line 518) | fn remove_calendar_properties(
FILE: crates/dav/src/calendar/query.rs
type CalendarQueryRequestHandler (line 48) | pub(crate) trait CalendarQueryRequestHandler: Sync + Send {
method handle_calendar_query_request (line 49) | fn handle_calendar_query_request(
method handle_calendar_query_request (line 58) | async fn handle_calendar_query_request(
function is_resource_in_time_range (line 127) | pub(crate) fn is_resource_in_time_range(resource: &DavResource, filter: ...
function extract_filter_range (line 138) | fn extract_filter_range(query: &CalendarQuery) -> Option<TimeRange> {
function extract_data_range (line 168) | fn extract_data_range(propfind: &PropFind, filter_range: Option<TimeRang...
function try_parse_tz (line 204) | pub fn try_parse_tz(tz: &Timezone) -> Option<Tz> {
type CalendarQueryHandler (line 211) | pub(crate) struct CalendarQueryHandler {
method new (line 217) | pub fn new(
method filter (line 242) | pub fn filter(&mut self, event: &ArchivedCalendarEvent, filters: &Cale...
method serialize_ical (line 414) | pub fn serialize_ical(
method into_expanded_times (line 614) | pub fn into_expanded_times(self) -> Vec<CalendarEventExpansion> {
function find_components (line 620) | fn find_components<'x>(
function find_properties (line 635) | fn find_properties<'x>(
function find_parameter (line 643) | fn find_parameter<'x>(
FILE: crates/dav/src/calendar/scheduling.rs
type CalendarEventNotificationHandler (line 44) | pub(crate) trait CalendarEventNotificationHandler: Sync + Send {
method handle_scheduling_get_request (line 45) | fn handle_scheduling_get_request(
method handle_scheduling_delete_request (line 52) | fn handle_scheduling_delete_request(
method handle_scheduling_post_request (line 58) | fn handle_scheduling_post_request(
method handle_scheduling_get_request (line 67) | async fn handle_scheduling_get_request(
method handle_scheduling_delete_request (line 150) | async fn handle_scheduling_delete_request(
method handle_scheduling_post_request (line 231) | async fn handle_scheduling_post_request(
FILE: crates/dav/src/calendar/update.rs
type CalendarUpdateRequestHandler (line 49) | pub(crate) trait CalendarUpdateRequestHandler: Sync + Send {
method handle_calendar_update_request (line 50) | fn handle_calendar_update_request(
method handle_calendar_update_request (line 60) | async fn handle_calendar_update_request(
function validate_ical (line 453) | fn validate_ical(ical: &ICalendar) -> crate::Result<&str> {
FILE: crates/dav/src/card/copy_move.rs
type CardCopyMoveRequestHandler (line 36) | pub(crate) trait CardCopyMoveRequestHandler: Sync + Send {
method handle_card_copy_move_request (line 37) | fn handle_card_copy_move_request(
method handle_card_copy_move_request (line 46) | async fn handle_card_copy_move_request(
function copy_card (line 432) | async fn copy_card(
function move_card (line 550) | async fn move_card(
function rename_card (line 703) | async fn rename_card(
function copy_container (line 753) | async fn copy_container(
function rename_container (line 961) | async fn rename_container(
FILE: crates/dav/src/card/delete.rs
type CardDeleteRequestHandler (line 36) | pub(crate) trait CardDeleteRequestHandler: Sync + Send {
method handle_card_delete_request (line 37) | fn handle_card_delete_request(
method handle_card_delete_request (line 45) | async fn handle_card_delete_request(
FILE: crates/dav/src/card/get.rs
type CardGetRequestHandler (line 30) | pub(crate) trait CardGetRequestHandler: Sync + Send {
method handle_card_get_request (line 31) | fn handle_card_get_request(
method handle_card_get_request (line 40) | async fn handle_card_get_request(
FILE: crates/dav/src/card/mkcol.rs
type CardMkColRequestHandler (line 31) | pub(crate) trait CardMkColRequestHandler: Sync + Send {
method handle_card_mkcol_request (line 32) | fn handle_card_mkcol_request(
method handle_card_mkcol_request (line 41) | async fn handle_card_mkcol_request(
FILE: crates/dav/src/card/mod.rs
function assert_is_unique_uid (line 74) | pub(crate) async fn assert_is_unique_uid(
FILE: crates/dav/src/card/proppatch.rs
type CardPropPatchRequestHandler (line 42) | pub(crate) trait CardPropPatchRequestHandler: Sync + Send {
method handle_card_proppatch_request (line 43) | fn handle_card_proppatch_request(
method apply_addressbook_properties (line 50) | fn apply_addressbook_properties(
method apply_card_properties (line 59) | fn apply_card_properties(
method handle_card_proppatch_request (line 69) | async fn handle_card_proppatch_request(
method apply_addressbook_properties (line 246) | fn apply_addressbook_properties(
method apply_card_properties (line 349) | fn apply_card_properties(
function remove_card_properties (line 416) | fn remove_card_properties(
function remove_addressbook_properties (line 442) | fn remove_addressbook_properties(
FILE: crates/dav/src/card/query.rs
type CardQueryRequestHandler (line 35) | pub(crate) trait CardQueryRequestHandler: Sync + Send {
method handle_card_query_request (line 36) | fn handle_card_query_request(
method handle_card_query_request (line 45) | async fn handle_card_query_request(
function vcard_query (line 105) | pub(crate) fn vcard_query(card: &ArchivedVCard, filters: &AddressbookFil...
function find_properties (line 186) | fn find_properties<'x>(
function find_parameter (line 196) | fn find_parameter<'x>(
function serialize_vcard_with_props (line 203) | pub(crate) fn serialize_vcard_with_props(
FILE: crates/dav/src/card/update.rs
type CardUpdateRequestHandler (line 38) | pub(crate) trait CardUpdateRequestHandler: Sync + Send {
method handle_card_update_request (line 39) | fn handle_card_update_request(
method handle_card_update_request (line 49) | async fn handle_card_update_request(
FILE: crates/dav/src/common/acl.rs
type DavAclHandler (line 39) | pub(crate) trait DavAclHandler: Sync + Send {
method handle_acl_request (line 40) | fn handle_acl_request(
method handle_acl_prop_set (line 47) | fn handle_acl_prop_set(
method validate_and_map_aces (line 54) | fn validate_and_map_aces(
method resolve_ace (line 61) | fn resolve_ace(
method handle_acl_request (line 81) | async fn handle_acl_request(
method handle_acl_prop_set (line 200) | async fn handle_acl_prop_set(
method validate_and_map_aces (line 287) | async fn validate_and_map_aces(
method resolve_ace (line 452) | async fn resolve_ace(
type ResourceAcl (line 70) | pub(crate) trait ResourceAcl {
method validate_and_map_parent_acl (line 71) | fn validate_and_map_parent_acl(
method validate_and_map_parent_acl (line 504) | fn validate_and_map_parent_acl(
type Privileges (line 530) | pub(crate) trait Privileges {
method current_privilege_set (line 531) | fn current_privilege_set(
method current_privilege_set (line 540) | fn current_privilege_set(
function current_user_privilege_set (line 554) | pub(crate) fn current_user_privilege_set(acl_bitmap: Bitmap<Acl>) -> Vec...
FILE: crates/dav/src/common/lock.rs
type ResourceState (line 31) | pub struct ResourceState<'x> {
type LockData (line 42) | pub(crate) struct LockData {
method remove_lock (line 624) | pub fn remove_lock(&mut self, lock_id: u64) -> bool {
method remove_expired (line 641) | pub fn remove_expired(&mut self) -> u64 {
type LockItems (line 48) | pub(crate) struct LockItems(Vec<LockItem>);
type LockItem (line 51) | pub(crate) struct LockItem {
method to_active_lock (line 769) | pub fn to_active_lock(&self, href: String) -> ActiveLock {
method urn (line 788) | pub fn urn(&self) -> Urn {
type LockCache (line 60) | struct LockCache<'x> {
type LockArchive (line 66) | enum LockArchive<'x> {
type LockCaches (line 72) | pub(crate) struct LockCaches<'x> {
type LockRequestHandler (line 76) | pub(crate) trait LockRequestHandler: Sync + Send {
method handle_lock_request (line 77) | fn handle_lock_request(
method validate_headers (line 84) | fn validate_headers(
method handle_lock_request (line 101) | async fn handle_lock_request(
method validate_headers (line 339) | async fn validate_headers(
type LockRequest (line 94) | pub(crate) enum LockRequest {
function unarchive (line 663) | fn unarchive(&'x self) -> trc::Result<&'x ArchivedLockData> {
function new_shared (line 674) | pub(self) fn new_shared(
function to_unarchived (line 688) | pub fn to_unarchived(&'x self) -> trc::Result<LockCaches<'x>> {
function is_cached (line 707) | pub fn is_cached(&self, resource_state: &ResourceState<'_>) -> Option<us...
function find_cache_pos (line 714) | pub async fn find_cache_pos(
function find_locks_by_pos (line 732) | fn find_locks_by_pos(
function insert_lock_data (line 744) | async fn insert_lock_data(
method find_locks (line 794) | pub fn find_locks<'x: 'y, 'y>(
method to_active_lock (line 843) | pub fn to_active_lock(&self, href: String) -> ActiveLock {
method urn (line 862) | pub fn urn(&self) -> Urn {
function lock_key (line 868) | pub fn lock_key(&self) -> Vec<u8> {
function lock_key (line 874) | pub fn lock_key(&self) -> Vec<u8> {
function build_lock_key (line 879) | pub(crate) fn build_lock_key(account_id: u32, collection: Collection) ->...
method eq (line 888) | fn eq(&self, other: &Self) -> bool {
FILE: crates/dav/src/common/mod.rs
type DavQuery (line 46) | pub(crate) struct DavQuery<'x> {
type SyncType (line 60) | pub(crate) enum SyncType {
method is_none (line 514) | pub fn is_none(&self) -> bool {
method is_none_or_initial (line 518) | pub fn is_none_or_initial(&self) -> bool {
type DavQueryResource (line 71) | pub(crate) enum DavQueryResource<'x> {
type AddressbookFilter (line 86) | pub(crate) type AddressbookFilter = Vec<Filter<(), VCardPropertyWithGrou...
type CalendarFilter (line 87) | pub(crate) type CalendarFilter =
type DavQueryFilter (line 91) | pub(crate) enum DavQueryFilter {
type ETag (line 100) | pub(crate) trait ETag {
method etag (line 101) | fn etag(&self) -> String;
method etag (line 109) | fn etag(&self) -> String {
type ExtractETag (line 104) | pub(crate) trait ExtractETag {
method etag (line 105) | fn etag(&self) -> Option<String>;
method etag (line 115) | fn etag(&self) -> Option<String> {
type DavCollection (line 141) | pub(crate) trait DavCollection {
method namespace (line 142) | fn namespace(&self) -> Namespace;
method namespace (line 146) | fn namespace(&self) -> Namespace {
function propfind (line 158) | pub fn propfind(
function multiget (line 180) | pub fn multiget(
function addressbook_query (line 202) | pub fn addressbook_query(
function calendar_query (line 225) | pub fn calendar_query(
function changes (line 253) | pub fn changes(
function expand (line 282) | pub fn expand(
function is_minimal (line 313) | pub fn is_minimal(&self) -> bool {
type ArchivedResource (line 318) | pub(crate) enum ArchivedResource<'x> {
function from_archive (line 329) | pub fn from_archive(
function acls (line 356) | pub fn acls(&self) -> Option<&ArchivedVec<ArchivedAclGrant>> {
function created (line 365) | pub fn created(&self) -> i64 {
function modified (line 379) | pub fn modified(&self) -> i64 {
function dead_properties (line 393) | pub fn dead_properties(&self) -> Option<&ArchivedDeadProperty> {
function content_length (line 405) | pub fn content_length(&self) -> Option<u32> {
function content_type (line 421) | pub fn content_type(&self) -> Option<&str> {
function display_name (line 438) | pub fn display_name(&self, access_token: &AccessToken) -> Option<&str> {
function supported_report_set (line 454) | pub fn supported_report_set(&self) -> Option<Vec<ReportSet>> {
function resource_type (line 491) | pub fn resource_type(&self) -> Option<Vec<ResourceType>> {
FILE: crates/dav/src/common/propfind.rs
type PropFindRequestHandler (line 75) | pub(crate) trait PropFindRequestHandler: Sync + Send {
method handle_propfind_request (line 76) | fn handle_propfind_request(
method handle_dav_query (line 83) | fn handle_dav_query(
method dav_quota (line 89) | fn dav_quota(
method handle_propfind_request (line 125) | async fn handle_propfind_request(
method handle_dav_query (line 290) | async fn handle_dav_query(
method dav_quota (line 1133) | async fn dav_quota(
type PropFindData (line 96) | pub(crate) struct PropFindData {
method new (line 1582) | pub fn new() -> Self {
method quota (line 1588) | pub async fn quota(
method owner (line 1603) | pub async fn owner(
method resources (line 1622) | pub async fn resources(
method locks (line 1642) | pub async fn locks(
type PropFindAccountData (line 101) | pub(crate) struct PropFindAccountData {
type PropFindAccountQuota (line 110) | pub(crate) struct PropFindAccountQuota {
type PropFindItem (line 116) | pub(crate) struct PropFindItem {
method new (line 1570) | pub fn new(name: String, account_id: u32, resource: DavResourcePath<'_...
function get (line 1161) | async fn get(
function multiget (line 1480) | async fn multiget(
type SyncTokenUrn (line 1680) | pub(crate) trait SyncTokenUrn {
method sync_token (line 1681) | fn sync_token(&self) -> String;
method sync_token (line 1685) | fn sync_token(&self) -> String {
function add_base_collection_response (line 1694) | async fn add_base_collection_response(
FILE: crates/dav/src/common/uri.rs
type UriResource (line 18) | pub(crate) struct UriResource<A, R> {
type Urn (line 24) | pub(crate) enum Urn {
method try_extract_sync_id (line 184) | pub fn try_extract_sync_id(token: &str) -> Option<&str> {
method parse (line 190) | pub fn parse(input: &str) -> Option<Self> {
method try_unwrap_lock (line 210) | pub fn try_unwrap_lock(&self) -> Option<u64> {
method try_unwrap_sync (line 217) | pub fn try_unwrap_sync(&self) -> Option<(u64, u32)> {
type UnresolvedUri (line 29) | pub(crate) type UnresolvedUri<'x> = UriResource<Option<u32>, Option<&'x ...
type OwnedUri (line 30) | pub(crate) type OwnedUri<'x> = UriResource<u32, Option<&'x str>>;
type DocumentUri (line 31) | pub(crate) type DocumentUri = UriResource<u32, u32>;
type DavUriResource (line 33) | pub(crate) trait DavUriResource: Sync + Send {
method validate_uri_with_status (line 34) | fn validate_uri_with_status<'x>(
method validate_uri (line 41) | fn validate_uri<'x>(
method map_uri_resource (line 47) | fn map_uri_resource(
method validate_uri (line 55) | async fn validate_uri<'x>(
method validate_uri_with_status (line 64) | async fn validate_uri_with_status<'x>(
method map_uri_resource (line 121) | async fn map_uri_resource(
function into_owned_uri (line 152) | pub fn into_owned_uri(self) -> crate::Result<OwnedUri<'x>> {
function new_owned (line 164) | pub fn new_owned(
method fmt (line 226) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/dav/src/file/copy_move.rs
type FileCopyMoveRequestHandler (line 39) | pub(crate) trait FileCopyMoveRequestHandler: Sync + Send {
method handle_file_copy_move_request (line 40) | fn handle_file_copy_move_request(
method handle_file_copy_move_request (line 49) | async fn handle_file_copy_move_request(
type Destination (line 330) | pub(crate) struct Destination {
method default (line 338) | fn default() -> Self {
function move_container (line 349) | async fn move_container(
function copy_container (line 419) | async fn copy_container(
function overwrite_and_delete_item (line 553) | async fn overwrite_and_delete_item(
function overwrite_item (line 634) | async fn overwrite_item(
function move_item (line 700) | async fn move_item(
function copy_item (line 776) | async fn copy_item(
function rename_item (line 822) | async fn rename_item(
method from_dav_resource (line 870) | fn from_dav_resource(item: DavResourcePath<'_>) -> Self {
FILE: crates/dav/src/file/delete.rs
type FileDeleteRequestHandler (line 22) | pub(crate) trait FileDeleteRequestHandler: Sync + Send {
method handle_file_delete_request (line 23) | fn handle_file_delete_request(
method handle_file_delete_request (line 31) | async fn handle_file_delete_request(
FILE: crates/dav/src/file/get.rs
type FileGetRequestHandler (line 31) | pub(crate) trait FileGetRequestHandler: Sync + Send {
method handle_file_get_request (line 32) | fn handle_file_get_request(
method handle_file_get_request (line 41) | async fn handle_file_get_request(
FILE: crates/dav/src/file/mkcol.rs
type FileMkColRequestHandler (line 33) | pub(crate) trait FileMkColRequestHandler: Sync + Send {
method handle_file_mkcol_request (line 34) | fn handle_file_mkcol_request(
method handle_file_mkcol_request (line 43) | async fn handle_file_mkcol_request(
FILE: crates/dav/src/file/mod.rs
type FromDavResource (line 66) | pub(crate) trait FromDavResource {
method from_dav_resource (line 67) | fn from_dav_resource(item: DavResourcePath<'_>) -> Self;
method from_dav_resource (line 140) | fn from_dav_resource(item: DavResourcePath) -> Self {
method from_dav_resource (line 146) | fn from_dav_resource(item: DavResourcePath) -> Self {
type FileItemId (line 70) | pub(crate) struct FileItemId {
type DavFileResource (line 76) | pub(crate) trait DavFileResource {
method map_resource (line 77) | fn map_resource<T: FromDavResource>(
method map_parent (line 82) | fn map_parent<'x>(&self, resource: &'x str) -> Option<(Option<DavResou...
method map_parent_resource (line 85) | fn map_parent_resource<'x, T: FromDavResource>(
method map_resource (line 92) | fn map_resource<T: FromDavResource>(
method map_parent (line 107) | fn map_parent<'x>(&self, resource: &'x str) -> Option<(Option<DavResou...
method map_parent_resource (line 117) | fn map_parent_resource<'x, T: FromDavResource>(
FILE: crates/dav/src/file/proppatch.rs
type FilePropPatchRequestHandler (line 39) | pub(crate) trait FilePropPatchRequestHandler: Sync + Send {
method handle_file_proppatch_request (line 40) | fn handle_file_proppatch_request(
method apply_file_properties (line 47) | fn apply_file_properties(
method handle_file_proppatch_request (line 57) | async fn handle_file_proppatch_request(
method apply_file_properties (line 173) | fn apply_file_properties(
function remove_file_properties (line 271) | fn remove_file_properties(
FILE: crates/dav/src/file/update.rs
type FileUpdateRequestHandler (line 39) | pub(crate) trait FileUpdateRequestHandler: Sync + Send {
method handle_file_update_request (line 40) | fn handle_file_update_request(
method handle_file_update_request (line 50) | async fn handle_file_update_request(
FILE: crates/dav/src/lib.rs
type Result (line 23) | pub(crate) type Result<T> = std::result::Result<T, DavError>;
type DavMethod (line 26) | pub enum DavMethod {
method parse (line 115) | pub fn parse(method: &Method) -> Option<Self> {
method has_body (line 142) | pub fn has_body(self) -> bool {
function from (line 47) | fn from(value: DavMethod) -> Self {
type DavError (line 70) | pub(crate) enum DavError {
method from (line 84) | fn from(value: DavErrorCondition) -> Self {
type DavErrorCondition (line 77) | struct DavErrorCondition {
method from (line 90) | fn from(value: Condition) -> Self {
method new (line 100) | pub fn new(code: StatusCode, condition: impl Into<Condition>) -> Self {
method with_details (line 108) | pub fn with_details(mut self, details: impl Into<String>) -> Self {
type PropStatBuilder (line 159) | pub struct PropStatBuilder {
method insert_ok (line 164) | pub fn insert_ok(&mut self, prop: impl Into<DavPropertyValue>) -> &mut...
method insert_with_status (line 172) | pub fn insert_with_status(
method insert_error_with_description (line 184) | pub fn insert_error_with_description(
method insert_precondition_failed (line 197) | pub fn insert_precondition_failed(
method insert_precondition_failed_with_description (line 210) | pub fn insert_precondition_failed_with_description(
method build (line 224) | pub fn build(self) -> Vec<PropStat> {
function fix_percent_encoding (line 238) | pub(crate) fn fix_percent_encoding(path: &'_ str) -> Cow<'_, str> {
FILE: crates/dav/src/principal/matching.rs
type PrincipalMatching (line 30) | pub(crate) trait PrincipalMatching: Sync + Send {
method handle_principal_match (line 31) | fn handle_principal_match(
method handle_principal_match (line 40) | async fn handle_principal_match(
FILE: crates/dav/src/principal/mod.rs
type CurrentUserPrincipal (line 17) | pub trait CurrentUserPrincipal {
method current_user_principal (line 18) | fn current_user_principal(&self) -> Href;
method current_user_principal (line 22) | fn current_user_principal(&self) -> Href {
FILE: crates/dav/src/principal/propfind.rs
type PrincipalPropFind (line 30) | pub(crate) trait PrincipalPropFind: Sync + Send {
method prepare_principal_propfind_response (line 31) | fn prepare_principal_propfind_response(
method expand_principal (line 40) | fn expand_principal(
method owner_href (line 47) | fn owner_href(
method prepare_principal_propfind_response (line 55) | async fn prepare_principal_propfind_response(
method expand_principal (line 394) | async fn expand_principal(
method owner_href (line 413) | async fn owner_href(&self, access_token: &AccessToken, account_id: u32...
function build_home_set (line 432) | pub(crate) async fn build_home_set(
function all_props (line 474) | fn all_props(collection: Collection, all_props: Option<&[DavProperty]>) ...
FILE: crates/dav/src/principal/propsearch.rs
type PrincipalPropSearch (line 21) | pub(crate) trait PrincipalPropSearch: Sync + Send {
method handle_principal_property_search (line 22) | fn handle_principal_property_search(
method handle_principal_property_search (line 30) | async fn handle_principal_property_search(
FILE: crates/dav/src/request.rs
type DavRequestHandler (line 57) | pub trait DavRequestHandler: Sync + Send {
method handle_dav_request (line 58) | fn handle_dav_request(
method handle_dav_request (line 564) | async fn handle_dav_request(
type DavRequestDispatcher (line 68) | pub(crate) trait DavRequestDispatcher: Sync + Send {
method dispatch_dav_request (line 69) | fn dispatch_dav_request(
method dispatch_dav_request (line 80) | async fn dispatch_dav_request(
method from (line 737) | fn from(err: dav_proto::parser::Error) -> Self {
method from (line 743) | fn from(err: trc::Error) -> Self {
FILE: crates/directory/src/backend/imap/client.rs
function authenticate (line 18) | pub async fn authenticate(
function authentication_mechanisms (line 72) | pub async fn authentication_mechanisms(&mut self) -> Result<u64, ImapErr...
function noop (line 113) | pub async fn noop(&mut self) -> Result<(), ImapError> {
function logout (line 123) | pub async fn logout(&mut self) -> Result<(), ImapError> {
function expect_greeting (line 132) | pub async fn expect_greeting(&mut self) -> Result<(), ImapError> {
function read_line (line 145) | pub async fn read_line(&mut self) -> Result<Vec<u8>, ImapError> {
function write (line 173) | pub async fn write(&mut self, bytes: &[u8]) -> Result<(), std::io::Error> {
function imap_auth (line 189) | async fn imap_auth() {
FILE: crates/directory/src/backend/imap/config.rs
method from_config (line 17) | pub fn from_config(config: &mut Config, prefix: impl AsKey) -> Option<Se...
FILE: crates/directory/src/backend/imap/lookup.rs
method query (line 15) | pub async fn query(&self, query: QueryBy<'_>) -> trc::Result<Option<Prin...
method email_to_id (line 63) | pub async fn email_to_id(&self, _address: &str) -> trc::Result<Option<u3...
method rcpt (line 67) | pub async fn rcpt(&self, _address: &str) -> trc::Result<RcptType> {
method vrfy (line 71) | pub async fn vrfy(&self, _address: &str) -> trc::Result<Vec<String>> {
method expn (line 75) | pub async fn expn(&self, _address: &str) -> trc::Result<Vec<String>> {
method is_local_domain (line 79) | pub async fn is_local_domain(&self, domain: &str) -> trc::Result<bool> {
FILE: crates/directory/src/backend/imap/mod.rs
type ImapDirectory (line 20) | pub struct ImapDirectory {
type ImapConnectionManager (line 25) | pub struct ImapConnectionManager {
type ImapClient (line 34) | pub struct ImapClient<T: AsyncRead + AsyncWrite> {
type ImapError (line 42) | pub enum ImapError {
method from (line 53) | fn from(error: std::io::Error) -> Self {
method fmt (line 59) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: crates/directory/src/backend/imap/pool.rs
type Type (line 18) | type Type = ImapClient<TlsStream<TcpStream>>;
type Error (line 19) | type Error = ImapError;
method create (line 21) | async fn create(&self) -> Result<ImapClient<TlsStream<TcpStream>>, ImapE...
method recycle (line 41) | async fn recycle(
FILE: crates/directory/src/backend/imap/tls.rs
function start_tls (line 17) | async fn start_tls(
function into_tls (line 37) | async fn into_tls(
function connect (line 62) | pub async fn connect(
FILE: crates/directory/src/backend/internal/lookup.rs
type DirectoryStore (line 18) | pub trait DirectoryStore: Sync + Send {
method query (line 19) | async fn query(&self, by: QueryParams<'_>) -> trc::Result<Option<Princ...
method email_to_id (line 20) | async fn email_to_id(&self, address: &str) -> trc::Result<Option<u32>>;
method is_local_domain (line 21) | async fn is_local_domain(&self, domain: &str) -> trc::Result<bool>;
method rcpt (line 22) | async fn rcpt(&self, address: &str) -> trc::Result<RcptType>;
method vrfy (line 23) | async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>>;
method expn (line 24) | async fn expn(&self, address: &str) -> trc::Result<Vec<String>>;
method expn_by_id (line 25) | async fn expn_by_id(&self, id: u32) -> trc::Result<Vec<String>>;
method query (line 29) | async fn query(&self, by: QueryParams<'_>) -> trc::Result<Option<Princ...
method email_to_id (line 79) | async fn email_to_id(&self, address: &str) -> trc::Result<Option<u32>> {
method is_local_domain (line 87) | async fn is_local_domain(&self, domain: &str) -> trc::Result<bool> {
method rcpt (line 95) | async fn rcpt(&self, address: &str) -> trc::Result<RcptType> {
method vrfy (line 112) | async fn vrfy(&self, address: &str) -> trc::Result<Vec<String>> {
method expn (line 144) | async fn expn(&self, address: &str) -> trc::Result<Vec<String>> {
method expn_by_id (line 158) | async fn expn_by_id(&self, list_id: u32) -> trc::Result<Vec<String>> {
FILE: crates/directory/src/backend/internal/manage.rs
type PrincipalList (line 36) | pub struct PrincipalList<T> {
type UpdatePrincipal (line 41) | pub struct UpdatePrincipal<'x> {
type ChangedPrincipals (line 51) | pub struct ChangedPrincipals(AHashMap<u32, ChangedPrincipal>);
method new (line 2680) | pub fn new() -> Self {
method from_change (line 2684) | pub fn from_change(principal_id: u32, principal_type: Type, field: Pri...
method add_change (line 2690) | pub fn add_change(&mut self, principal_id: u32, principal_type: Type, ...
method add_member_change (line 2731) | pub fn add_member_change(
method add_deletion (line 2770) | pub fn add_deletion(&mut self, principal_id: u32, principal_type: Type) {
method contains (line 2786) | pub fn contains(&self, principal_id: u32) -> bool {
method iter (line 2790) | pub fn iter(&'_ self) -> std::collections::hash_map::Iter<'_, u32, Cha...
method is_empty (line 2794) | pub fn is_empty(&self) -> bool {
type ChangedPrincipal (line 54) | pub struct ChangedPrincipal {
method new (line 2800) | pub fn new(typ: Type) -> Self {
method update_member_change (line 2808) | pub fn update_member_change(&mut self, member_change: bool) -> &mut Se...
method update_name_change (line 2813) | pub fn
Copy disabled (too large)
Download .json
Condensed preview — 1534 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (12,327K chars).
[
{
"path": ".dockerignore",
"chars": 99,
"preview": "// Ignore everything\n*\n\n// Allow what is needed\n!crates\n!tests\n!resources\n\n!Cargo.lock\n!Cargo.toml\n"
},
{
"path": ".editorconfig",
"chars": 196,
"preview": "# https://EditorConfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 4\nindent_style = space\nend_of_line = lf\ninsert"
},
{
"path": ".github/DISCUSSION_TEMPLATE/issue-triage.yml",
"chars": 5680,
"preview": "labels: [\"triage\"]\nbody:\n - type: markdown\n attributes:\n value: |\n > [!IMPORTANT]\n > Please revie"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 944,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Report an Issue\n url: https://github.com/stalwartlabs/stalwart/d"
},
{
"path": ".github/ISSUE_TEMPLATE/confirmed_issue.yml",
"chars": 1601,
"preview": "name: Confirmed Bug Report\ndescription: Only for issues that have been discussed and confirmed as bugs in GitHub Discuss"
},
{
"path": ".github/dependabot.yml",
"chars": 847,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/ci.yml",
"chars": 16522,
"preview": "name: \"CI\"\n\non:\n workflow_dispatch:\n inputs:\n Docker:\n required: false\n default: false\n ty"
},
{
"path": ".github/workflows/scorecard.yml",
"chars": 3427,
"preview": "# This workflow uses actions that are not certified by GitHub. They are provided\n# by a third-party and are governed by "
},
{
"path": ".github/workflows/test.yml",
"chars": 1753,
"preview": "name: Test\n\non:\n workflow_dispatch:\n\njobs:\n style:\n name: Check Style\n runs-on: ubuntu-latest\n steps:\n -"
},
{
"path": ".github/workflows/trivy.yml",
"chars": 1144,
"preview": "# trivy ci workflow\nname: trivy\n\non:\n workflow_dispatch:\n push:\n branches: [ \"main\" ]\n pull_request:\n # The bra"
},
{
"path": ".gitignore",
"chars": 65,
"preview": "/target\n.vscode\n.idea\n*.failed\n*_failed\nrun.sh\n_ignore\n.DS_Store\n"
},
{
"path": "CHANGELOG.md",
"chars": 49041,
"preview": "# Change Log\n\nAll notable changes to this project will be documented in this file. This project adheres to [Semantic Ver"
},
{
"path": "CNAME",
"chars": 14,
"preview": "get.stalw.art\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 4285,
"preview": "# Contributing\n\n## Contributions are Temporarily Limited\n\nThank you for your interest in contributing to Stalwart. We ap"
},
{
"path": "Cargo.toml",
"chars": 1253,
"preview": "[workspace]\nresolver = \"2\"\nmembers = [\n \"crates/main\",\n \"crates/types\",\n \"crates/http\",\n \"crates/http-proto\""
},
{
"path": "Dockerfile",
"chars": 2142,
"preview": "# Stalwart Dockerfile\n# Credits: https://github.com/33KK \n\nFROM --platform=$BUILDPLATFORM docker.io/lukemathwalker/cargo"
},
{
"path": "Dockerfile.build",
"chars": 7158,
"preview": "# syntax=docker/dockerfile:1\n# check=skip=FromPlatformFlagConstDisallowed,RedundantTargetPlatform\n\n# *****************\n#"
},
{
"path": "LICENSES/AGPL-3.0-only.txt",
"chars": 34020,
"preview": "GNU AFFERO GENERAL PUBLIC LICENSE\nVersion 3, 19 November 2007\n\nCopyright (C) 2007 Free Software Foundation, Inc. <http:/"
},
{
"path": "LICENSES/LicenseRef-SEL.txt",
"chars": 9796,
"preview": "Stalwart Enterprise License 1.0 (SELv1) Agreement\n=================================================\n\nLast Update: April "
},
{
"path": "README.md",
"chars": 13759,
"preview": "<p align=\"center\">\n <a href=\"https://stalw.art\">\n <img src=\"./img/logo-red.svg\" height=\"150\">\n </a>\n</p>\n\n<h3 a"
},
{
"path": "SECURITY.md",
"chars": 5740,
"preview": "# Security Policy for Stalwart\n\n## Supported Versions\n\nWe provide security updates for the following versions of Stalwar"
},
{
"path": "SECURITY_PROCESS.md",
"chars": 5179,
"preview": "# Stalwart Security Incident Response Checklist\n\n## Phase 1 : Initial Assessment & Validation\n\n### Updates\n\n<< Use this "
},
{
"path": "SECURITY_TEMPLATE.md",
"chars": 3481,
"preview": "# Stalwart Security Advisory\n\n**CVE ID:** CVE-YYYY-NNNNN\n**Publication Date:** YYYY-MM-DD \n**Last Updated:** YYYY-MM-DD"
},
{
"path": "UPGRADING/v0_04.md",
"chars": 3265,
"preview": "# Upgrading from `v0.4.0` to `v0.4.x`\n\n- Replace the binary with the new version.\n- Restart the service.\n\n# Upgrading fr"
},
{
"path": "UPGRADING/v0_05.md",
"chars": 5910,
"preview": "# Upgrading from `v0.5.2` to `v0.5.3`\n\n- The following configuration attributes have been renamed, see [store.toml](http"
},
{
"path": "UPGRADING/v0_06.md",
"chars": 997,
"preview": "# Upgrading from `v0.5.3` to `v0.6.0`\n\n- In order to support [expressions](https://stalw.art/docs/configuration/expressi"
},
{
"path": "UPGRADING/v0_07.md",
"chars": 4426,
"preview": "# Upgrading from `v0.6.0` to `v0.7.0`\n\nVersion `0.7.0` of Stalwart introduces significant improvements and features that"
},
{
"path": "UPGRADING/v0_08.md",
"chars": 3816,
"preview": "# Upgrading from `v0.7.3` to `v0.8.0`\n\nVersion `0.8.0` includes both performance and security enhancements that require "
},
{
"path": "UPGRADING/v0_09.md",
"chars": 1588,
"preview": "# Upgrading from `v0.8.x` to `v0.9.0`\n\nVersion `0.9.0` introduces significant internal improvements while maintaining co"
},
{
"path": "UPGRADING/v0_10.md",
"chars": 1959,
"preview": "\n# Upgrading from `v0.9.x` to `v0.10.0`\n\n## Important Notes\n\n- In version `0.10.0` accounts are associated with roles an"
},
{
"path": "UPGRADING/v0_11.md",
"chars": 1001,
"preview": "\n# Upgrading from `v0.10.x` to `v0.11.0`\n\nVersion `0.11.0` introduces breaking changes to the spam filter configuration."
},
{
"path": "UPGRADING/v0_12.md",
"chars": 4306,
"preview": "\n# Upgrading from `v0.11.x` to `v0.12.x`\n\n## Important Notes\n\nVersion `0.12.x` introduces significant improvements such "
},
{
"path": "UPGRADING/v0_13.md",
"chars": 3910,
"preview": "# Upgrading from `v0.12.x` (and `v0.11.x`) to `v0.13.x`\n\n## Important Notes\n\nVersion `0.13.x` introduces a significant r"
},
{
"path": "UPGRADING/v0_14.md",
"chars": 2367,
"preview": "# Upgrading from `v0.13.x` to `v0.14.x`\n\n## Binary installation\n\n- Stop Stalwart in **every single node of your cluster*"
},
{
"path": "UPGRADING/v0_15.md",
"chars": 8067,
"preview": "# Upgrading from `v0.14.x` to `v0.15.x`\n\nStalwart `v0.15.x` introduces **breaking changes** to both the **database schem"
},
{
"path": "api/v1/openapi.yml",
"chars": 84034,
"preview": "# SPDX-FileCopyrightText: 2025 Stalwart Labs LLC <hello@stalw.art>\n#\n# SPDX-License-Identifier: AGPL-3.0-only OR License"
},
{
"path": "crates/cli/Cargo.toml",
"chars": 1058,
"preview": "[package]\nname = \"stalwart-cli\"\ndescription = \"Stalwart Server CLI\"\nauthors = [\"Stalwart Labs LLC <hello@stalw.art>\"]\nli"
},
{
"path": "crates/cli/src/main.rs",
"chars": 10271,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/account.rs",
"chars": 13415,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/cli.rs",
"chars": 14968,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/database.rs",
"chars": 5032,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/dkim.rs",
"chars": 1998,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/domain.rs",
"chars": 4298,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/export.rs",
"chars": 14171,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/group.rs",
"chars": 5590,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/import.rs",
"chars": 39879,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/list.rs",
"chars": 5584,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/mod.rs",
"chars": 6805,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/queue.rs",
"chars": 17894,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/cli/src/modules/report.rs",
"chars": 9008,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/Cargo.toml",
"chars": 3057,
"preview": "[package]\nname = \"common\"\nversion = \"0.15.5\"\nedition = \"2024\"\nbuild = \"build.rs\"\n\n[dependencies]\nutils = { path = \"../ut"
},
{
"path": "crates/common/build.rs",
"chars": 3151,
"preview": "use std::collections::HashMap;\nuse std::env;\nuse std::fs;\nuse std::path::Path;\n\nfn main() {\n let out_dir = env::var(\""
},
{
"path": "crates/common/src/addresses.rs",
"chars": 6128,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/access_token.rs",
"chars": 20025,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/mod.rs",
"chars": 11167,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/config.rs",
"chars": 12438,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/crypto.rs",
"chars": 1433,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/introspect.rs",
"chars": 2591,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/mod.rs",
"chars": 1758,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/oidc.rs",
"chars": 4941,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/registration.rs",
"chars": 5383,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/oauth/token.rs",
"chars": 8522,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/rate_limit.rs",
"chars": 3059,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/roles.rs",
"chars": 7667,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/auth/sasl.rs",
"chars": 3236,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/groupware.rs",
"chars": 9318,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/imap.rs",
"chars": 1870,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/inner.rs",
"chars": 8221,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/jmap/capabilities.rs",
"chars": 10645,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/jmap/mod.rs",
"chars": 179,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/jmap/settings.rs",
"chars": 17785,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/mod.rs",
"chars": 9056,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/network.rs",
"chars": 12519,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/scripts.rs",
"chars": 14849,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/server/listener.rs",
"chars": 12232,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/server/mod.rs",
"chars": 1835,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/server/tls.rs",
"chars": 17508,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/auth.rs",
"chars": 16062,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/mod.rs",
"chars": 3636,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/queue.rs",
"chars": 30496,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/report.rs",
"chars": 9633,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/resolver.rs",
"chars": 13681,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/session.rs",
"chars": 31613,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/smtp/throttle.rs",
"chars": 3001,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/spamfilter.rs",
"chars": 27768,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/storage.rs",
"chars": 867,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/config/telemetry.rs",
"chars": 34669,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/core.rs",
"chars": 35587,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/dns.rs",
"chars": 2801,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/enterprise/alerts.rs",
"chars": 5396,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/enterprise/config.rs",
"chars": 16281,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/enterprise/license.rs",
"chars": 9064,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/enterprise/llm.rs",
"chars": 7999,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/enterprise/mod.rs",
"chars": 9074,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/enterprise/undelete.rs",
"chars": 3384,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/expr/eval.rs",
"chars": 26291,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/functions/array.rs",
"chars": 1529,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/functions/asynch.rs",
"chars": 13420,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/functions/email.rs",
"chars": 2858,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/functions/misc.rs",
"chars": 1763,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/functions/mod.rs",
"chars": 3638,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/functions/text.rs",
"chars": 10690,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/if_block.rs",
"chars": 7677,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/mod.rs",
"chars": 14390,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/parser.rs",
"chars": 11766,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/expr/tokenizer.rs",
"chars": 15169,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/i18n.rs",
"chars": 1009,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/ipc.rs",
"chars": 7562,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/lib.rs",
"chars": 33170,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/acme/cache.rs",
"chars": 3636,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/acme/directory.rs",
"chars": 12158,
"preview": "// Adapted from rustls-acme (https://github.com/FlorianUekermann/rustls-acme), licensed under MIT/Apache-2.0.\n\nuse super"
},
{
"path": "crates/common/src/listener/acme/jose.rs",
"chars": 4638,
"preview": "// Adapted from rustls-acme (https://github.com/FlorianUekermann/rustls-acme), licensed under MIT/Apache-2.0.\n\nuse base6"
},
{
"path": "crates/common/src/listener/acme/mod.rs",
"chars": 4280,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/acme/order.rs",
"chars": 18309,
"preview": "// Adapted from rustls-acme (https://github.com/FlorianUekermann/rustls-acme), licensed under MIT/Apache-2.0.\n\nuse chron"
},
{
"path": "crates/common/src/listener/acme/resolver.rs",
"chars": 4017,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/asn.rs",
"chars": 16155,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/blocked.rs",
"chars": 10918,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/limiter.rs",
"chars": 1847,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/listen.rs",
"chars": 15736,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/mod.rs",
"chars": 8625,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/stream.rs",
"chars": 4010,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/listener/tls.rs",
"chars": 7203,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/backup.rs",
"chars": 11586,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/boot.rs",
"chars": 24893,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/config.rs",
"chars": 20826,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/console.rs",
"chars": 11211,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/mod.rs",
"chars": 4134,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/reload.rs",
"chars": 4751,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/restore.rs",
"chars": 7522,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/manager/webadmin.rs",
"chars": 6198,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/array.rs",
"chars": 4323,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/email.rs",
"chars": 2380,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/header.rs",
"chars": 3191,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/image.rs",
"chars": 2653,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/misc.rs",
"chars": 3062,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/mod.rs",
"chars": 7240,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/text.rs",
"chars": 8864,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/unicode.rs",
"chars": 2544,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/functions/url.rs",
"chars": 2078,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/mod.rs",
"chars": 2106,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/dns.rs",
"chars": 6159,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/exec.rs",
"chars": 1397,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/headers.rs",
"chars": 764,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/http.rs",
"chars": 1760,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/llm_prompt.rs",
"chars": 2796,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/lookup.rs",
"chars": 4874,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/mod.rs",
"chars": 3079,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/query.rs",
"chars": 2974,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/scripts/plugins/text.rs",
"chars": 2632,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/sharing/acl.rs",
"chars": 3663,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/sharing/mod.rs",
"chars": 1304,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/sharing/notification.rs",
"chars": 2653,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/sharing/resources.rs",
"chars": 3899,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/storage/blob.rs",
"chars": 994,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/storage/index.rs",
"chars": 25442,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/storage/mod.rs",
"chars": 183,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/storage/state.rs",
"chars": 1090,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/metrics/mod.rs",
"chars": 371,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/metrics/otel.rs",
"chars": 3920,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/metrics/prometheus.rs",
"chars": 3749,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/metrics/store.rs",
"chars": 11360,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/telemetry/mod.rs",
"chars": 4298,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/tracers/journald.rs",
"chars": 15657,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/tracers/log.rs",
"chars": 4923,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/tracers/mod.rs",
"chars": 411,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/tracers/otel.rs",
"chars": 10569,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/tracers/stdout.rs",
"chars": 2639,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/common/src/telemetry/tracers/store.rs",
"chars": 12364,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: LicenseRef-SEL\n *\n"
},
{
"path": "crates/common/src/telemetry/webhooks/mod.rs",
"chars": 5673,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/Cargo.toml",
"chars": 720,
"preview": "[package]\nname = \"dav\"\nversion = \"0.15.5\"\nedition = \"2024\"\n\n[dependencies]\ndav-proto = { path = \"../dav-proto\" }\ncommon"
},
{
"path": "crates/dav/src/calendar/copy_move.rs",
"chars": 35858,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/delete.rs",
"chars": 8220,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/freebusy.rs",
"chars": 14968,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/get.rs",
"chars": 3927,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/mkcol.rs",
"chars": 4801,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/mod.rs",
"chars": 5961,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/proppatch.rs",
"chars": 20433,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/query.rs",
"chars": 26564,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/scheduling.rs",
"chars": 15334,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/calendar/update.rs",
"chars": 18330,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/copy_move.rs",
"chars": 33873,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/delete.rs",
"chars": 7065,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/get.rs",
"chars": 3982,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/mkcol.rs",
"chars": 4588,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/mod.rs",
"chars": 4116,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/proppatch.rs",
"chars": 16606,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/query.rs",
"chars": 7583,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/card/update.rs",
"chars": 10042,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/common/acl.rs",
"chars": 20948,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/common/lock.rs",
"chars": 31119,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/common/mod.rs",
"chars": 18075,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/common/propfind.rs",
"chars": 76647,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/common/uri.rs",
"chars": 7201,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/copy_move.rs",
"chars": 28900,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/delete.rs",
"chars": 3218,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/get.rs",
"chars": 3899,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/mkcol.rs",
"chars": 4655,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/mod.rs",
"chars": 5503,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/proppatch.rs",
"chars": 10445,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
},
{
"path": "crates/dav/src/file/update.rs",
"chars": 10878,
"preview": "/*\n * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>\n *\n * SPDX-License-Identifier: AGPL-3.0-only OR L"
}
]
// ... and 1334 more files (download for full content)
About this extraction
This page contains the full source code of the stalwartlabs/stalwart GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1534 files (11.2 MB), approximately 3.0M tokens, and a symbol index with 10791 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.