Skip to main content

Module texts

Module texts 

Source
Expand description

Texts on your computers, read and sent through your phone, without Sioul being the phone’s SMS app (docs/texts.md; research: docs/research/sms.md, phase b). The phone’s SMS app stays the record: a fault of Sioul’s can delay a text on the computer, never lose one on the phone.

Reading, the whole history. With READ_SMS, the phone reads its texts from Android’s provider (the inbox and the sent box, multimedia messages and group threads included: Android shows no other app the drafts, the failed or queued texts, nor a multimedia message still to download) and writes a line per message in its own log, texts/log/<phone>.jsonl (Text), every column the provider gives kept for a faithful restore. The first import goes a batch at a time. The log only grows: a text deleted on the phone gets a line of its own saying so (Text::deleted), and every device keeps what it holds.

Media. Each part of a multimedia message the phone has downloaded (pictures, sound, video, cards, words) under a size you set travels as a sealed blob of the sharing (blobs/), never inside a line (Part).

An archive. The texts and their media are kept in Sioul’s data folder on every device that shares the part, never trimmed by age, with every column a later restore of a new phone would need; that restore is not built.

Sending. A computer writes a Request in its own file (texts/send/<device>.jsonl): a random key, the phone it must leave from, the number, the words, the SIM, when it was written. The phone decides at its step (verdict), claims the key in its private Ledger (written and flushed before Android is asked), hands the text to Android, and says what happened in its own texts/outcome/<phone>.jsonl (Outcome).

Never twice (verdict): a key already in the ledger is never sent again, whatever the sharing reads again; a request written before the ledger’s mark is refused (a ledger lost with the phone’s data cannot make old requests new); a request names its phone, and another phone never sends it; one older than EXPIRY_MS on the phone’s clock, corrected by how far the writer’s clock may run ahead, is not sent; Sioul never retries, Android does (three times, “reject duplicates”); after a crash between the claim and the result, Sioul looks for the row Android filed for it, and says “Your phone may not have sent it” when there is none (doubt_after), never sending again by itself. Send again makes a new key.

Sealed at rest: every line of these stores, and every file of their media, is sealed on the device that writes it (Sealer, with a key made from the sharing key, in each device’s keyring), lines padded to steps of PAD_STEP bytes inside: a computer’s copy is unreadable without the key.

Structs§

Claim
One line of the phone’s private ledger: a key, when, what was done.
Conversation
A conversation, as the Texts page lists it.
Found
One text found by search, with its conversation.
Ledger
The phone’s private ledger, never shared: every key it decided, and its mark.
Limits
What a SIM’s carrier lets a phone send (Android’s carrier configuration, SmsManager.getCarrierConfigValues, which asks no permission), as the phone says it in its outcomes (a “limits” line): numbers only, never the carrier’s name.
LogRead 🔒
A phone’s log as Logs read it: its lines, how far, the bytes just before that place (to tell the same file grown from another one), and the file’s stamp then (Stamp).
Logs
Every phone’s log under a root as read_logs gives it, kept between two reads and read again only where a file grew (a log only grows: a line is added at its end, never changed); a file that changed otherwise (another file under its name, cut short) is read again whole. With each text’s fingerprint kept by phone and row (one_each): the window’s refresh after an exchange that brought one text opened 20,000 sealed lines and hashed them all, 0.3 s on its thread (the review of 16 October 2026, LOW 3).
Mark
The ledger’s mark: requests written before it are never sent (a ledger lost cannot make them new).
Marks
Every device’s marks, by conversation: the latest moment read up to, and hidden up to.
Medium
A medium of a multimedia message written on a computer: its content’s hash (SHA-256, hex: its sealed blob in the sharing, and its sealed file on the computers), its content type, its size. Never its file’s name.
Message
One message of a conversation, or a text being sent.
Outcome
What became of a request, as its phone says it.
Part
One part of a multimedia message: its own columns, and where its content is.
Print
What a message is, whichever phone or backup holds it: what SMS Backup & Restore carries from one phone to another unchanged, and what its own backups hold of the rows Sioul’s archive keeps (docs/texts.md, “Each text once”). Never the provider’s row or conversation, which another phone numbers its own way.
Request
A text to send, as a computer writes it.
Row
A text’s row in its phone’s provider of texts: its table, Android’s _id, and the row’s own date there (milliseconds for a plain text, seconds for a multimedia message, as the provider counts them): what tells two texts apart on one phone. The plain texts’ table has no AUTOINCREMENT, so the next text takes a deleted newest text’s id again, and a provider emptied starts again at 1; the date tells those rows apart (docs/texts.md, “A row’s name”).
Said
A request’s state, as the computer says it.
Shown
A part of a message, as the page shows it.
Stamp 🔒
What tells a file unchanged since it was read: its size and time, and on Unix its inode and change time, which no tool sets back (a file of the same size whose time was put back, by rsync -t or a restore, is read again: the review of 16 October 2026, LOW 6). On Windows, Rust’s standard library gives neither (NTFS keeps a file ID and a change time, which only its unstable parts read): such a file is read again there once its size or time changes. NTFS’s tunnelling gives a file made again within seconds under the same name the old one’s creation time, so created() cannot be relied on either.
Text
A text as the phone’s provider holds it, as it travels.
TextMark
A device’s mark on a conversation (MARKS): read up to a moment (ms), or hidden up to a moment, its texts until then gone from Sioul on every device (a conversation deleted in Sioul while it is not the phone’s SMS app: the phone’s own app keeps them).
Viewer
What the view needs besides the lines.

