Commit Graph

4 Commits

Author SHA1 Message Date
tuxedomm
e64d24580a refactor: migrate mail shortcuts to FileIO (#356)
* refactor: migrate mail shortcuts to FileIO

- DraftSnapshot.FIO: inject FileIO into draft snapshot for patch ops
  (addAttachment, loadAndAttachInline, replaceInline)
- emlbuilder.Builder.fio: inject via WithFileIO(), readFile uses FileIO.Open
- mail_draft_edit: loadPatchFile uses runtime.FileIO().Open
- helpers: checkAttachmentSizeLimit takes fio param, uses FileIO.Stat
- validateComposeInlineAndAttachments: pass fio through to size check
- All mail entry points (send/reply/reply_all/forward/draft_create):
  pass runtime.FileIO() to builder and size limit checks
2026-04-09 17:40:30 +08:00
feng zhi hao
c54a1354a0 feat(mail): auto-resolve local image paths in all draft entry points (#205)
All draft-related shortcuts now support <img src="./local.png"> in --body,automatically resolving relative paths into cid: inline MIME parts. Only relative paths are supported; absolute paths are rejected. Previously only +draft-edit supported this; now extended to +draft-create, +send, +reply, +reply-all, and +forward.
2026-04-08 14:36:01 +08:00
feng zhi hao
eda2b9cd85 revert: undo auto-resolve local image paths in draft body HTML (#199)
* Revert "fix(mail): clarify that file path flags only accept relative paths (#141)"

This reverts commit 1ffe870dc8.

* Revert "feat(mail): auto-resolve local image paths in draft body HTML (#81) (#139)"

This reverts commit 70c72a2c02.

* Reapply "fix(mail): clarify that file path flags only accept relative paths (#141)"

This reverts commit d465e085b1.
2026-04-01 23:11:30 +08:00
feng zhi hao
70c72a2c02 feat(mail): auto-resolve local image paths in draft body HTML (#81) (#139)
* feat(mail): auto-resolve local image paths in draft body HTML (#81)

Allow <img src="./local/path.png" /> in set_body/set_reply_body HTML.
Local file paths are automatically resolved into inline MIME parts with
generated CIDs, eliminating the need to manually pair add_inline with
set_body. Removing or replacing an <img> tag in the body automatically
cleans up or replaces the corresponding MIME inline part.

- Add postProcessInlineImages to unify resolve, validate, and orphan
  cleanup into a single post-processing step
- Extract loadAndAttachInline shared helper to deduplicate addInline
  and resolveLocalImgSrc logic
- Cache resolved paths so the same file is only attached once
- Use whitelist URI scheme detection instead of blacklist
- Remove dead validateInlineCIDAfterApply and
  validateOrphanedInlineCIDAfterApply functions

Closes #81

* fix(mail): harden inline image CID handling

1. Fix imgSrcRegexp to skip attribute names like data-src/x-src that
   contain "src" as a suffix — only match the real src attribute.
2. Sanitize cidFromFileName to replace whitespace with hyphens,
   producing RFC-safe CID tokens (e.g. "my logo.png" → "my-logo").
3. Add CID validation in newInlinePart to reject spaces, tabs, angle
   brackets, and parentheses — fail fast instead of silently producing
   broken inline images in the sent email.

* refactor(mail): use UUID for auto-generated inline CIDs

Replace filename-derived CID generation (cidFromFileName + uniqueCID)
with UUID-based generation. UUIDs contain only [0-9a-f-] characters,
eliminating all RFC compliance risks from special characters, Unicode,
or filename collisions. Same-file deduplication via pathToCID cache
is preserved — multiple <img> tags referencing the same file still
share one MIME part and one CID.

* fix(mail): avoid panic in generateCID by using uuid.NewRandom

uuid.New() calls Must(NewRandom()) which panics if the random source
fails. Replace with uuid.NewRandom() and propagate the error through
resolveLocalImgSrc, so the CLI returns a clear error instead of
crashing in extreme environments.

* fix(mail): restore quote block hint in set_reply_body template description

The auto-resolve PR accidentally dropped "the quote block is
re-appended automatically" from the set_reply_body shape description.
Restore it alongside the new local-path support note.

* fix(mail): add orphan invariant comment and expand regex test coverage

- Add comment in postProcessInlineImages explaining that partially
  attached inline parts on error are cleaned up by the next Apply.
- Add regex test cases: single-quoted src, multiple spaces before src,
  and newline before src.

* fix(mail): use consistent inline predicate and safer HTML part lookup

1. removeOrphanedInlineParts: change condition from
   ContentDisposition=="inline" && ContentID!="" to
   isInlinePart(child) && ContentID!="", matching the predicate used
   elsewhere — parts with only a ContentID (no Content-Disposition)
   are now correctly cleaned up.
2. postProcessInlineImages: use findPrimaryBodyPart instead of
   findPart(snapshot.Body, PrimaryHTMLPartID) to avoid stale PartID
   after ops restructure the MIME tree.

* fix(mail): revert orphan cleanup to ContentDisposition check to protect HTML body

The previous change (d3d1982) broadened the orphan cleanup predicate to
isInlinePart(), which treats any part with a ContentID as inline. This
deletes the primary HTML body when it carries a Content-ID header
(valid in multipart/related), even on metadata-only edits like
set_subject.

Revert to the original ContentDisposition=="inline" && ContentID!=""
condition — only parts explicitly marked as inline attachments are
candidates for orphan removal. Add regression test covering
multipart/related with a Content-ID-bearing HTML body.
2026-04-01 15:47:20 +08:00