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.
- `directory:read` for api.user.findPeople, with at least 3 characters,
at most 20 ids, 20 results and 10 lookups a minute, in the directory
of the account the call names; one load in flight per client.
- Plugins hear `group` only for accounts the server confirmed are group
principals; the policy's fallback stays for the admin's scopes.
- The email.* keyword methods refuse $draft, $junk, $notjunk and
$phishing.
- A plugin keeps at most 4 KB in a mailbox and reads it 30 times a
minute; the email:write consent text says others in a team mailbox
can read it.
- email.updateKeywords also changes the rows of expanded conversations.
The first version took a template missing from the account's Inbox
metadata as deleted, skipped the browser's own list once the account
held anything, wrote the marker before the settings blob had loaded,
and let a round overwrite edits made while it ran. Each of these could
drop templates, or bring deleted ones back.
Now the marker entry `org.bulwarkmail.templates` holds tombstones
(90 days, at most 8 KB, oldest dropped first) and only a tombstone
deletes; a missing entry is uploaded again. Every round merges the
browser's list in when it is this account's, each version once, minus
what a newer tombstone deleted. While settings sync hasn't loaded the
account's settings, the list isn't used and no marker is written; a
blob that loads later is merged into the account's copy. The settings
blob drops its templates only once the marker is on the server. Without
settings sync the list goes into the first account that answers only.
A round that saw changes while it ran plans again against the server as
it left it. An answer without the metadata property counts as
unsupported. Changes move `updatedAt` past the previous value, dateless
synced templates get a fixed early date, and ids that don't fit a
metadata key get a new id derived from the old one. Queued changes go
out before an account signs out; a full sign-out keeps unsent templates
and deletions.
Team templates are written only if the entry is still the version the
edit started from ("Changed by someone else"), never carry Bcc, and a
refusal is told apart by Stalwart's error type. The template manager's
lists are a real tab list with arrow keys and 44 px row buttons on
phones.
What the team inbox plugin needs, kept general for other plugins:
- `api.ui.setListFilters`: keyword filters drawn as chips in the list
header of the folders they apply to (by account kind and folder
role). A chip the user turns on is ANDed into the folder's query and
comes off with one click; a keyword change a filter tests loads the
list again (ui:message-list).
- Actions get `accounts`, `hasKeyword` and `notKeyword`, so a button
shows only on messages of group accounts, or of a keyword state; the
click of message-row-actions and reader-actions carries the message's
`accountId`.
- `api.email.updateKeywords`: several keywords in one change, through
the list for a listed message (email:write).
- `api.user.getSelf`, `getMailAccounts` and `findPeople`: the user's own
account id (Stalwart's principal id), which accounts are group
accounts, and people from the directory (account:read).
- `api.accountData`: a plugin's own entry in a mail account's shared
Inbox metadata on Stalwart 1.0 (email:read / email:write).
- Row badges take an `icon`.
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