Commit Graph
201 Commits
Author SHA1 Message Date
Linus Rath e28e8b4d9c fix: turn scheduled send and the undo-send delay back on for Stalwart #57
RFC 8621 puts the submission limits (`maxDelayedSend`,
`submissionExtensions`) and the mail limits
(`maxSizeAttachmentsPerEmail`) under each account's
`accountCapabilities`. Stalwart advertises an empty object for them at
session level, which is the only place the client looked, so scheduled
send was refused, the undo-send delay silently fell back to an instant
send, the Scheduled view listed nothing and the per-message attachment
cap was never enforced.

The client now reads these from the account that sends (the account's
own submission capability, else the session's primary submission
account, like the webmail), falling back to the session-level object
for servers that only advertise it there. Quick reply, which can send
from a shared account, now checks that account before holding the
message for the undo-send delay.
2026-09-24 18:43:56 +02:00
Linus Rath ee652d39df fix: open mailto links whose address contains a plus
The mailto parser decoded `+` as a space, as in HTML form encoding, so
`mailto:alice+news@partner.example` became "alice news@…", failed
validation and opened nothing; a `+` in a subject or body was turned
into a space as well. RFC 6068 only uses percent-encoding, so a `+` now
stays a plus, like the webmail's `parseMailtoUrl`.

App compose links (`bulwarkmobile://compose?…`) went through the same
parser after `URLSearchParams.toString()`, which writes spaces as `+`.
They are now re-encoded with percent-encoding, and the recipient is read
from the `to=` parameter only, which also stops it from being added
twice.
2026-09-24 18:43:43 +02:00
Linus Rath 06e89422bd fix: open the composer for mailto links sent with SENDTO
Most apps start an email with `ACTION_SENDTO` and a `mailto:` URI. The
manifest offered the app for it, but React Native's Linking only
forwards VIEW intents, so the app opened on the inbox instead of the
composer.

MainActivity now rewrites a `SENDTO mailto:` intent into the equivalent
`VIEW mailto:` link before React Native sees it, on a cold start and
when the running app receives it. The EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC,
EXTRA_SUBJECT and EXTRA_TEXT extras are folded into the link's query.
Bcc recipients of a mailto link now reach the composer too; they were
dropped for VIEW links as well.
2026-09-24 18:43:43 +02:00
Linus Rath cd4ce9d08b fix: upload files shared into the app with their real name and type
Sharing a photo or document from another app into Bulwark failed every
time: the upload task was handed the share's `content://` URI, but it
can only stream from a file path, so it failed with "Directory for
'/external/images/media/…' doesn't exist". The attachment was also named
after the URI's last segment (a MediaStore row id such as "1000000027"),
and SEND_MULTIPLE shares only carried a wildcard type like `image/*`.

- `uploadBlob` copies `content://` URIs into the cache, uploads the copy
  and deletes it afterwards, also when the upload fails
- `ShareIntentStore` asks the providing app for the display name, size
  and MIME type when the intent arrives, falling back to the URI segment
  plus an extension for the MIME type
- the composer gets the real name, type and size, so the size limit
  check now applies to shared files too
2026-09-24 18:43:43 +02:00
Linus Rath 8d7fbfc99c fix: clear the Files selection on Android back instead of switching to Mail 2026-09-24 18:41:23 +02:00
Linus Rath caea3d0c60 fix: offer sharing files and calendars with other users on Stalwart
`supportsSharing()` required `urn:ietf:params:jmap:principals:owner`,
which Stalwart advertises nowhere; its session only has `principals` and
`principals:availability`. The file menu therefore never showed
"Sharing & access", and `getPrincipals()` returned nothing, so the
calendar share sheet had no one to offer either.

- Gate sharing on `urn:ietf:params:jmap:principals`, like the webmail's
  `supportsPrincipals()`.
- Keep `principals:owner` out of FileNode requests unless the server
  advertises it, since an unknown capability in `using` fails the whole
  request (why the gate had been tied to it).
- Page the principal lookup by `maxObjectsInGet`, as the webmail does:
  one unbounded `Principal/query` fed every id to `Principal/get`, which
  the server refuses once the directory has more than 500 entries.
2026-09-24 18:41:23 +02:00
Linus Rath 00ad2f49fb fix: show an error when the server refuses a file rename, move or delete
`updateFileNode` and `deleteFileNodes` only looked for `notUpdated` and
`notDestroyed` in the first method response. A method-level `error`
reply (e.g. `forbidden`) has neither, so a refused rename, move or delete
reported success and the Files tab silently refreshed to the old state.

Every `FileNode/set` in `src/api/files.ts` now goes through
`requireMethodResult`, so the error reaches the existing alert in the
Files screen and the share sheet with the server's description.
2026-09-24 18:41:23 +02:00
Linus Rath 4eb8c47670 fix: list every file when the account holds more than 500 nodes #1069
The Files tab read the whole drive with `FileNode/get ids:null`, which
Stalwart silently caps at `maxObjectsInGet` (500 by default). Anything
past that, including folders created after the first 500 files and
everything inside them, never showed up, both for the own drive and for
shared accounts.

