Skip to main content

Module draftcopies

Module draftcopies 

Source
Expand description

The copy of the message a draft answers or forwards, kept beside it (drafts/<id>.eml, Draft::keep_original), stays as it came: encrypted when it came so, opened only at Send, in memory (sioul_sync::send::build_draft). Until 19 October 2026 Sioul wrote there the decrypted text of an encrypted message it answered; the sharing carried that text to each of your devices, and kept its earlier versions on each (sioul_sync::history). seal_beside and seal_versions encrypt those clear copies again, to your own certificates, on each device that holds them, and overwrite what they held where the filesystem lets it (crate::filelock::Placed::finish; docs/client.md, “What a disk keeps”). Nothing else is touched: a draft’s own file, its text and its choices stay as they are, and a copy is replaced whole, never missing.

Each copy’s new bytes are written beside it first; then it takes its place under the sharing’s exchange lock (Hold), a short hold at a time, only if the file is still as it was read; its old bytes are overwritten once the lock is let go. The sharing reads these files only under that lock, by their names: it never holds a file being replaced, so it never reads, seals nor sends the zeros that follow. Every other reader (Send, the writing window) reads through crate::filelock::read_whole, which never returns them.

Which copies may hold decrypted text, in doubt sealed (review of 19 October 2026, F6 and N7), judged by where they come from, never by their shape alone: a copy kept as it came (its draft says so, from 19 October 2026: Draft::copy_as_received) never. Any other was written before: the message itself when it came in clear, its decrypted text when it came encrypted. It is sealed unless it is, byte for byte, a message found here under its Message-ID or the one its draft answers (Draft::in_reply_to), every message of those IDs here having come in clear: a copy of a message found nowhere, or of one another message shares its ID with (anyone who knows an ID can send one), is sealed. A decrypted entity with no header of its own looks like a message that came as it is (N7): its shape says nothing. Its earlier versions and what was kept before sharing began are judged the same way, and “Put back” opens a sealed one with your key at Send.

What a look decides is kept with the file as it was read (its stamp taken from the descriptor that read it, or from the new file before it took its place), never as the path names it afterwards: a version an exchange puts in place meanwhile is looked at again (N6).

Structs§

Batch 🔒
Copies prepared, placed under the lock in short holds.
Certs
Your own certificates, to seal to: read only once a copy is to be sealed (reading every key, others’ too, costs a phone’s step its time: 18 ms for 300 others’ keys, review of 19 October 2026, F9).
Judged
The files looked at, as they were then (their device, number, size and time): not read again until they change. Kept on the disk between processes (Judged::load, Judged::save: state/draftcopies.json, never shared), so that a process started for a moment (a phone’s background step) reads only what changed since the last look; one that does not read (another format, damaged) is a look from nothing, which seals nothing twice.
JudgedFile 🔒
The verdicts’ file: its format, and each file’s stamp.
Sealed
What a look did, in counts only: nothing of what the copies say.
Waiting 🔒
A copy’s new bytes beside it, waiting for its place: the file as it was read, and what it counts as.

Constants§

BATCH_BYTES 🔒
BATCH_FILES 🔒
The copies prepared at once, their new bytes beside them on the disk.
HOLD_AT_MOST 🔒
The longest the replacements made under one hold of that lock take: an exchange waiting for it (a dose’s) never waits longer (the lesson of the review of 18 October 2026, L-3). Only renames happen then: each copy’s new bytes are written before, its old bytes overwritten after.
JUDGED_FORMAT 🔒
The verdicts’ format: another one is read as none.
LET_GO 🔒
How long the lock is let go between two holds, for an exchange that waits, beside the hold’s own hand-off to one waiting in this process (the guard sioul_sync::share::replacements_hold gives waits for it to take the lock).

Traits§

Held
A hold of the exchanges’ lock, as a Hold gives it: let go when dropped.

Functions§

copy_id 🔒
The draft’s name of a copy beside it: <id>.eml, its id plain letters and digits as a draft’s is (Draft::by_id).
may_hold_decrypted 🔒
Whether a copy in clear may hold an encrypted message’s text (in doubt, yes), a copy not kept as it came: see the module’s words. answers, the Message-ID its draft answers, if any; find gives every file of a Message-ID in your mail here.
message_id
The Message-ID a message names, bare (“abc@example.org”).
orphaned 🔒
An encrypted copy left alone more than a day: its draft, gone, will not come.
prepare 🔒
clear, the content of the copy at path, encrypted to to and written beside it, waiting for its place, with its size; None when no certificate takes it.
read_copy 🔒
A copy read whole for a look (counted in tests).
seal_beside
The clear copies beside the drafts of drafts that may hold an encrypted message’s text, encrypted again to your own certificates. find gives every file of a Message-ID in your mail here; hold, the sharing’s lock, under which each copy takes its place.
seal_versions
Earlier versions of those copies (paths, each a file), judged as the copies are, encrypted again to your own certificates, each under hold as above: only “Put back” reads them, which then opens a sealed one with your key at Send.
unshared
The guard of a device that has never shared: nothing to hold.

Type Aliases§

Hold
The sharing’s exchange lock, taken for a batch of replacements and let go when what it returns is dropped (sioul_sync::share::exchange_lock); None when it cannot be taken: the copies wait for the next look. A device that has never shared gives a guard that holds nothing (unshared).