79 lines
3.8 KiB
Markdown
79 lines
3.8 KiB
Markdown
# Development
|
|
|
|
## Architecture
|
|
|
|
```
|
|
src/
|
|
main.rs CLI (serve, admin, config, device, probe)
|
|
lib.rs public router (ActiveSync, Autodiscover, /, /healthz)
|
|
app.rs application state: settings (ArcSwap), IMAP pool, metrics, lockouts
|
|
config.rs settings model (serde, validation, merging, secrets)
|
|
db.rs SQLite (sqlx, WAL), migrations in migrations/, housekeeping
|
|
server.rs HTTP/1.1 + HTTP/2 listener, optional TLS, graceful shutdown
|
|
wbxml/ WBXML encoder/decoder + MS-ASWBXML code pages
|
|
eas/ ActiveSync protocol
|
|
mod.rs request parsing (plain/base64 query), auth, provisioning, dispatcher
|
|
state.rs SyncKey {uuid}N and states (item fingerprints)
|
|
folders.rs FolderSync / Create / Update / Delete
|
|
sync.rs Sync, GetItemEstimate, MoveItems
|
|
ping.rs Ping and the shared wait-for-changes loop (hanging Sync)
|
|
provision.rs policies, remote wipe
|
|
mailcmd.rs SendMail / SmartReply / SmartForward / MeetingResponse
|
|
itemops.rs ItemOperations, GetAttachment
|
|
misc.rs Settings, Search, ResolveRecipients
|
|
convert/ RFC 5322 / iCalendar / vCard <-> ApplicationData
|
|
backend/
|
|
imap.rs own async IMAP client (literals, UIDPLUS, MOVE, SPECIAL-USE)
|
|
dav.rs CalDAV/CardDAV client
|
|
smtp.rs SMTP (lettre) / sendmail
|
|
ical.rs iCalendar/vCard parser and serializer
|
|
tz.rs EAS <-> IANA time zones, dates
|
|
mime.rs MIME building (SmartReply/Forward)
|
|
mod.rs session: folder hierarchy, fingerprint listings, operations
|
|
autodiscover.rs
|
|
admin.rs panel API, sessions, CSRF, SSE, Prometheus
|
|
web/ panel (dependency-free HTML/CSS/JS, embedded in the binary)
|
|
```
|
|
|
|
### Synchronisation
|
|
|
|
The device state of a folder is a map `item id -> fingerprint` (IMAP: flags; DAV: ETag) stored under the key
|
|
`{uuid}N`. Sync compares the backend listing with the state and sends the differences (deletes -> changes ->
|
|
adds, newest mail first) within `WindowSize`. The new state is stored as `N+1`; the previous one is kept to
|
|
handle lost responses (the device replays the old key). Client adds are idempotent thanks to the `ClientId` map.
|
|
|
|
Ping keeps a folder signature (IMAP `STATUS UIDNEXT/MESSAGES/UNSEEN/HIGHESTMODSEQ`, DAV CTag); a full listing
|
|
comparison only happens when the signature changes.
|
|
|
|
Collection ids that a device uses but that do not exist (Z-Push leftovers) are remembered per device and sent
|
|
as FolderHierarchy Delete on the next FolderSync.
|
|
|
|
## Development environment
|
|
|
|
```bash
|
|
sudo apt install dovecot-imapd # any dovecot >= 2.3
|
|
pip install radicale aiosmtpd
|
|
./dev.sh backends # Dovecot :11143, Radicale :15232, SMTP sink :12525
|
|
./dev.sh seed && ./dev.sh # ActivePush :8081 / panel :9091
|
|
./dev.sh e2e # test of every command against live backends
|
|
```
|
|
|
|
Test accounts: `jan`, `anna`, `biuro`, `kasia` `@test.local`, password `Test-Password-123`.
|
|
|
|
`./dev.sh lint` - rustfmt, clippy `-D warnings`, JS syntax check and WBXML tag name check
|
|
(`scripts/check-wbxml-names.py`). `./dev.sh test` - unit tests (WBXML, IMAP tokenizer, UTF-7, calendar/contact/
|
|
task conversions, time zones, query parser, CIDR, MIME).
|
|
|
|
Protocol debugging: add the login to **ActiveSync -> Logging -> Debug users**; decoded WBXML of requests and
|
|
responses goes to the log.
|
|
|
|
Simulating devices: `active-push probe --device-id F2LX8KQ1N72J --device-type iPhone --model "iPhone 15 Pro" ...`.
|
|
|
|
## Documentation screenshots
|
|
|
|
`tools/dev/screenshots.js` (Playwright) regenerates `docs/images/` from a running dev instance:
|
|
|
|
```bash
|
|
node tools/dev/screenshots.js http://127.0.0.1:9091 admin 'password'
|
|
```
|