Commit Graph
7 Commits
Author SHA1 Message Date
jcoffey-dev 687027c7cb export: bring matched items up to date on every run
ci / test (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 2m50s
ci / announce (pull_request) Skipped
Export matched each item against the target and then skipped it, so a second
run -- the usual final pass of a cutover -- never carried anything that had
changed at the source since the first: read and flagged state, moves between
folders, edited contacts, events and Sieve scripts. It reported them as
skipped and exited 0, while the usage guide said matched items were updated.

Matched items are now updated, with one batched /set per type:

- Email: keywords are set to the archive's, added and removed, compared
  case-insensitively. Memberships of folders this run migrated are added and
  removed to match; folders that exist only on the target are left alone,
  and a message is never left in no folder. Properties the server did not
  report are not touched.
- Contacts and events: when both copies carry `updated`, the archive's is
  written only if it is newer, compared as instants so an offset or a
  fraction of a second is not taken for a change; otherwise each property the
  archive writes is compared, and those that differ are sent whole.
- Sieve scripts: the target's copy is downloaded and compared byte for byte
  with what export would write -- after renaming Stalwart's vendor names for
  an inbuxa target -- and replaced when it differs, so a renamed script is
  not re-uploaded on every run.

Updated items are counted as `updated`; unchanged ones stay `skipped`. The
usage guide now describes this.
2026-09-30 11:37:39 -07:00
jcoffey-dev 14a797cd65 Merge pull request 'Time out every connection, and scope --allow-invalid-certs' (#6) from fix/connection-safety into main
ci / test (push) Skipped
github/ci (branch) GitHub Actions
ci / github (push) Successful in 3m31s
ci / announce (push) Skipped
2026-09-30 18:34:50 +00:00
jcoffey-dev 01ac1a5b3e Merge pull request 'export: write a message once, in every folder it was in' (#4) from fix/one-message-many-folders into main
ci / test (push) Skipped
github/ci (branch) GitHub Actions
ci / github (push) Canceled after 1m36s
ci / announce (push) Canceled after 0s
2026-09-30 18:33:09 +00:00
jcoffey-dev 234b3203d7 Scope --allow-invalid-certs to the server the user named
ci / test (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 2m33s
ci / announce (pull_request) Skipped
The flag switched certificate checks off for every connection in the run.
That included the Microsoft sign-in endpoints, so a user passing it for a
self-signed source also sent refresh tokens, device codes and EWS client
secrets over unverified TLS. It also covered the export target, and any host
a server redirected to or named for its API, uploads or downloads.

It now applies only where the user pointed it: the host of --url, for the
source of an import or the target of an export. For an Exchange import with
no --url, it covers the mailbox's own domain, where on-premises Autodiscover
looks, and then only the EWS endpoint Autodiscover finds. The Microsoft and
Google sign-in and cloud hosts are always verified, with or without the flag.

Each HTTP client keeps a verifying agent and, only when the flag applies, a
second one that accepts invalid certificates, and picks per request by host.
The sign-in modules no longer take the flag at all. Autodiscover v2, which is
Microsoft's own service, is always verified.
2026-09-30 11:31:44 -07:00
jcoffey-dev 5ae0625ee1 export: write a message once, in every folder it was in
ci / test (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 2m11s
ci / announce (pull_request) Skipped
A source that files one message in several folders -- IMAP and Maildir
copies, Gmail labels -- leaves one archive row per folder, all pointing at the
same blob. Export imported each row on its own, so the message arrived on the
target once per folder. Worse, an interrupted export matched the rest by
Message-ID alone on the next run and skipped them, so their folders were never
added.

Export now folds rows with the same blob into one email, with the union of
their folders and keywords. On a match it adds, with one batched Email/set,
any migrated folder the target copy is missing; folders that exist only on the
target are left alone. Matching is still by Message-ID (or the fallback
digest), with size deciding between several messages that share one, so two
different messages are never folded onto one target email.

The archive is unchanged: the fold happens at export, so imports, resumes and
deletions work exactly as before.
2026-09-30 11:25:04 -07:00
jcoffey-dev 54fd18b410 docs: export matches and skips, it does not update
ci / test (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 1m50s
ci / announce (pull_request) Skipped
usage.md said items that match are updated. Export skips a match: a
change made at the source after the first export -- read state, a folder
move, an edited event, contact or Sieve script -- does not reach the target
on a second one. Say so until updating on re-export is built.
2026-09-30 11:16:47 -07:00
jcoffey-dev 210c04997c Track the Gitea workflows and docs/usage.md
The .gitignore inherited from upstream ignores every dotfile except .github,
and every Markdown file except README and CHANGELOG. The Gitea workflows and
docs/usage.md, which the README links to, were therefore never committed.
Both are now excepted and added.
2026-09-30 10:23:30 -07:00