Stalwart's x:ArchivedItem/query without calculateTotal scans ids
ascending, stops at 5000 and only then reverses them, so the newest
items of a large archive never showed, and admin accounts got every
account's items. The review of the branch also found gaps around
account switches, restores and focus.
- Read the archive in pages of 500 with calculateTotal, newest first,
stop at a whole page older than the days limit, and offer
"Show older" after 2000 items; detection asks for one item.
- Send the accountId filter and fall back without it on
unsupportedFilter; keep only items of the account, never one without
an account id.
- Ask nothing until config and policy are loaded and the policy is the
current account's; the later check after a refusal is forced.
- Show the Trash link only when the archive holds a message inside the
days limit; the Settings page shows whenever the server has the
feature and says that archiving must be on in Stalwart.
- Restore: notFound leaves the list with a note, forbidden hides the
page, results for another account are dropped, the button keeps focus.
- Forget what servers said at a full sign-out.
The first version wrote the whole tag list on every change, guessed a
group when the server wouldn't say, and treated a failed read like a
server without metadata. Now:
- Definitions are a map by tag id under `tags`, and each change patches
one tag (`metadata/org.bulwarkmail.tags/tags/<id>`), so two members
adding tags at once both keep theirs. Fields and colors this version
doesn't know survive. The `{ list }` and bare-array shapes are still
read and converted by the first save.
- Shared tags appear only for confirmed group principals. A failed
principal lookup keeps the user's own tags and asks again later.
- "No metadata advertised" (0.16) and "the read failed" are separate.
A failed read keeps the last good tags; a failed save keeps the change,
says so, and sends it with the next good read after the client's
pause.
- Push reloads wait for 5 s of quiet and skip the echo of our own save;
a returning tab reloads definitions only, and the scan for unnamed tags
runs once per sign-in and then at most every 30 minutes.
- The editor names its buttons after the tag, shows the delete warning
and 44 px buttons on phones, returns focus to the edit button, and
asks for Inbox rights only for confirmed groups.
Change used to pre-fill the closest choice and then replace everything
of that type, so a folder added after "all", a single non-Inbox folder,
a non-default calendar, free/busy only or manager rights were narrowed
or widened on Save. Now a type gets a choice only when the grants match
it exactly; anything else starts at "Keep as it is", which leaves that
type out of the patch. Mixed levels keep each type's rights.
Also in the Delegates page:
- Change and Remove wait, with Try again, while a type couldn't be read
- an answer from the account before an account switch is dropped
- calendars, contacts and files follow their feature gates
- Remove says it covers what was shared from the user's own account
- typing your own address says "That's you"
- groups named only by the session get the group badge
- on Stalwart 1.0 the read hint says read delegates can flag mail
- the person list is plain buttons, not a listbox without arrow keys
- the rights follow sharingRights
Admins write an HTML and a plain-text signature with placeholders on
Organisation > Signatures, per scope. Users fill in the details it asks
for once, under Settings > Account. Without a lock it is the default for
addresses without a signature of their own; locked or hidden, it
replaces every signature.
- `lib/org-signature.ts` fills the templates: values escaped, lines whose
placeholders are all empty dropped
- the composer applies it right before the plugin signature, so new mail,
replies, forwards, re-opened drafts, plain text and identity swaps all
take it the way they take an identity signature; quick reply too
- a send finaliser puts a locked signature back once when it was deleted
- the identity editor shows the filled-in signature read-only with "Set
by your organisation" when locked, and no editor when hidden
- `signatureDetails` is a synced setting
Part 3 of 3 of the account archive (#1198). Signing in on a browser that
knows no other account, with a list saved for that account, opens a dialog
asking for the backup password and restores the list as Settings does.
Not now hides the offer for that account in this browser; the restore
stays in Settings.
Some user-facing strings still said "Bulwark" on a deployment with its own
APP_NAME: Settings > General > Default apps (protocol handlers), the "Open
Bulwark" notification, the rate-limit banner and toast, the plugin connect
dialog, one plugin permission text and the connector page.
These strings now take an {appName} placeholder, filled by productName():
the configured APP_NAME, or "Bulwark" when it is unset or the default
"Webmail" (the same rule as the TOTP issuer and the About card, #1160).
A stock install reads as before.
The settings search (the settings page and api.app.searchSettings) indexes
these texts with the name filled in, so "bulwark" or the configured name
finds Default apps and no result carries the raw placeholder.
Locales: the 13 keys in every locale that has "Bulwark" in them. Languages
that inflect the name (cs, et, hu, ko, ro, sk, tr) use a neutral form such
as "{appName} uygulamasında" instead of a declined "Bulwark'ta"; a native
check of those is welcome.
Not changed on purpose: the mobile app, push relay, Lite, demo and admin
texts, which speak about Bulwark itself.
Closes#1314
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>