Enums§

Standing
Where a device that asks stands in the sharing (verdict, and the replies’ Judge): counted now; gone by a sealed fact (it left, you forgot it, another device replaces it), refused; or not known yet (its records have not come, a file alone, a device silent for weeks), its request waiting while it is fresh (the review of 18 October 2026, I-a).
Took
What a multimedia message’s result says (TextSend.Result): sent, when Android took it to the carrier and the carrier answered Ok; not sent, and why; or, Android’s Ok with no answer of the carrier’s, to be looked for in the provider’s sent box (a message Android moved to its failed box is out of Sioul’s sight: none there, not sent); or in doubt, and why (“network”: each of Android’s tries ended on the network; “cancelled”: Android stopped it; “unexpected”: an unexpected failure, or a code Sioul does not know).
Verdict
What the phone does with a request.

Constants§

ADDR_BCC
ADDR_CC
ADDR_FROM
A multimedia message’s address types (addr.type, OMA’s PduHeaders): from, to, copy, hidden copy.
ADDR_TO
AHEAD_MS
A request dated further ahead of the phone’s clock than this is refused: the clocks disagree.
BATCH
The first import, and each step after: at most this many texts at a time.
DAY_MS 🔒
EXPIRY_MS
A request older than this on the phone’s clock is not sent.
FOLDER
Their folder, in the data folder (an archive, never a cache).
FOLD_MS
A phone’s notification and a text are one message within this time, by number (folded_into).
GSM_BASIC 🔒
GSM 03.38’s basic alphabet: one septet each.
GSM_EXTENDED 🔒
Its extension table: two septets each.
KEPT_DAYS
Requests and outcomes are taken out by their device after this many days…
LATE_DAYS
…and by any device this many days later (45 in all). Texts never are.
LEDGER
The phone’s private files, in the state folder, never shared: the ledger, its mark, the reader’s marks and the import’s progress, Java’s results.
LEDGER_KEPT_MS
The ledger keeps a key this long, past any request’s life.
LIMITS_AHEAD_MS
A phone’s “limits” line dated further ahead of the reader’s clock than this is passed over (a phone whose clock was once set ahead).
LOG
Each phone’s texts, a line each, the whole history.
LOG_CHECK 🔒
How many bytes before the place a log was read to tell the same file grown.
LOOK_AFTER_MMS_MS
…a multimedia message’s, handed or not, from this long after: Android may wait 30 minutes for a mobile network before its first try, and loses its queue if the phone restarts meanwhile (docs/texts.md)…
LOOK_AFTER_MS
A claim with no word from Android this long after is looked for in the provider.
MARK
MARKS
Each device’s marks on conversations: read up to a moment, hidden up to a moment (a conversation deleted in Sioul; 23 October 2026). Never trimmed.
MEDIA
The media of multimedia messages, each sealed at rest by its content’s hash; never shared as a store (they travel as blobs).
MEDIA_BATCH
…and this many bytes of media.
MEDIA_CAP_MB
A part over this many bytes stays on the phone, said, unless you set another size (MB, texts.toml).
MEDIA_MAX
A multimedia message from a computer: at most this many media.
MMS_LAST_WORD_MS
…until this long after, Android’s last word at the latest: each of its three tries may wait 30 minutes and 5 seconds for a network, then two minutes on it, with 2 and 4 seconds between (MmsRequest, MmsNetworkManager, android16-release: some 97 minutes). Not found by then: the doubt; until then, it may still go.
MMS_MAX_EVER
The most a multimedia message may weigh, whatever a phone said: Android’s own ceiling for one (MmsService.MAX_MMS_FILE_SIZE, 8 MB).
MOVED_WITHIN_MS
How far apart a received text’s two dates may be for a re-date (a provider re-dates its own sending, an MMS downloaded or sent, a resend; never a text received hours later under a deleted text’s id).
OUTCOME
Each phone’s word on each text it was asked to send.
OWN_ADDRESS
What Android writes for “this phone” among a multimedia message’s addresses.
PAD_STEP
Each line’s plain length is a multiple of this before it is sealed.
PART
The sharing’s part that carries them.
PART_KINDS
A part’s words for its kind: “texts-part-picture” and the others take a size.
READER
RESULTS
SEND
Each computer’s texts to send.
STORES
The shared stores, in that order.
UNREAD_DAYS
A text newer than this, in, not read since: unread (older ones count as read).
WRITE_MAX
A text written on a computer: at most this many characters.