A full first page now counts as truncated, as in the webmail: the
remaining ids come from paging `FileNode/query`, are fetched in
`maxObjectsInGet`-sized `FileNode/get` batches packed into as few
requests as `maxCallsInRequest` allows, and parents that are still
unknown afterwards are fetched by id, which recovers folders on Stalwart
before 0.16.6 where the query returns files only. If the paging fails,
the first page is kept as before.
2026-09-24 18:41:23 +02:00
Linus Rath bd42206686 fix: accept a pasted JMAP session URL as the server address #971 2026-09-24 18:40:43 +02:00
Linus Rath ab845783ab fix: stop adding an OAuth account from signing in the current user again
Adding a second account through the server's own OAuth opened the
authorization endpoint in the shared system browser with no `prompt`,
so the identity provider found the session of the account that was
already signed in and quietly handed back the same user.

When adding an account, the PKCE flow now sends
`prompt=select_account` like the webmail does (5771a213), or
`prompt=login` when the server's metadata lists no account picker, and
on iOS it runs the auth session ephemerally so the browser's cookies
don't carry over. The webmail hand-off gets the ephemeral session too.
Android's Custom Tabs have no private mode, so there the prompt is the
only guard.
2026-09-24 18:40:43 +02:00
Linus Rath 5f3f584ca8 fix: auto-send read receipts only for the message on screen and clean up failed ones
With "Always send" the banner's auto-send ran in every page the viewer
pager keeps mounted, so opening one message also answered the receipt
requests of its unseen neighbours. The receipt is imported into Sent
before it is submitted, so a refused submission left a "Read: ..." copy
there, and the failure cleared the per-instance guard, so the next
render or remount imported another one.

- the pager marks the page on screen `active`, and the banner only
  auto-sends there
- an automatic receipt is tried once per message per session, keyed by
  account and id, so a failure or a remounted page does not send again
- `sendReadReceipt` destroys the imported copy when the submission
  fails, which also covers the manual "Send receipt" button
2026-09-24 18:36:15 +02:00
Linus Rath cb6ddd6fcf fix: strip CR/LF from read-receipt header values (GHSA-w38p-hpqv-g89c)
The read receipt is assembled as raw RFC 5322 text, and every header
value in it comes from the message being answered. Stalwart returns
subjects already RFC 2047-decoded, so a sender could hide CRLF in an
encoded-word subject (or in the Message-ID or
Disposition-Notification-To) and have it interpolated verbatim. That
let them add headers such as Reply-To, or a whole body, to a message
the user's own account files in Sent and submits. `encodeHeaderWord`
passed any pure-ASCII value through untouched, CR/LF included.

