super-productivity/docs
Parman Mohammadalizadeh 7fba6f55e2
fix(tasks): decode multipart and transfer-encoded eml bodies #8975 (#8999)
* fix(tasks): decode multipart and transfer-encoded eml bodies #8975

Dropping a real-world .eml (e.g. saved from Outlook) onto the add-task
button created a title-only task: the parser only accepted a single,
unencoded text/plain body, but most clients send multipart/alternative
(plain + HTML) with quoted-printable or base64 transfer encoding on the
plain part.

eml-parser.ts now walks multipart/* structures (bounded recursion depth)
for the first supported text/plain leaf, and decodes quoted-printable/
base64 transfer encodings on it. HTML bodies and non-UTF-8/ASCII
charsets are still never decoded, matching the existing threat model
for this untrusted, inert note content.

* fix(tasks): keep unsupported-encoding eml test accurate after decode support

The service-level test for "unsupported body encoding" used a base64
fixture, which the eml-parser fix now legitimately decodes. Switch it
to a genuinely unsupported transfer-encoding token, and add a
dedicated test asserting base64 bodies decode and wrap in the notes
code fence as expected.

* fix(tasks): skip Content-Disposition: attachment parts in eml import

_extractPlainText() picked the first supported text/plain leaf in wire
order regardless of Content-Disposition, so a text/plain attachment
could be imported as the note when the real body was HTML, or shadow
the real body if it appeared first in the multipart structure. Skip
any part (leaf or multipart container) marked as an attachment before
inspecting it further.

Addresses review feedback from @johannesjo on PR #8999.

* fix(tasks): treat non-inline disposition and legacy name= as attachment

Content-Disposition is optional (legacy mail marks a filename via
Content-Type's name= parameter instead), and RFC 2183 §2.8 requires
any disposition type other than inline — recognized or not — to be
treated as attachment. The previous fix only matched the literal
token "attachment", so a text/plain part identified solely by a
legacy name= parameter, or one with an unrecognized disposition type
(e.g. x-download), still shadowed the real body.

_isAttachmentPart() now treats any present disposition other than
inline as an attachment, and falls back to the Content-Type name=
hint only when Content-Disposition is absent entirely.

Addresses further review feedback from @johannesjo on PR #8999.

* fix(tasks): recognize RFC 2231 name*/name*0 attachment filename hints

The legacy Content-Type name= fallback (used when Content-Disposition
is absent) only matched the literal key "name", missing RFC 2231's
encoded (name*) and continuation (name*0, name*0*, name*1, ...)
spellings of the same parameter. A part identified solely by a
continued name*0/name*1 filename hint slipped through undetected and
could be imported as the note instead of producing a title-only task.

_parseContentType() now matches any RFC 2231 spelling of name via a
presence-only regex; the value is never decoded or reassembled since
only the filename hint's existence matters.

Addresses further review feedback from @johannesjo on PR #8999.

* fix(tasks): recognize RFC 2231 filename*/filename*0 disposition hints

Content-Disposition's hasFilename fallback (used when the disposition
type token fails to parse, e.g. a type-less "; filename=...") only
matched the literal key "filename=", missing RFC 2231's encoded
(filename*) and continuation (filename*0, filename*0*, ...) spellings
of the same parameter -- the mirror of the name*/name*0 gap fixed for
Content-Type.

_parseContentDisposition() now matches any RFC 2231 spelling of
filename via a presence-only regex, symmetric to _NAME_PARAM_KEY_RE.

Addresses further review feedback from @johannesjo on PR #8999.
2026-07-15 09:55:39 +02:00
..
long-term-plans docs(sync): note local-file rev-check/write is non-atomic (#8898) (#8902) 2026-07-10 17:31:24 +02:00
plans fix(sync): file-based provider atomicity & conflict UX (#8960) (#9004) 2026-07-14 19:23:24 +02:00
promotion build: better organize stuff 2025-06-27 09:03:16 +02:00
research feat(task-repeat): RFC 5545 RRULE recurring schedules — EPIC · Phase 1/13 (Closes #4020) (#7948) 2026-06-09 11:25:35 +02:00
screens docs/wiki content v0.8 (#7068) 2026-04-01 12:40:28 +02:00
sync-and-op-log fix(sync): preserve multi-entity conflict recovery (#8990) 2026-07-14 14:10:52 +02:00
wiki fix(tasks): decode multipart and transfer-encoded eml bodies #8975 (#8999) 2026-07-15 09:55:39 +02:00
add-new-integration.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
android-edge-to-edge-keyboard.md fix(android): keyboard + status-bar follow-ups for edge-to-edge (#8508) (#8548) 2026-06-23 11:57:49 +02:00
apple-release-automation.md ci: auto-submit iOS and macOS App Store builds for review (#7857) 2026-06-01 11:42:16 +02:00
build-and-publish-notes.md fix(ci): prevent duplicate unsigned exe files in GitHub Releases 2026-03-19 18:58:52 +01:00
documentation-guide.md Housekeeping for various docs, templates, and actions (#7451) 2026-05-02 13:58:25 +02:00
ENV_SETUP.md build: final approach 2025-07-14 20:52:51 +02:00
github-access-token-instructions.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
gitlab-access-token-instructions.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
how-to-rate.md feat(rate-dialog): action-aware prompt with feedback split 2026-05-04 17:27:11 +02:00
howto-refresh-snap-credentials.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
i18n-script-usage.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
legacy-webview-analysis.md 16.2.1 2025-11-01 13:22:58 +01:00
mac-app-store-code-signing-guide.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
performance-project-tag-report.md docs: add performance report 2025-11-13 18:23:50 +01:00
plainspace-api-extension-plan.md feat(plainspace): create tasks directly in a Plainspace-backed project (#8676) 2026-07-01 19:36:52 +02:00
plainspace-integration-plan.md refactor(sync): remove unused error classes, dialog, and constructor-time logging (phase 1, #8325) (#8510) 2026-06-20 13:36:56 +02:00
plugin-development.md fix(electron): remove exec IPC to close GHSA-256q (#8669) 2026-07-01 17:55:35 +02:00
styling-guide.md docs: update styling breakpoint table (#8846) 2026-07-07 16:50:49 +02:00
theming-contract.md feat(theme): add Plainspace built-in theme 2026-06-15 14:06:21 +02:00
TRANSLATING.md Fix frequency translations (#8000) 2026-06-05 10:53:26 +02:00
unused-translations-analysis.md chore(i18n): remove additional 86 orphan translation keys 2026-01-09 14:59:05 +01:00
update-android-app.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00
update-mac-certificates.md docs: clean up and organize project documentation 2026-03-10 10:22:56 +01:00