Traits§

Sealer
What seals a line at rest and opens it: the caller’s, made from the sharing key.

Functions§

append
Lines added at the end of a device’s own file, under its lock, each written whole (padded, sealed), those whose id the file holds already left out (id_of; none: every line written). Returns how many were written.
carried
Words as XML 1.0 can carry them: the control characters it refuses (all below a space but the tab, the line feed and the carriage return, and U+FFFE, U+FFFF) left out. SMS Backup & Restore’s backups are XML, so a text restored from one never holds them.
conversation_id
A conversation’s id: its people’s keys, sorted, joined.
conversations
The conversations, newest first: every text’s, and those you wrote to from a computer.
day_and_time 🔒
A moment’s day and time, for a thread: (“Today”, “14:02”), (“Monday 5 October”, “14:02”), (“Friday 3 May 2024”, “09:15”).
doubt_after
After a crash between the claim and Android’s word: what to say of a claim LOOK_AFTER_MS old with no result, given whether the provider holds a sent row Sioul filed for it (found: its row). Found: sent. Not found: “doubt”, never sent again. A multimedia message’s claim is looked for by its key from LOOK_AFTER_MMS_MS on, and said in doubt only once Android’s last word is past (MMS_LAST_WORD_MS): until then it may still go.
drop_hidden
A phone’s own log without the texts hidden on any device (Marks): written again by its one writer, the phone, so that every computer’s copy loses them too. A line that does not open stays. How many went.
file_name
A device’s name as its files name it (a line’s device).
fold_logs
The phones’ log lines (each with its device) as read_logs gives them: oldest first, each text once by phone and row (a line named by its id alone and the same row named with its date are one: a phone put back on an older Sioul, which writes again under the old names what a newer one read, never doubles a text on the computers; the review of 16 October 2026, MEDIUM 1), a deletion’s line folded into its text, a line moved under its new name (its row’s date rewritten) shown under that name alone, its old name kept beside it (also), so that a request sent from a computer still finds its text (review of 18 October 2026, L-4).
folded_into
The conversation a phone’s notification of a text is the same message as (phonemsgs::Line: its sender’s number’s key, its time): a text in from that one number within FOLD_MS. None: it stays a line of its own.
folder
The folder of the texts: the phones’ logs, the requests and outcomes, the media; in the data folder.
grow 🔒
A log read on from where it was read (LogRead), or again whole when it is not that file grown; only whole lines. Whether its lines changed.
is_false 🔒
is_words
A part’s content type that is words, never a medium: the text and the SMIL that lays it out.
is_zero 🔒
is_zero_u64 🔒
kept
What a device keeps: how many texts, and how many bytes of media here (media: those whose sealed file is on this device).
kind_of 🔒
What a part is, in a word for the page.
known_reason 🔒
A failure’s reason as the words know it.
known_refusal 🔒
A refusal’s reason as the words know it.
last_sim
The SIM a conversation last used, on the phone that sends: its texts’ sub, the newest; -1 none.
limits_of
What a phone last said its carriers let it send (its newest “limits” line), and when (ms); none before it said. A line dated more than LIMITS_AHEAD_MS ahead of now_ms (the reader’s clock) is passed over: a phone whose clock was once set ahead would otherwise be read by it until that date, whatever it said since.
messages
A conversation’s messages, oldest first: its texts, deleted ones said, and the texts you wrote to it from a computer with their states; a request Android filed is said on its row, once. A row is its phone’s own: another phone’s row of the same number is another text (row_key).
mms_failure
Why a multimedia message was not sent, as the words say it: Android’s code (SmsManager’s MMS_ERROR_…: 8 and 11 mobile data off, 3 no mobile network within 30 minutes, 2, 7 and 12 no multimedia settings for the carrier, 5 not read, 6 the carrier’s messaging app asking to try later, 9 and 10 an inactive SIM, 13 too large for a satellite link), else the carrier’s status (ENC 7.3.48: 0xC0 to 0xDF for a moment, 0xE1 service denied, 0xE5 content not accepted, 0xEB no credit, the rest refused; MMS 1.0’s 0x82, 0x87 and 0x88 alike).
moved
Whether new is the message of old under a date its provider rewrote: the same table and row id, another date, the same way and people; a text’s words the same, and either sent from the phone or dated within MOVED_WITHIN_MS of the other (the plain texts’ table gives a deleted newest text’s id to the next one: Alice’s “Oui.” deleted, her next “Oui.” is another text, said deleted as before: review of 18 October 2026, L-3); a multimedia message’s media the same by their hashes wherever the older has them, its words and media as complete or more (one read before its parts were attached comes whole).
moved_marks
The marks of the lines whose row its provider re-dated (moved): each line of a phone’s log not marked yet whose row is no longer listed, while its row id is listed under another date with a line of the log holding the same message (the newest such): a deletion’s line naming it (Text::moved), never “deleted on your phone”.
new_key
A random key, 32 hex digits, from the system’s randomness (/dev/urandom); the clock’s when none.
no_sim 🔒
number
A column’s number, written as a number or as words.
one_each
Every phone’s texts with each text once (docs/texts.md, “Each text once”): a text found in several phones’ logs, as after a restore onto a new phone, once; a text there twice in one phone’s log (truly sent twice), twice: for each fingerprint (Print::key), as many as the phone holding most, its copies paired with the others’ in their logs’ order. The copy kept of each pair has the most media here, else is not deleted, else is the first phone’s by name; it is said deleted only when every copy is, and names the others (Text::also). Oldest first, as read_logs. For what the page, the search and agents read; the phones’ logs themselves keep every copy (nothing is lost if one goes).
one_each_by
one_each with each text’s fingerprint as print gives it (Print::key with the region of the numbers, kept by phone and row between two reads: Logs).
own_file
A device’s file in one of the stores under root: <store>/<device>.jsonl.
padded
A JSON object padded inside: {…,"pad":" "}, its length a multiple of PAD_STEP.
parts
How many parts a text takes, and in which alphabet: GSM’s 7 bits (160 characters in one part, 153 in each of several) or UCS-2 (70, 67) as soon as one character is outside it. Android chooses alike (divideMessage).
place_of 🔒
A line’s place in its phone’s log: its row (Row::of), so that a line named by its id alone (before 16 October 2026) and its row’s name now are one text; its name for a line of no row.
print_people
Whether a multimedia message’s addresses of this type are its other people for Print: a received one’s sender; a sent one’s recipients.
private_folder
The phone’s private texts folder, in the state folder: never shared.
read_file
Every line of a file that opens and reads, in order; the rest passed over.
read_lines
Every line of a file’s text that opens and reads, in order; the rest passed over.
read_logs
Every phone’s texts, oldest first, each once (by phone and row), a deletion’s line folded into its text (deleted); the whole history.
read_outcomes
read_requests
Every device’s requests under root, each with its device: its sealed writer (a line whose writer is not its file’s device is passed over: moved from another device’s file), else, a request of an older Sioul, its file’s name.
read_store 🔒
Every device’s lines of a store under root, each with its device.
record
A line added to the ledger and flushed to the disk before this returns: the claim exists before Android is asked to send.
record_all
Lines added to the ledger together and flushed once before this returns (a step’s decisions: one flush, not one each); nothing for none.
refusal
Why a number or words are refused from a computer, if they are: several recipients (an MMS group), a short number (premium risk; Android would ask on the phone), no words, too many. None: it may go.
refusal_mms
Why a multimedia message is refused from a computer, if it is: its words over WRITE_MAX; no medium, or more than MEDIA_MAX; a medium of a kind the phone does not send (pictures, videos, sounds, contact cards and calendar entries only: another file goes by mail) or not named by a content’s hash; other people beside its number (a group: a later step); a number as refusal refuses one. None: it may go.
replace_flushed 🔒
A file written whole beside, flushed, then put in place: a crash leaves the old one or the new one, never an empty one.
row_key 🔒
The key of the request a text is, by the row its phone filed it as (Outcome::row): its own row or one of its copies’ (Text::also), each on its own phone, never another phone’s row of the same number. An outcome that names no phone matches the row on any (as before phones were two). A row is its name with its date (Row::name); an outcome written before 16 October 2026 names it by its id alone, and matches that id’s text only from when its request could be sent (from) to a little after the outcome itself (Android files the row before its result comes: AHEAD_MS), never an older text whose id the text sent took again, nor a text received days later under that id (review of 16 October 2026, LOW 5).
said
A request’s state in words, never red, never “late”: waiting for the phone (and when it last shared), sending, sent at, delivered at (only when the carrier said so), not sent and why, expired, may not have been sent. A multimedia message (media) refused “empty” was read by a phone whose Sioul cannot send one yet: said so; its media not there in time, said.
search
The texts holding every word of query, case and accents aside, in their words, a part’s name, or their people’s names or numbers; the newest first, limit at most. For a search of the archive (the MCP server’s).
sendable
Whether a phone sends a medium of this content type in a multimedia message (decisions 7 to 9): a picture, a video, a sound, a contact card or a calendar entry.
shown 🔒
A part as the page shows it: what it is and its size; too large, or not downloaded, said; on its way when its file has not come yet. The SMIL, which only lays the message out, and the text parts (in the words) are not shown apart.
state_of
What a request’s outcomes say: its latest meaningful one (delivered over sent over handed…).
time_of 🔒
The time a line says (at, else written), opened; none when it does not open.
time_of_day
“14:02”: a moment (ms) as a time of day, in now’s zone.
title_of 🔒
“Dr Martin”, “Dr Martin, Alice”, “01 99 00 12 34”.
took
A multimedia message’s result: Android’s code (-1, Activity.RESULT_OK; else SmsManager.MMS_ERROR_…), the carrier’s answer (M-Send.conf) when it came, and the HTTP status Android adds to its code 4 (0 none). Android’s Ok alone is not the carrier’s. Its code 4 with no HTTP status, or one under 400, says that every try ended on the network (an I/O failure, even a read timeout after the message was posted: MmsHttpClient, MmsRequest, android16-release): the carrier may have taken it, once or more; with a status of 400 or more, the carrier refused it. Its code 0 (Activity.RESULT_CANCELED: Android stopped it) and 1 (an unexpected failure, which may come after the message went), and any code Sioul does not know, are said in doubt too.
trim_ledger
The ledger’s old keys taken out, LEDGER_KEPT_MS on (any request expired long before; the mark refuses those written before it anyway).
trim_others
Another device’s requests and outcomes LATE_DAYS past their time taken out here: texts never.
trim_own
This device’s own requests and outcomes past KEPT_DAYS taken out; its texts never (an archive). A line that does not open stays. Returns how many went.
unread
A conversation’s unread texts: in, newer than UNREAD_DAYS, after its last read mark, not deleted on the phone; newest first.
verdict
The never-twice decision, step for step: another phone’s; decided already (the ledger holds the key, whatever the sharing read again); written by a computer of an older Sioul after this phone began to check writers (“old-computer”); asked by a device gone from the sharing (standing: it left, you forgot it, another device replaces it: “not-counted”), or one it does not know yet, which waits while its request is fresh (Verdict::Wait; then dated ahead or expired, as below); refused (refusal, a multimedia message’s refusal_mms); written before the ledger’s mark; dated ahead of the phone’s clock; older than EXPIRY_MS; else sent. The time written is corrected by how far the writer’s clock may run ahead (Request::ahead, measured by the writer as an upper bound: a request looks older, never younger). standing is asked only of a request not decided yet.
visible
The texts without those hidden (Marks::hides).
when_words 🔒
“14:02” today, “Yesterday 14:02”, “Monday 5 October 14:02”.
words_hash
A text’s words, hashed as the ledger keeps them (FNV-1a, 16 hex digits).
write_flushed 🔒
Written (or appended) and flushed to the disk, yours alone.
write_mark
A mark written in this device’s own file.
write_request
A request added to its device’s own file under root, its writer (device) sealed in it, padded and sealed, under its lock.
written
A value as written: its JSON padded with spaces inside a pad field to a multiple of PAD_STEP bytes, then sealed. No line says how long its words are.
xml_char
A character XML 1.0 can carry (its Char; Rust’s strings hold no lone surrogate).