Port the webmail fix: free-text values go through
`stripHeaderControls` (controls collapse to a space, then RFC 2047 if
non-ASCII), address-like values and message-ids through `headerAtom`
(controls and whitespace removed), and the From display name is quoted
when it uses specials.
2026-09-24 18:36:15 +02:00
Linus Rath ee04e95d4f feat: add UnifiedPush as an alternative to FCM for push notifications 2026-09-24 18:17:43 +02:00
Linus Rath f228257ec9 fix: stop the viewer crashing on any message with attachments by keeping store selectors referentially stable 2026-08-29 22:41:09 +02:00
Linus Rath a02e7f8a49 test: add an opt-in live Stalwart integration suite 2026-08-29 22:28:42 +02:00
Linus Rath ea1f53f550 fix: keep the created message id when the server answers a send with an implicit filing update 2026-08-29 22:28:41 +02:00
Linus Rath 3f2dfe83ee chore: merge upstream fixes for reply threading, iOS session auth drop, calendar paging and the camera prompt (#35, #38, #39, #40) 2026-08-29 20:16:33 +02:00
Linus Rath 96272b6e17 fix: confirm the host before opening meeting links from calendar events and invitations 2026-08-29 18:56:46 +02:00
Linus Rath 2abea9742e feat: add a send-invitations switch and custom reminder offsets, keeping alerts the picker cannot show 2026-08-29 18:53:58 +02:00
Linus Rath 5fe8e407c7 feat: duplicate, share as .ics and copy the meeting link of an event; link imported UIDs instead of skipping them (#113) 2026-08-29 18:49:08 +02:00
Linus Rath 0205aa0e1c feat: cross-account moves via blob import, shared-account offline sync, parked failed outbox ops with retry and back-off, archive replay with foldering, localized relative dates 2026-08-29 18:47:12 +02:00
Linus Rath 09c24fa805 feat: edit tasks with description, priority and due time, filter the list and overlay due tasks on the calendar 2026-08-29 18:44:36 +02:00
Linus Rath 86c3ab9f28 fix: escape the line-break regex in the quick-reply prefill 2026-08-29 18:42:26 +02:00
Linus Rath f9ae4423e9 fix: sweep stale export files at launch and carry quick-reply text into the composer 2026-08-29 18:41:49 +02:00
Linus Rath 8e1d03c746 feat: fire calendar and task reminders as local notifications 2026-08-29 18:41:06 +02:00
Linus Rath a222e89611 refactor: merge the quick reply's email-body imports 2026-08-29 18:40:42 +02:00
Linus Rath 6ae21d5690 feat: folder actions, tags and unified views in the drawer, folder parent/role editing, tag discovery and account-routed unified actions (#404, #498, #495, #175, #658, #855) 2026-08-29 18:39:45 +02:00
Linus Rath d2ed27fd3b feat: conversation view with collapsible cards, header details, auth chips, unsubscribe and read-receipt banners, attachment preview and zip, embedded-message and TNEF unwrap in the reader (#480, #830, #891) 2026-08-29 18:38:53 +02:00
Linus Rath ee3b3ffcc3 test: mock the Expo native modules the stores reach transitively 2026-08-29 18:36:08 +02:00
Linus Rath 0f80e98fbc feat: localize the calendar, add Saturday week start, ISO week numbers, month chips and 12h labels (#666) 2026-08-29 18:35:46 +02:00
Linus Rath bf92a00199 test: cover the draft route-param builder and tick the composer parity items 2026-08-29 18:34:09 +02:00
Linus Rath c659b5489c feat: signature, read-receipt, empty-subject, autosave and sub-address settings, identity Reply-To/Bcc/HTML signature with a default identity, template category/favourite, and reschedule/send-now/edit on the scheduled screen (#507) 2026-08-29 18:33:22 +02:00
Linus Rath 3a8264c7f7 feat: translate the account security pane 2026-08-29 18:33:16 +02:00
Linus Rath dc3ac4c7ed feat: translate the downloads pane 2026-08-29 18:30:32 +02:00
Linus Rath 0e63d45599 feat: expose a mobile sidebar-apps selector for the drawer 2026-08-29 18:30:08 +02:00
Linus Rath 22697fd111 feat: translate the appearance, reading, composing, identity, template, keyword and sidebar-app panes 2026-08-29 18:29:34 +02:00
Linus Rath fe45a444d3 feat: port the webmail's built-in colour themes to the Themes pane 2026-08-29 18:29:18 +02:00
Linus Rath bea3fc4c42 feat: message-list order presets with the Stalwart keyword-sort polarity probe, avatars-in-junk and folder-count toggles (#718, #498) 2026-08-29 18:28:43 +02:00
Linus Rath 5b72c4d314 feat: drafts with autosave and a save/discard close guard, Bcc, signatures, templates, sub-addressing, From override, read receipts, upload progress, inline-image hydration and an undo-send snackbar in the composer (#188, #849, #848, #540, #570, #684, #163) 2026-08-29 18:28:38 +02:00
Linus Rath 3194b5ece1 feat: tags, pins, recipients, not-spam, delete confirm, folder-scoped search and draft editing in the mail list 2026-08-29 18:23:08 +02:00
Linus Rath f07e039ef0 feat: flip $junk/$notjunk on spam, search all folders by default, keep the search across folders and coalesce refreshes in the mail store (#850, #788, #553, #175) 2026-08-29 18:22:14 +02:00
Linus Rath 8206893860 feat: assess invitation trust, read the iTIP method from the ICS and pick the target calendar in the invitation banner 2026-08-29 18:22:00 +02:00
Linus Rath 18e56163de test: compare locale coverage against the vendored catalog and add missing overlay keys 2026-08-29 18:20:47 +02:00
Linus Rath 3ae9bbe702 feat: add a toast host, prompt dialog, haptics helper and reduce-motion aware animations 2026-08-29 18:20:01 +02:00
Linus Rath 5802caeea9 feat: open deep links, mailto: URLs and share-sheet payloads in the app 2026-08-29 18:20:01 +02:00
Linus Rath 06742ef7d5 fix: render HTML-only mail as HTML, keep stylesheets and block every external-content vector in the reader (#46, #49) 2026-08-29 18:15:22 +02:00
Linus Rath dae5700688 feat: manage calendars from the drawer and scope, edit and auto-refresh iCal subscriptions 2026-08-29 18:14:48 +02:00
Linus Rath 42ab246cb9 feat: port recipient parsing, reply-identity, sub-addressing, signature, quote-header and template helpers; drop the dead submission api 2026-08-29 18:12:15 +02:00
Linus Rath ddae1e63f2 feat: manage public keys and encryption at rest from account security 2026-08-29 18:11:13 +02:00
Linus Rath 490355c65e feat: list logged-in accounts, storage quota and auth method in account settings 2026-08-29 18:11:13 +02:00