diff --git a/PARITY_CHECKLIST.md b/PARITY_CHECKLIST.md index 74a7e622..b1ff860e 100644 --- a/PARITY_CHECKLIST.md +++ b/PARITY_CHECKLIST.md @@ -98,8 +98,8 @@ the audit's "Fix pass, 2026-09-24" section. | 07 | Filters (Sieve), vacation responder, Files | [docs/parity/07-filters-vacation-files.md](docs/parity/07-filters-vacation-files.md) | 32 | 29 | 3 | 3 | 8 | 21 | | 08 | Settings, sync, push, i18n, themes, updates, misc UI | [docs/parity/08-settings-push-i18n-ui.md](docs/parity/08-settings-push-i18n-ui.md) | 46 | 38 | 8 | 0 | 14 | 32 | | 09 | JMAP client core, live sync, offline, security, S/MIME | [docs/parity/09-jmap-core-sync-security.md](docs/parity/09-jmap-core-sync-security.md) | 56 | 54 | 2 | 7 | 23 | 26 | -| 10 | Webmail 1.10.0 to 1.18.0 and Unreleased (all areas) | [docs/parity/10-webmail-1.10-to-1.18.md](docs/parity/10-webmail-1.10-to-1.18.md) | 112 | 0 | 112 | 10 | 40 | 62 | -| | **Total** | | **527** | **380** | **147** | **42** | **178** | **306** | +| 10 | Webmail 1.10.0 to 1.18.0 and Unreleased (all areas) | [docs/parity/10-webmail-1.10-to-1.18.md](docs/parity/10-webmail-1.10-to-1.18.md) | 112 | 52 | 60 | 10 | 40 | 62 | +| | **Total** | | **527** | **432** | **95** | **42** | **178** | **306** | Counts are of the `- [ ]` and `- [x]` items per file as of 2026-09-24 (row 10: 2026-10-29). Done and diff --git a/docs/parity/10-webmail-1.10-to-1.18.md b/docs/parity/10-webmail-1.10-to-1.18.md index e695c0a6..c3073d14 100644 --- a/docs/parity/10-webmail-1.10-to-1.18.md +++ b/docs/parity/10-webmail-1.10-to-1.18.md @@ -18,22 +18,22 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Security -- [ ] **HTML sanitizer lets `on*` handlers through after a slash** — `P1` — `bug` +- [x] **HTML sanitizer lets `on*` handlers through after a slash** — `P1` — `bug` — fixed in f5e997ba, 07679cbf, 47a1d249, 440a2e7a - What WEB does: DOMPurify for mail and drafts (`lib/email-sanitization.ts`, GHSA-g35q-3gpc-x2rr). - What RN does: the handler regex needs whitespace before `on*` (`src/lib/email-html.ts:142-145`), so `` survives. The viewer WebView (`src/components/EmailBodyView.tsx:793`) and the editor (`src/lib/editor-html.ts:37`, seeded at `src/screens/ComposeScreen.tsx:557`) allow inline script; a received mail can navigate without a tap (`EmailBodyView.tsx:841-843`). - Fix hint: drop every `on*` attribute whatever precedes it (or parse), and stop allowing inline handlers. -- [ ] **A sender can fake a DMARC/DKIM pass in the auth chips** — `P1` — `bug` +- [x] **A sender can fake a DMARC/DKIM pass in the auth chips** — `P1` — `bug` — fixed in ef9561f1, 8adef1e1 - What WEB does: splits Authentication-Results on `;` outside quotes and comments, reads the method at the start of each part, takes DKIM/DMARC from the topmost header only (`lib/email-headers.ts:231`, 8f7124c87). - What RN does: matches `dkim=`/`dmarc=` anywhere in all headers joined (`src/lib/email-headers.ts:143`, `:152`, `:265`); this also feeds invitation trust. - Fix hint: port the web parser. -- [ ] **mailto unsubscribe sends to every address and the confirm hides it** — `P1` — `bug` +- [x] **mailto unsubscribe sends to every address and the confirm hides it** — `P1` — `bug` — fixed in 942f4517, 918571c3 - What WEB does: one address, ignores `to=`/`cc=`, caps subject and body, shows them in the confirm (`lib/validation.ts:180`, `components/email/unsubscribe-banner.tsx:42`, f0aa0eeda). - What RN does: sends to every to/cc and `to=` address with the sender's subject and body (`src/lib/unsubscribe.ts:95-113`); the confirm only says an email will be sent (`src/components/email/UnsubscribeBanner.tsx:139-147`). - Fix hint: port parseUnsubscribeMailto and the confirm text. -- [ ] **A crafted winmail.dat freezes the JS thread** — `P1` — `bug` +- [x] **A crafted winmail.dat freezes the JS thread** — `P1` — `bug` — fixed in 855d304b - What WEB does: clamps the MAPI value count and stops on a read that doesn't advance (`lib/tnef.ts:173`, 012fe6eda). - What RN does: trusts the count (up to 2^32) and loops on non-advancing reads (`src/lib/tnef.ts:201`, `:211`). - Fix hint: clamp to remaining/4, break on a null or non-advancing read. @@ -60,12 +60,12 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 - What RN does: stays signed in for good (`src/stores/auth-store.ts:929`, `App.tsx:818`). - Fix hint: needs the policy; then an AppState idle timer and a max-age check in restoreSession, drafts flushed first. -- [ ] **With TOTP on, changing the password and turning TOTP off fail** — `P2` — `bug` +- [x] **With TOTP on, changing the password and turning TOTP off fail** — `P2` — `bug` — fixed in 99a42128 - What WEB does: asks for the current code and sends it (`components/settings/account-security-settings.tsx:52`). - What RN does: sends neither (`src/api/account-security.ts:346-353`, `:387-395`; `src/components/settings/AccountSecuritySettings.tsx:292`); Stalwart answers "Current OTP code is required". - Fix hint: ask for the code and patch `otpAuth/otpCode` (not the whole object). -- [ ] **A full sign-out keeps the search history** — `P2` — `bug` +- [x] **A full sign-out keeps the search history** — `P2` — `bug` — fixed in 986216f4, 639aa4aa - What WEB does: `stores/auth-store.ts:1301`, `lib/sign-out-cleanup.ts:22`. - What RN does: clearAllFeatureStores (`src/stores/auth-store.ts:126-134`) never clears `src/stores/search-history-store.ts:44`. - Fix hint: clear it, and check the other persisted stores in the same pass. @@ -86,25 +86,25 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Mail list and folders -- [ ] **The list stops loading older mail when the server sends no total (#1364)** — `P2` — `bug` +- [x] **The list stops loading older mail when the server sends no total (#1364)** — `P2` — `bug` — fixed in 58bc4aca - What WEB does: keeps paging while full pages come back (`stores/email-store.ts:6508-6515`). - What RN does: a missing total becomes 0 (`src/api/email.ts:529`, `:757`) and paging stops (`src/stores/email-store.ts:1113`). -- [ ] **View scheduled messages; Cancel send puts them back in Drafts (native #84)** — `P2` — `partial` +- [x] **View scheduled messages; Cancel send puts them back in Drafts (native #84)** — `P2` — `partial` — fixed in 14d009de, 51b3208b, c817f978 - What WEB does: opens scheduled mail with a banner (Send now, Reschedule, Cancel) (`components/mail/mail-app.tsx:2523`, `components/email/email-viewer.tsx:773`, f7adbf1ef, 780b64461, 831a3e6b8). - What RN does: a row tap only opens the action sheet (`src/screens/ScheduledScreen.tsx:278`); Cancel leaves the copy in Sent (`:129-132`, `src/api/email.ts:2079`). - Fix hint: open the row in the thread screen with a scheduled banner; make Cancel do the cancel-to-Drafts that Edit already does. -- [ ] **Shared tags in group mailboxes (#1310, #470)** — `P2` — `missing` +- [x] **Shared tags in group mailboxes (#1310, #470)** — `P2` — `missing` — fixed in b7b9c7e0, ba672050 (read-only; editing stays in the webmail) - What WEB does: reads and writes `org.bulwarkmail/tags` via JMAP Metadata on the group account (`lib/shared-tags.ts:185`, `components/settings/shared-tag-settings.tsx`, `lib/jmap/bulwark-metadata.ts`). - What RN does: local tag names only (`src/stores/keywords-store.ts:5`, `src/components/settings/KeywordSettings.tsx`). - Fix hint: read the group's tags through Metadata (Stalwart 1.0 implements it; the 0.16 guard from 42751a6b stays). Locking needs the policy. -- [ ] **Search leaves out Spam and Trash by default** — `P2` — `missing` +- [x] **Search leaves out Spam and Trash by default** — `P2` — `missing` — fixed in a412b516, 2b5257bf - What WEB does: `inMailboxOtherThan` trash/junk unless "All folders" is picked (`lib/unified-mailbox.ts:98`, 763732fdc, 3904af2cb). - What RN does: no mailbox filter (`src/stores/email-store.ts:268-271`, `:492`). -- [ ] **Unified "All mail" search leaves out Sent, Archive and Drafts** — `P2` — `bug` +- [x] **Unified "All mail" search leaves out Sent, Archive and Drafts** — `P2` — `bug` — fixed in 484cac58 - What WEB does: with a query, excludes only trash and junk (`lib/unified-mailbox.ts:510`). - What RN does: applies the view exclusions also with a query (`src/api/unified-inbox.ts:353`, `:35`). @@ -122,7 +122,7 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 - [ ] **Tag views and counts include Trash and Spam (#1156)** — `P3` — `bug` - What WEB does: `lib/unified-mailbox.ts:104`, `:577`. What RN does: `src/api/tag-counts.ts:37-48`, `src/stores/email-store.ts:455`. -- [ ] **User folders named like system folders get system icons (#1235, native #80)** — `P3` — `bug` +- [x] **User folders named like system folders get system icons (#1235, native #80)** — `P3` — `bug` — fixed in 96c7c045 - What WEB does: icons by role only (`components/layout/sidebar.tsx:168`). What RN does: name matching fallback (`src/components/SidebarDrawer.tsx:92`). - [ ] **Sort by "Date sent" falls back to received date in merged lists (#1219)** — `P3` — `bug` @@ -172,7 +172,7 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Reading mail -- [ ] **Unverified-sender warning, badge, no "Always trust" for forged mail** — `P2` — `partial` +- [x] **Unverified-sender warning, badge, no "Always trust" for forged mail** — `P2` — `partial` — fixed in cc21317b - What WEB does: getSenderVerification (`lib/email-headers.ts:112`), banner and badge (`components/email/email-viewer.tsx:4037`). - What RN does: a spoof line in the collapsed details only, first DKIM signature only, trust still offered (`src/components/email/MessageHeader.tsx:108`, `:273`; `src/lib/email-headers.ts:99`; `src/components/EmailBodyView.tsx:771`). @@ -181,11 +181,11 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 - What RN does: `src/components/email/MessageHeader.tsx:159`, nothing. - Fix hint: internal and partner domains come from the policy; identity domains would only be a fallback. -- [ ] **Invitation trust uses unaligned SPF/DKIM and flags colleagues (#1374)** — `P2` — `bug` +- [x] **Invitation trust uses unaligned SPF/DKIM and flags colleagues (#1374)** — `P2` — `bug` — fixed in 7a95d43f, 1bce37bb, 6133bcd9 - What WEB does: alignment check and own-domain exemption, REPLY/COUNTER checked against the answering attendee (`lib/calendar-invitation.ts:210-216`, `:400-422`). - What RN does: `src/lib/calendar-invitation.ts:325-328`, `:375-376`. -- [ ] **Copy chip for sign-in and verification codes** — `P2` — `missing` +- [x] **Copy chip for sign-in and verification codes** — `P2` — `missing` — fixed in b1550f14 - What WEB does: `lib/verification-code.ts:275`, `components/email/email-viewer.tsx:1378`, setting at `stores/settings-store.ts:540`. - What RN does: nothing (`src/components/email/MessageHeader.tsx`, `src/screens/EmailListScreen.tsx`). @@ -195,7 +195,7 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 - [ ] **Attachment names keep direction-override characters** — `P3` — `bug` - What WEB does: `lib/bidi.ts:10`. What RN does: `src/lib/attachment-display.ts:34`, `src/lib/email-export.ts:56`. -- [ ] **Part names that are paths (#1371, #1373)** — `P3` — `bug` +- [x] **Part names that are paths (#1371, #1373)** — `P3` — `bug` — fixed in 4d545f8f - What WEB does: `lib/jmap/download-name.ts:11`. What RN does: `src/api/jmap-client.ts:1350` puts `%2F` into the download URL. - [ ] **Dark mode recolours instead of inverting** — `P3` — `missing` @@ -215,34 +215,34 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Composer and sending -- [ ] **An open draft follows an account switch; its autosave can destroy another account's message** — `P1` — `bug` +- [x] **An open draft follows an account switch; its autosave can destroy another account's message** — `P1` — `bug` — fixed in 9daa3441, 388f46b5, 4e57b191 - What WEB does: pins the account when the composer opens (`components/email/email-composer.tsx:506`, d58344329). - What RN does: reads Drafts/Sent, identities and `jmapClient.accountId` live (`src/screens/ComposeScreen.tsx:443-455`, `:778`, `:1355`; `src/api/email.ts:1899`, `:1928-1930`). A notification tap or deep link switches with the composer open (`App.tsx:117-120`); the next autosave creates the draft in the other account and destroys `previousDraftId` there. - Fix hint: pin account, identities and mailboxes at open; pass the account to saveDraftVersion, sendEmail and uploads. -- [ ] **Undo or Send now of a delayed send goes through the active login** — `P1` — `bug` +- [x] **Undo or Send now of a delayed send goes through the active login** — `P1` — `bug` — fixed in e81f0071, 893f40a2 - What WEB does: GHSA-8x23 (`components/mail/mail-app.tsx:2549`). - What RN does: the pending send has no login (`src/stores/send-undo-store.ts:89`, `:109-118`; `src/screens/ComposeScreen.tsx:2202`); after a switch the cancel hits the same submission id on another server. - Fix hint: store the login with the pending send; refuse or clear on a switch. -- [ ] **Reschedule and Send now create the replacement before cancelling (#1308)** — `P2` — `bug` +- [x] **Reschedule and Send now create the replacement before cancelling (#1308)** — `P2` — `bug` — fixed in 22f2ac5b, fdf8eece - What WEB does: cancels first, restores on failure (`lib/jmap/client.ts:11532-11664`). - What RN does: creates first (`src/api/email.ts:2189`). -- [ ] **A send the server doesn't confirm is reported as sent (#1019)** — `P2` — `bug` +- [x] **A send the server doesn't confirm is reported as sent (#1019)** — `P2` — `bug` — fixed in 3eac700a - What WEB does: `lib/jmap/client.ts:994`, `:5115`. - What RN does: returns success without a submission id (`src/api/email.ts:1857`), drops the draft and closes (`src/screens/ComposeScreen.tsx:2158`). -- [ ] **Send and save drafts as a group or shared identity (#1090)** — `P2` — `missing` (old 04 item too) +- [x] **Send and save drafts as a group or shared identity (#1090)** — `P2` — `missing` (old 04 item too) — fixed in 31d8e4a4, 6414b0d6, 893f40a2 - What WEB does: resolveSendAccountId (`lib/jmap/client.ts:6257`), identities of every account (`components/email/email-composer.tsx:214`, `:271`). - What RN does: primary account's identities only (`src/api/identity.ts:17`, `src/screens/ComposeScreen.tsx:778`); sendEmail has no account (`:2151`). -- [ ] **Team templates, personal templates in the account, org template library** — `P2` — `missing` +- [x] **Team templates, personal templates in the account, org template library** — `P2` — `missing` — fixed in fac318dc (personal + team read-only; org library needs the policy) - What WEB does: templates in JMAP Metadata with tombstones (`lib/templates/personal-templates.ts:141`, `lib/templates/team-templates.ts:57`, `lib/templates/org-library.ts:13`); on 1.0 the webmail moves them into the account. - What RN does: local only (`src/stores/templates-store.ts:30`, `src/components/TemplateSheet.tsx`). - Fix hint: read and write `org.bulwarkmail` templates via Metadata. The org library and locks need the policy. -- [ ] **Attach from Files (#1179)** — `P2` — `missing` +- [x] **Attach from Files (#1179)** — `P2` — `missing` — fixed in 8e07b7d8 - What WEB does: `components/email/email-composer.tsx:4574`. What RN does: device picker only (`src/screens/ComposeScreen.tsx:1686-1711`). - [ ] **External recipient confirm (composer, quick reply, invitations)** — `P2` — `missing` (blocked on the policy) @@ -253,7 +253,7 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 - What WEB does: added in the client before sending (`lib/org/outgoing.ts:73`, `:99`, `lib/org-signature.ts:311`, 0154e24ff). - What RN does: mail from the phone goes out without the disclaimer (`src/screens/ComposeScreen.tsx:2151`, `src/lib/signature-utils.ts`). -- [ ] **Unfilled placeholder warning** — `P3` — `missing` +- [x] **Unfilled placeholder warning** — `P3` — `missing` — fixed in a8e7a3f4, 7594e459 - What WEB does: findUnfilledPlaceholders with per-locale words and a confirm (`lib/placeholder-check.ts:115`, `components/email/email-composer.tsx:3261`), setting placeholderWarningEnabled. - What RN does: nothing (`src/screens/ComposeScreen.tsx:2151`). @@ -284,37 +284,37 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Calendar -- [ ] **Calendar and task data from the previous account lands after a switch** — `P1` — `bug` +- [x] **Calendar and task data from the previous account lands after a switch** — `P1` — `bug` — fixed in 1f190c94, e993540a, 41e8f005, 98dc13fe - What WEB does: epoch check (`stores/calendar-store.ts:956`). - What RN does: in-flight fetchEvents and `tasksInFlight` survive reset (`src/stores/calendar-store.ts:742`, `:750`, `:786`; reset at `src/stores/auth-store.ts:830`); a tick or delete then writes to the new account by the old one's id. -- [ ] **Task reminders relative to the start use the due date (native #83, webmail #1328)** — `P2` — `bug` +- [x] **Task reminders relative to the start use the due date (native #83, webmail #1328)** — `P2` — `bug` — fixed in 6f475c0c - What WEB does: `lib/calendar-alerts.ts:343`. What RN does: `src/lib/calendar-alert-scheduler.ts:86`. -- [ ] **Daily series stop at a DST gap** — `P2` — `bug` +- [x] **Daily series stop at a DST gap** — `P2` — `bug` — fixed in 4de85692 - What WEB does: candidates from the start's wall clock (`lib/recurrence-expansion.ts:420`, 34fb9d247). - What RN does: `src/lib/recurrence-expansion.ts:526-531`, `:396-398`, `:709`. -- [ ] **Subscribed feed changes never reach imported events** — `P2` — `bug` +- [x] **Subscribed feed changes never reach imported events** — `P2` — `bug` — fixed in 8a71495e, 47f29718 - What WEB does: calendar-feed-diff (`stores/calendar-store.ts:2012`). What RN does: known UIDs skipped (`src/stores/calendar-subscriptions-store.ts:222`, `src/stores/calendar-store.ts:1158`). -- [ ] **Invitation time in the wrong zone (#1252)** — `P2` — `bug` +- [x] **Invitation time in the wrong zone (#1252)** — `P2` — `bug` — fixed in 0fb7c8cd - What WEB does: `lib/calendar-invitation.ts:701`. What RN does: `src/components/email/CalendarInvitationBanner.tsx:175`. -- [ ] **Default reminders per calendar and email reminders (#1209)** — `P2` — `partial` +- [x] **Default reminders per calendar and email reminders (#1209)** — `P2` — `partial` — fixed in 9b87100a, b767df9f - What WEB does: `components/settings/calendar-management-settings.tsx:184`, `components/calendar/event-modal.tsx:448`, `lib/calendar-alerts.ts:175`. - What RN does: fires a calendar's defaults (`src/lib/calendar-alert-scheduler.ts:96`) but can't set them and new events don't start with them (`src/components/calendar/EventModal.tsx:266`). -- [ ] **Search events** — `P2` — `missing` +- [x] **Search events** — `P2` — `missing` — fixed in b50270d8 - What WEB does: `components/calendar/calendar-search.tsx:82`. What RN does: `src/screens/CalendarScreen.tsx`. -- [ ] **Zero-length events run to 23:59 (#837)** — `P3` — `bug` +- [x] **Zero-length events run to 23:59 (#837)** — `P3` — `bug` — fixed in acbd085a - What RN does: `src/stores/calendar-store.ts:144`, `src/lib/calendar-utils.ts:116`. Fix: `duration || 'PT0S'`. -- [ ] **.ics export breaks emoji and colon names** — `P3` — `bug` +- [x] **.ics export breaks emoji and colon names** — `P3` — `bug` — fixed in f83284d7 - What RN does: `src/lib/calendar-ics-export.ts:9`, `:160`, `:167`. Fix: port foldLine and parameter quoting. -- [ ] **Blank participant names are written (#748)** — `P3` — `bug` +- [x] **Blank participant names are written (#748)** — `P3` — `bug` — fixed in 59c32782 - What WEB does: `lib/calendar-participants.ts:368`. What RN does: `src/lib/calendar-participants.ts:360`, `:385`, `:484`. - [ ] **Offer to save without invitations when the server refuses them** — `P3` — `partial` @@ -331,23 +331,23 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Contacts -- [ ] **Contacts from the previous account land after a switch** — `P1` — `bug` +- [x] **Contacts from the previous account land after a switch** — `P1` — `bug` — fixed in 6b9552fc - What WEB does: epoch guard (`stores/contact-store.ts:597`). What RN does: `src/stores/contacts-store.ts:357`, `:373`; reset (`:873`) keeps contactsPromise. -- [ ] **Contacts with a calendar, scheduling or free/busy link don't save** — `P2` — `bug` +- [x] **Contacts with a calendar, scheduling or free/busy link don't save** — `P2` — `bug` — fixed in 32f70c10 - What WEB does: maps them to `calendars`/`schedulingAddresses` (`lib/jmap/contact-wire.ts:63-87`). - What RN does: writes `calendarUri`, `schedulingUri`, `freeBusyUri` as card properties (`src/lib/contact-form.ts:412-414`, `src/api/contacts.ts:97`); Stalwart refuses the card. -- [ ] **vCard import sends fields Stalwart rejects** — `P2` — `bug` +- [x] **vCard import sends fields Stalwart rejects** — `P2` — `bug` — fixed in 32f70c10, 3c156673 - What WEB does: `lib/jmap/contact-wire.ts`. What RN does: flat ADR and `source` (`src/lib/vcard.ts:652-672`, `:989-990`). -- [ ] **Company directory in Contacts and the composer (#1253)** — `P2` — `missing` +- [x] **Company directory in Contacts and the composer (#1253)** — `P2` — `missing` — fixed in 0fd14a83 (Contacts; the composer lookup is exported, not wired) - What WEB does: `components/contacts/directory-browser.tsx:61`, `stores/contact-store.ts:924`. What RN does: `src/screens/ContactsScreen.tsx`, `src/stores/contacts-store.ts:728`; listPrincipals exists (`src/api/files.ts:593`). -- [ ] **Deleting an address book that still holds contacts fails** — `P3` — `bug` +- [x] **Deleting an address book that still holds contacts fails** — `P3` — `bug` — fixed in 32f70c10 - What WEB does: `onDestroyRemoveContents` (`lib/jmap/client.ts:6937`). What RN does: `src/api/contacts.ts:404`. -- [ ] **vCard 4.0 export (#1407)** — `P3` — `bug` +- [x] **vCard 4.0 export (#1407)** — `P3` — `bug` — fixed in 07fd03e2 - What RN does: dashes in dates, MOBILE instead of CELL (`src/lib/vcard.ts:21`, `:24`, `:1264`). - [ ] **Delete contact categories; address book sharing; list filters; deep links new/edit** — `P3` — `missing`/`partial` @@ -355,11 +355,11 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Files -- [ ] **Files trash** — `P2` — `missing` +- [x] **Files trash** — `P2` — `missing` — fixed in 7c914183 and be04fcb1..946304ab - What WEB does: `lib/files-trash.ts:20`, `components/files/files-app.tsx:419`. - What RN does: deletes for good (`src/api/files.ts:316`, `src/screens/FilesScreen.tsx:673`) and lists the webmail's `/.Trash` as an ordinary folder. -- [ ] **Save an attachment to Files (incl. shared and group mail)** — `P2` — `missing` +- [x] **Save an attachment to Files (incl. shared and group mail)** — `P2` — `missing` — fixed in 8e07b7d8, 39e82f99 - What WEB does: `components/email/save-to-files-dialog.tsx:43`, `lib/jmap/client.ts:9981`. What RN does: `src/components/email/AttachmentChips.tsx:183`; `src/api/files.ts:411` has createFileNodeFromBlob. - [ ] **Copy folders, numbered new folder names, next/previous in preview, starred and recent, deep links** — `P3` — `partial`/`missing` @@ -370,28 +370,28 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Filters and vacation -- [ ] **Filter scripts saved by webmail 1.13+ open as raw Sieve; reset wipes them (#1152)** — `P1` — `bug` +- [x] **Filter scripts saved by webmail 1.13+ open as raw Sieve; reset wipes them (#1152)** — `P1` — `bug` — fixed in 2167a9d7, fc9c164d - What WEB does: accepts metadata v1 and v2 (`lib/sieve/parser.ts:855`); writes v2 for rule periods, vacation forwarding or audience (`lib/jmap/sieve-types.ts:146`). - What RN does: `if (metadata.version !== 1) return OPAQUE` (`src/lib/sieve/parser.ts:804`); "Reset to visual builder" (`src/components/settings/FilterSettings.tsx:290-318`) wipes the rules and forwarding. - Fix hint: accept v2 and carry activeFrom/activeUntil, vacationForward, vacationAudience through parse and save. -- [ ] **Webmail "is the address" / "has the domain" rules are broadened on a phone save** — `P1` — `bug` +- [x] **Webmail "is the address" / "has the domain" rules are broadened on a phone save** — `P1` — `bug` — fixed in 2167a9d7 - What WEB does: `address :is` / `address :domain :is` (`lib/sieve/generator.ts:106`, `lib/sieve/parser.ts:485`). - What RN does: no such comparators (`src/lib/sieve/types.ts:27`); the generator's default branch writes `header :contains` (`src/lib/sieve/generator.ts:130-131`). -- [ ] **"All messages" condition (#1154)** — `P2` — `missing` +- [x] **"All messages" condition (#1154)** — `P2` — `missing` — fixed in 2167a9d7, df1a5ab4 - What WEB does: `lib/sieve/generator.ts:61`. What RN does: throws on save (`src/lib/sieve/generator.ts:113`), so every save fails once a web rule uses it. -- [ ] **"Stop processing" after Delete silently or Reject (#1153)** — `P2` — `bug` +- [x] **"Stop processing" after Delete silently or Reject (#1153)** — `P2` — `bug` — fixed in 2167a9d7 - What WEB does: `lib/sieve/generator.ts:487`. What RN does: skips `stop;` (`src/lib/sieve/generator.ts:396`). -- [ ] **Rule names with double spaces get a duplicate (#1153)** — `P2` — `bug` +- [x] **Rule names with double spaces get a duplicate (#1153)** — `P2` — `bug` — fixed in 2167a9d7 - What WEB does: collapses whitespace (`lib/sieve/generator.ts:455`, `lib/sieve/parser.ts:904`). What RN does: `src/lib/sieve/parser.ts:841`, `src/lib/sieve/generator.ts:39`. -- [ ] **Out of Office forwarding, reply audience and rule periods (#1152)** — `P2` — `missing` +- [x] **Out of Office forwarding, reply audience and rule periods (#1152)** — `P2` — `missing` — fixed in df1a5ab4 - What WEB does: `components/settings/vacation-settings.tsx:135`, `components/filters/filter-rule-modal.tsx:188`, `:299`, `lib/sieve/period.ts`. What RN does: `src/components/settings/VacationSettings.tsx:209`, `src/lib/sieve/types.ts:66-108`. -- [ ] **Create rules from a message** — `P2` — `missing` +- [x] **Create rules from a message** — `P2` — `missing` — fixed in d546d509, 7b7236f0 - What WEB does: `components/email/rules-menu.tsx`, `lib/filters/quick-rules.ts:187`. What RN does: `src/components/email/ActionSheet.tsx`, `src/components/filters/FilterRuleModal.tsx`. - [ ] **Forward limit (#1155, #1208); vacation length warning; run a rule on a folder (#1166); Sieve editor loses typed text (#1162); size value raw into Sieve; undo after deleting tags/rules/trusted senders** — `P3` — `missing`/`bug` @@ -399,15 +399,15 @@ Stalwart 1.0.0 items found in the same pass (1.0 SSO scopes, Files on 1.0, #1385 ### Push, settings and core -- [ ] **Push is renewed for the active account only; settings show only that account (#1054)** — `P2` — `bug` +- [x] **Push is renewed for the active account only; settings show only that account (#1054)** — `P2` — `bug` — fixed in d92a2ca8 - What WEB does: `components/push-notification-prompt.tsx:173`, `:219`, `components/settings/multi-account-push.tsx:33`. - What RN does: resyncPushNotifications works on the active client (`App.tsx:671`, `:723`; `src/lib/push-notifications.ts:1592-1602`), so other accounts' subscriptions expire. -- [ ] **Push with two logins that share a JMAP account id** — `P2` — `bug` +- [x] **Push with two logins that share a JMAP account id** — `P2` — `bug` — fixed in 9ccb6228, b352e470 - What WEB does: 07e6ecce1. - What RN does: the iOS extension's credentials are keyed by JMAP id (`src/lib/ios-push-shared.ts:54`); a tap opens the first match (`src/lib/push-notifications.ts:1873`); the background task checks every login with that id (`src/lib/push-background-task.ts:201`). -- [ ] **Writes other than sends are replayed after a dropped connection** — `P2` — `partial` +- [x] **Writes other than sends are replayed after a dropped connection** — `P2` — `partial` — fixed in d57bdfaa - What WEB does: retries read-only batches only (`lib/jmap/client.ts:245`). - What RN does: blocks the retry only for EmailSubmission/set, Email/import, Blob/upload (`src/api/jmap-client.ts:102-109`, `:853-857`).