Files
chatmail-core/docs/schema.sql
link2xt 31c37848ec docs: add SQL schema documentation
There is currently no place to document up to date SQL schema.
New database is initialized with src/sql/tables.sql
and then updated by migrations,
So tracking down how some column is used requires grepping the code,
looking for a migration adding it and corresponding commits.

Co-Authored-By: biørn <r10s@b44t.com>
2026-08-13 12:07:15 +00:00

784 lines
27 KiB
SQL

-- Commented SQLite database schema.
--
-- This file should only be used for documentation,
-- do not run this SQL e.g. to create databases.
-- This is because we want to be 100% sure
-- that new users and users who run the migrations
-- get the same database schema.
--
-- This is a dump of the database schema using `sqlite3 dc.db .schema`,
-- formatted, reordered and commented afterwards.
-- Raw dump of the database schema does not have comments
-- for deprecated columns and columns added by migrations.
CREATE TABLE config (
id INTEGER PRIMARY KEY,
keyname TEXT UNIQUE,
value TEXT NOT NULL
);
CREATE INDEX config_index1 ON config (keyname);
CREATE TABLE contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- Name of the contact as set by the user.
name TEXT DEFAULT '',
-- Normalized name for search.
name_normalized TEXT,
-- Email address last seen as the From address for this contact.
-- For address-contacts that have empty "fingerprint" this should never change.
-- For key-contacts this address may change when a new signed message is received.
--
-- This is the address messages are sent to unless the key
-- advertises a different set of addresses, in which case
-- this address should be ignored
-- (and not appended to the list of addresses advertised in the key).
addr TEXT DEFAULT '' COLLATE NOCASE,
-- The origin or source of the contact,
-- e.g. whether the contact was added from some chat
-- or via SecureJoin.
origin INTEGER DEFAULT 0,
-- True if the contact is blocked.
-- Unlike the chat, contact is either blocked or not,
-- there is no third "contact request" state.
blocked INTEGER DEFAULT 0,
-- Timestamp of the last time any message was received from this contact.
last_seen INTEGER DEFAULT 0,
-- Key-value parameters.
param TEXT DEFAULT '',
-- Name of the contact as sent by the contact itself.
authname TEXT DEFAULT '',
-- Timestamp of the last time we have sent our avatar to this contact.
-- Used to decide whether to send the avatar.
-- Normally avatars are resent after 14 days.
-- This column is reset to 0 when avatar is changed.
selfavatar_sent INTEGER DEFAULT 0,
-- Last seen message signature from this contact, also known as bio in the UI.
status TEXT DEFAULT '',
-- True if the contact is a bot.
is_bot INTEGER NOT NULL DEFAULT 0,
-- OpenPGP key fingerprint for "key-contacts",
-- empty string for "address-contacts".
fingerprint TEXT NOT NULL DEFAULT '',
-- ID of the contact that has "introduced" us to this contact
-- by sharing the key with a verified attribute or in a "verified" chat.
verifier INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX contacts_index1 ON contacts (name COLLATE NOCASE);
CREATE INDEX contacts_index2 ON contacts (addr COLLATE NOCASE);
CREATE INDEX contacts_fingerprint_index ON contacts (fingerprint);
CREATE TABLE chats (
-- Chat ID 0 should never be used as it is used as a sentinel value in some APIs.
--
-- Chat IDs 1 to 9, including 9, are reserved.
-- The first proper chat gets ID 10, but may not exist if it is deleted.
--
-- Chat ID 3 is the trash chat and this chat ID is assigned to deleted messages
-- to create "tombstones".
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- Chat type, e.g. 100 for single chat, 120 for a group etc.
-- Check the Chattype enumeration in the code for concrete values.
type INTEGER DEFAULT 0,
name TEXT DEFAULT '',
-- Normalized name for search.
name_normalized TEXT,
-- 0 for visible chat, 1 for hidden and 2 for contact request.
-- 1 does not necessarily mean that the contact is blocked.
blocked INTEGER DEFAULT 0,
-- Chat-Group-ID header for encrypted groups and channels.
-- Empty for unencrypted groups and single chats.
grpid TEXT DEFAULT '',
-- Key-value parameters.
param TEXT DEFAULT '',
-- Chat visibility.
-- 0 for normal, 1 for archived and 2 for pinned chats.
archived INTEGER DEFAULT 0,
locations_send_begin INTEGER DEFAULT 0,
locations_send_until INTEGER DEFAULT 0,
locations_last_sent INTEGER DEFAULT 0,
-- Time when the chat was created.
-- Used for sorting in the chatlist when the chat has no messages.
created_timestamp INTEGER DEFAULT 0,
-- 0 if the chat is not muted.
-- -1 if the chat is muted forever.
-- Otherwise the timestamp until which the chat is muted.
muted_until INTEGER DEFAULT 0,
-- Disappearing messages timer.
-- 0 means the timer is disabled.
ephemeral_timer INTEGER,
-- Deprecated, but still used to send Chat-Verified headers
-- for existing protected chats.
-- All new chats are created as "not protected".
protected INTEGER DEFAULT 0,
gossiped_timestamp INTEGER DEFAULT 0, -- deprecated 2025-04-08, replaced with gossip_timestamp table
-- Unused columns, drafts are now tracked as separate
-- messages with a special msgs.state value.
draft_timestamp INTEGER DEFAULT 0,
draft_txt TEXT DEFAULT ''
);
CREATE INDEX chats_index1 ON chats (grpid);
CREATE INDEX chats_index2 ON chats (archived);
CREATE INDEX chats_index3 ON chats (locations_send_until);
CREATE INDEX chats_index4 ON chats (name);
CREATE TABLE chats_descriptions (
chat_id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL DEFAULT ''
) STRICT;
-- Chat member lists.
-- Saved messages has only self.
-- Single chats have only the contact, but not self.
-- Groups have self if we are part of the group.
CREATE TABLE chats_contacts (
chat_id INTEGER,
contact_id INTEGER,
add_timestamp NOT NULL DEFAULT 0,
remove_timestamp NOT NULL DEFAULT 0,
UNIQUE(chat_id, contact_id)
);
CREATE INDEX chats_contacts_index1 ON chats_contacts (chat_id);
CREATE INDEX chats_contacts_index2 ON chats_contacts (contact_id);
-- This table contains "message bubbles" that are normally visible
-- and "tombstones" that are put into the trash chat
-- or have a "hidden" column set to the true value.
--
-- Tombstones are used to avoid downloading and processing
-- the same messages twice, e.g. when the message is deleted
-- but another copy of it arrives later.
CREATE TABLE msgs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- The messages may be split into pre- and post-message.
-- Pre-messages have a Chat-Post-Message-ID header
-- which contains the Message-ID of the post-message.
-- Post-messages have a Chat-Is-Post-Message header.
--
-- For outgoing messages that are split into pre-message
-- and post-message, rfc724_mid contains the Message-ID
-- of the post-message, and pre_rfc724_mid
-- contains the Message-ID of the pre-message.
--
-- For incoming messages, when a pre-message arrives,
-- rfc724_mid is set to the Message-ID of the post-message,
-- and pre_rfc724_mid is set to the Message-ID of the arrived pre-messsage.
-- For other messages rfc724_mid is taken from the Message-ID
-- and pre_rfc724_mid is set to empty string.
-- Message-ID as defined in RFC 724 (now replaced by RFC 5322)
rfc724_mid TEXT DEFAULT '',
-- Message-ID of the pre-message.
pre_rfc724_mid TEXT DEFAULT '',
-- Chat ID.
--
-- Chat ID 3 is the trash chat, messages with this ID are tombstones.
chat_id INTEGER DEFAULT 0,
-- Contact ID of the message author.
from_id INTEGER DEFAULT 0,
-- Mostly unused Contact ID of the first recipient or 0.
-- For info messages set to ContactID::INFO (2).
--
-- If to_id is set to 2, the message must be displayed
-- as an info message even if from_id is not set to 2.
--
-- Info messages generated by Webxdc status updates
-- have from_id set to the contact ID of the sender
-- and to_id set to 2.
-- from_id is then used to collapse series of updates
-- into a single message (see test_webxdc_info_msg_cleanup_series),
-- while to_id of 2 makes sure the message is displayed
-- as an info message.
to_id INTEGER DEFAULT 0,
-- Message viewtype.
-- 10 is a text message,
-- 20 is an image etc.
type INTEGER DEFAULT 0,
-- Message state,
-- e.g. 10 for fresh incoming messages,
-- 26 for outgoing delivered message,
-- 28 for outgoing message that got a read receipt.
--
-- Messages sent by self, but arriving from a second device
-- are still considered "outgoing".
state INTEGER DEFAULT 0,
-- Size of the attachment for file parts, otherwise 0.
bytes INTEGER DEFAULT 0,
txt TEXT DEFAULT '', -- Message text for display.
txt_normalized TEXT, -- Message text normalized for search.
txt_raw TEXT DEFAULT '', -- deprecated 2025-03-29
-- Key-value parameters.
param TEXT DEFAULT '',
-- For messages bookmarked into the Saved Messages chat,
-- ID of the original message, making it possible to jump to it.
starred INTEGER DEFAULT 0,
-- True if the message is pinned.
pinned INTEGER NOT NULL DEFAULT 0,
timestamp INTEGER DEFAULT 0, -- Timestamp of the message used for sorting.
timestamp_sent INTEGER DEFAULT 0, -- Timestamp of the message as sent in the Date header.
timestamp_rcvd INTEGER DEFAULT 0,
-- True if the message should not be displayed.
-- Most messages that should not be displayed
-- better go to the trash chat (ID 3),
-- but at least reactions are hidden
-- so they still belong to the chat
-- and can be marked as noticed when the chat is opened.
hidden INTEGER DEFAULT 0,
-- mime_headers column actually contains BLOBs, i.e. it may
-- contain non-UTF8 MIME messages. TEXT was a bad choice, but
-- thanks to SQLite 3 being dynamically typed, there is no need to
-- change column type.
mime_headers TEXT,
-- True if mime_headers column is compressed with Brotli.
mime_compressed INTEGER NOT NULL DEFAULT 0,
mime_modified INTEGER DEFAULT 0,
mime_in_reply_to TEXT,
mime_references TEXT,
-- Location ID for POI locations manually placed on the map.
location_id INTEGER DEFAULT 0,
error TEXT DEFAULT '',
-- Timer value in seconds. For incoming messages this
-- timer starts when message is read, so we want to have
-- the value stored here until the timer starts.
ephemeral_timer INTEGER DEFAULT 0,
-- Timestamp indicating when the message should be
-- deleted. It is convenient to store it here because UI
-- needs this value to display how much time is left until
-- the message is deleted.
ephemeral_timestamp INTEGER DEFAULT 0,
subject TEXT DEFAULT '',
-- Download state for the message.
-- 0 for most messages, meaning the message is fully downloaded.
-- Otherwise 10 for the message available for download etc.
download_state INTEGER DEFAULT 0,
-- Information extracted from Received headers
-- as a plain text for debugging.
hop_info TEXT,
-- True if the message is deleted on the server.
-- If this is true and another copy of the message arrives
-- it should be deleted from the server as well.
deleted INTEGER NOT NULL DEFAULT 0,
--
-- Unused columns.
--
-- Always 1 for new messages.
-- Previously:
-- 0 if the message is a non-chat message,
-- 1 if the message is a chat message,
-- 2 if the message is a non-chat reply to a chat message
msgrmsg INTEGER DEFAULT 1,
server_folder TEXT DEFAULT '', -- Deprecated column that was used before "imap" table, replaced by imap.folder
server_uid INTEGER DEFAULT 0, -- Deprecated column that was used before "imap" table, replaced by imap.uid
-- Unused column formely used to mark the messages
-- that should be moved to the dedicated IMAP folder.
-- It was replaced with imap.target, which is also now
-- used only to mark the messages on IMAP for deletion.
move_state INTEGER DEFAULT 1
);
CREATE INDEX msgs_index1 ON msgs (rfc724_mid);
CREATE INDEX msgs_index2 ON msgs (chat_id);
CREATE INDEX msgs_index3 ON msgs (timestamp);
CREATE INDEX msgs_index4 ON msgs (state);
CREATE INDEX msgs_index5 ON msgs (starred);
CREATE INDEX msgs_index6 ON msgs (location_id);
CREATE INDEX msgs_index7 ON msgs (state, hidden, chat_id, timestamp);
CREATE INDEX msgs_index8 ON msgs (ephemeral_timestamp);
CREATE INDEX msgs_index9 ON msgs (pre_rfc724_mid);
CREATE INDEX msgs_index10 ON msgs (pinned) WHERE pinned=1;
CREATE TABLE leftgrps (
id INTEGER PRIMARY KEY,
grpid TEXT DEFAULT ''
);
CREATE INDEX leftgrps_index1 ON leftgrps (grpid);
CREATE TABLE msgs_mdns (
msg_id INTEGER,
contact_id INTEGER,
timestamp_sent INTEGER DEFAULT 0
);
CREATE INDEX msgs_mdns_index1 ON msgs_mdns (msg_id);
CREATE TABLE locations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
latitude REAL DEFAULT 0.0,
longitude REAL DEFAULT 0.0,
accuracy REAL DEFAULT 0.0,
timestamp INTEGER DEFAULT 0,
chat_id INTEGER DEFAULT 0,
from_id INTEGER DEFAULT 0,
-- If true, the location is an independent POI
-- and should not be part of the path.
independent INTEGER DEFAULT 0
);
CREATE INDEX locations_index1 ON locations (from_id);
CREATE INDEX locations_index2 ON locations (timestamp);
CREATE TABLE devmsglabels (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT,
msg_id INTEGER DEFAULT 0
);
CREATE INDEX devmsglabels_index1 ON devmsglabels (label);
-- Table to store QR code tokens for SecureJoin protocol.
CREATE TABLE tokens (
id INTEGER PRIMARY KEY,
-- Namespace is one of:
-- 0 - unknown
-- 100 - invite number
-- 110 - auth
namespc INTEGER NOT NULL,
foreign_key TEXT DEFAULT '' NOT NULL,
token TEXT NOT NULL UNIQUE,
timestamp INTEGER DEFAULT 0 NOT NULL
) STRICT;
-- State of the scanner of the QR code (Bob) in SecureJoin protocol.
CREATE TABLE bobstate (
id INTEGER PRIMARY KEY AUTOINCREMENT,
invite TEXT NOT NULL,
next_step INTEGER NOT NULL,
chat_id INTEGER NOT NULL
);
CREATE TABLE smtp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
rfc724_mid TEXT NOT NULL, -- Message-ID
mime TEXT NOT NULL, -- SMTP payload
msg_id INTEGER NOT NULL, -- ID of the message in `msgs` table
recipients TEXT NOT NULL, -- List of recipients separated by space
retries INTEGER NOT NULL DEFAULT 0 -- Number of failed attempts to send the message
);
CREATE TABLE smtp_mdns (
msg_id INTEGER NOT NULL, -- id of the message in msgs table which requested MDN (DEPRECATED 2024-06-21)
from_id INTEGER NOT NULL, -- id of the contact that sent the message, MDN destination
rfc724_mid TEXT NOT NULL, -- Message-ID header
retries INTEGER NOT NULL DEFAULT 0 -- Number of failed attempts to send MDN
);
CREATE TABLE smtp_status_updates (
msg_id INTEGER NOT NULL UNIQUE, -- msg_id of the webxdc instance with pending updates
first_serial INTEGER NOT NULL, -- id in msgs_status_updates
last_serial INTEGER NOT NULL, -- id in msgs_status_updates
descr TEXT NOT NULL -- text to send along with the updates
);
-- Table of "sync items" to be grouped into sync messages
-- and sent to own devices.
CREATE TABLE multi_device_sync (
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- JSON of the "sync item".
item TEXT DEFAULT ''
);
CREATE TABLE reactions (
msg_id INTEGER NOT NULL, -- id of the message reacted to
contact_id INTEGER NOT NULL, -- id of the contact reacting to the message
reaction TEXT DEFAULT '' NOT NULL, -- a sequence of emojis separated by spaces
PRIMARY KEY(msg_id, contact_id),
FOREIGN KEY(msg_id) REFERENCES msgs(id) ON DELETE CASCADE -- delete reactions when message is deleted
FOREIGN KEY(contact_id) REFERENCES contacts(id) ON DELETE CASCADE -- delete reactions when contact is deleted
);
CREATE INDEX reactions_index1 ON reactions (msg_id);
CREATE TABLE pending_reactions (
rfc724_mid TEXT NOT NULL,
contact_id INTEGER NOT NULL,
reaction TEXT NOT NULL,
timestamp INTEGER NOT NULL,
PRIMARY KEY(rfc724_mid, contact_id),
FOREIGN KEY(contact_id) REFERENCES contacts(id) ON DELETE CASCADE
) STRICT;
-- accumulated reactions received from broadcast owner.
-- pairs of reaction and their counts.
-- these pairs are given to the UI (for non-broadcasts, the pairs are calculated from the `reactions` table)
CREATE TABLE broadcasted_reactions (
msg_id INTEGER NOT NULL DEFAULT 0,
reaction TEXT NOT NULL DEFAULT '',
count INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY(msg_id) REFERENCES msgs(id) ON DELETE CASCADE -- delete reactions when message is deleted
) STRICT;
CREATE INDEX broadcasted_reactions_index1 ON broadcasted_reactions (msg_id);
-- messages that received reactions from broadcast subscriber to broadcast owner.
-- the broadcast owner will send them, accumulated by chat_id,
-- to all other subscribers every some minutes, and then remove all entries with the chat_id processed.
CREATE TABLE reactions_need_broadcast (
chat_id INTEGER NOT NULL DEFAULT 0,
msg_id INTEGER NOT NULL DEFAULT 0,
UNIQUE (chat_id, msg_id),
FOREIGN KEY(msg_id) REFERENCES msgs(id) ON DELETE CASCADE -- delete reactions when message is deleted
) STRICT;
CREATE INDEX reactions_need_broadcast_index1 ON reactions_need_broadcast (chat_id);
CREATE TABLE connection_history (
host TEXT NOT NULL, -- server hostname
port INTEGER NOT NULL, -- server port
alpn TEXT NOT NULL, -- ALPN such as smtp or imap
addr TEXT NOT NULL, -- IP address
timestamp INTEGER NOT NULL, -- timestamp of the most recent successful connection
UNIQUE (host, port, alpn, addr)
) STRICT;
CREATE TABLE dns_cache (
hostname TEXT NOT NULL,
address TEXT NOT NULL, -- IPv4 or IPv6 address
timestamp INTEGER NOT NULL,
UNIQUE (hostname, address)
);
CREATE TABLE tls_spki (
host TEXT NOT NULL UNIQUE,
spki_hash TEXT NOT NULL, -- base64 of SPKI SHA-256 hash
timestamp INTEGER NOT NULL -- timestamp of the last time we have seen this key
) STRICT;
CREATE INDEX tls_spki_index_timestamp ON tls_spki (timestamp);
CREATE TABLE http_cache (
url TEXT PRIMARY KEY,
expires INTEGER NOT NULL, -- When the cache entry is considered expired, timestamp in seconds.
stale INTEGER NOT NULL, -- When the cache entry is considered stale, timestamp in seconds.
blobname TEXT NOT NULL,
mimetype TEXT NOT NULL DEFAULT '', -- MIME type extracted from Content-Type header.
encoding TEXT NOT NULL DEFAULT '' -- Encoding from Content-Type header.
) STRICT;
-- Webxdc updates.
CREATE TABLE msgs_status_updates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
msg_id INTEGER,
update_item TEXT DEFAULT '',
uid TEXT UNIQUE,
FOREIGN KEY(msg_id) REFERENCES msgs(id) ON DELETE CASCADE
);
CREATE INDEX msgs_status_updates_index1 ON msgs_status_updates (msg_id);
CREATE INDEX msgs_status_updates_index2 ON msgs_status_updates (uid);
-- Webxdc realtime.
CREATE TABLE iroh_gossip_peers (
msg_id INTEGER not NULL,
topic BLOB NOT NULL,
public_key BLOB NOT NULL,
relay_server TEXT, UNIQUE (topic, public_key),
PRIMARY KEY(topic, public_key)
) STRICT;
--
-- OpenPGP.
--
-- Storage for own private keys.
-- Only one of the keys is used.
--
-- In the past mulitple keys could be imported,
-- so this table can contain multiple keys for existing users.
-- Used key is identified by the "key_id" config value.
-- Other keys must never be used, even for decryption.
CREATE TABLE keypairs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- OpenPGP private key stored as a binary blob.
private_key UNIQUE NOT NULL,
-- Unused public key aka OpenPGP certificate.
-- Stored only for compatibility.
-- OpenPGP certificate is generated at runtime from the private key.
public_key UNIQUE NOT NULL,
--
-- Unused columns.
--
--
-- Columns "addr", "is_default" and "created" were
-- dropped in migration 107
-- but added back for compatibility in migration 110.
addr TEXT DEFAULT '' COLLATE NOCASE,
-- Migrated into "key_id" config value in migration 107.
is_default INTEGER DEFAULT 0,
created INTEGER DEFAULT 0
);
CREATE TABLE public_keys (
id INTEGER PRIMARY KEY AUTOINCREMENT,
fingerprint TEXT NOT NULL UNIQUE, -- Upper-case fingerprint of the key.
public_key BLOB NOT NULL -- Binary key, not ASCII-armored
) STRICT;
CREATE INDEX public_key_index ON public_keys (fingerprint);
CREATE TABLE gossip_timestamp (
chat_id INTEGER NOT NULL,
fingerprint TEXT NOT NULL, -- Upper-case fingerprint of the key.
timestamp INTEGER NOT NULL,
UNIQUE (chat_id, fingerprint)
) STRICT;
CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint);
-- Timestamps of distributing own key in the Autocrypt header of MDNs.
CREATE TABLE mdn_autocrypt_timestamp (
fingerprint TEXT PRIMARY KEY NOT NULL, -- Upper-case fingerprint of the recipient key.
attached_timestamp INTEGER NOT NULL
) STRICT;
-- Passwords used to derive symmetric keys for broadcast lists aka channels.
CREATE TABLE broadcast_secrets(
chat_id INTEGER PRIMARY KEY NOT NULL,
secret TEXT NOT NULL
) STRICT;
-- Candidate chatmail relays for automatic relay management.
CREATE TABLE relay_candidates(
host TEXT PRIMARY KEY NOT NULL,
last_tried INTEGER NOT NULL DEFAULT 0 -- Timestamp of the last connection attempt.
) STRICT;
CREATE TABLE transports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
-- Email address associated with this transport.
-- It uniquely identifies the transport.
addr TEXT NOT NULL,
-- JSON with the settings entered by the user.
-- The settings are not necessary entered manually,
-- but can be entered by scanning the QR code.
-- These settings are only used during the transport configuration process.
entered_param TEXT NOT NULL,
-- JSON with the settings used to connect to the transport.
-- These settings are derived from entered parameters
-- and possibly autoconfiguration XML fetched over HTTPS.
-- The settings stored here are known to have worked at least once,
-- this is ensured during configuration.
configured_param TEXT NOT NULL,
add_timestamp INTEGER NOT NULL DEFAULT 0,
-- True if the transport address is published
-- by sending it in the public key signature.
is_published INTEGER DEFAULT 1 NOT NULL,
-- Time when the transport was last used to receive a message.
-- Used to remove the least recently used transport
-- when a new transport is added and there are too many relays already.
last_rcvd_timestamp INTEGER NOT NULL DEFAULT 0,
UNIQUE(addr)
);
CREATE TABLE removed_transports (
addr TEXT NOT NULL,
remove_timestamp INTEGER NOT NULL,
UNIQUE(addr)
) STRICT;
CREATE TABLE imap (
id INTEGER PRIMARY KEY AUTOINCREMENT,
transport_id INTEGER NOT NULL, -- ID of the transport in the `transports` table.
rfc724_mid TEXT NOT NULL, -- Message-ID header
folder TEXT NOT NULL, -- IMAP folder
target TEXT NOT NULL, -- Destination folder. Empty string means that the message shall be deleted.
uid INTEGER NOT NULL, -- UID
uidvalidity INTEGER NOT NULL,
UNIQUE (transport_id, folder, uid, uidvalidity)
) STRICT;
CREATE INDEX imap_folder ON imap(transport_id, folder);
CREATE INDEX imap_rfc724_mid ON imap(transport_id, rfc724_mid);
CREATE INDEX imap_only_rfc724_mid ON imap(rfc724_mid);
CREATE TABLE imap_markseen (
id INTEGER PRIMARY KEY NOT NULL,
FOREIGN KEY(id) REFERENCES imap(id) ON DELETE CASCADE
);
CREATE TABLE imap_sync (
transport_id INTEGER NOT NULL, -- ID of the transport in the `transports` table.
folder TEXT NOT NULL,
uidvalidity INTEGER NOT NULL DEFAULT 0,
uid_next INTEGER NOT NULL DEFAULT 0,
modseq INTEGER NOT NULL DEFAULT 0,
UNIQUE (transport_id, folder)
) STRICT;
CREATE INDEX imap_sync_index ON imap_sync(transport_id, folder);
CREATE TABLE download (
rfc724_mid TEXT PRIMARY KEY,
msg_id INTEGER NOT NULL DEFAULT 0
) STRICT;
CREATE TABLE available_post_msgs (
rfc724_mid TEXT PRIMARY KEY
) STRICT;
--
-- Statistics.
--
CREATE TABLE stats_securejoin_sources(
source INTEGER PRIMARY KEY,
count INTEGER NOT NULL DEFAULT 0
) STRICT;
CREATE TABLE stats_securejoin_uipaths(
uipath INTEGER PRIMARY KEY,
count INTEGER NOT NULL DEFAULT 0
) STRICT;
CREATE TABLE stats_securejoin_invites(
already_existed INTEGER NOT NULL,
already_verified INTEGER NOT NULL,
type TEXT NOT NULL
) STRICT;
CREATE TABLE stats_msgs(
chattype INTEGER PRIMARY KEY,
verified INTEGER NOT NULL DEFAULT 0,
unverified_encrypted INTEGER NOT NULL DEFAULT 0,
unencrypted INTEGER NOT NULL DEFAULT 0,
only_to_self INTEGER NOT NULL DEFAULT 0,
last_counted_msg_id INTEGER NOT NULL DEFAULT 0
) STRICT;
CREATE TABLE stats_sending_enabled_events(timestamp INTEGER NOT NULL) STRICT;
CREATE TABLE stats_sending_disabled_events(timestamp INTEGER NOT NULL) STRICT;
-- Deprecated and unused tables.
--
-- We don't immediately drop unused tables,
-- because we want users to be able to downgrade.
-- Deprecated table for Autocrypt peer states.
-- It is replaced by the new "public_keys" table in migration 132
-- that introduced "key contacts" which have a fixed fingerprint.
CREATE TABLE acpeerstates (
id INTEGER PRIMARY KEY,
addr TEXT DEFAULT '' COLLATE NOCASE,
last_seen INTEGER DEFAULT 0,
last_seen_autocrypt INTEGER DEFAULT 0,
public_key,
prefer_encrypted INTEGER DEFAULT 0,
gossip_timestamp INTEGER DEFAULT 0,
gossip_key,
public_key_fingerprint TEXT DEFAULT '',
gossip_key_fingerprint TEXT DEFAULT '',
verified_key,
verified_key_fingerprint TEXT DEFAULT '',
verifier TEXT DEFAULT '',
secondary_verified_key,
secondary_verified_key_fingerprint TEXT DEFAULT '',
secondary_verifier TEXT DEFAULT '',
backward_verified_key_id -- What we think the contact has as our verified key
INTEGER,
UNIQUE (addr) -- Only one peerstate per address
);
CREATE INDEX acpeerstates_index1 ON acpeerstates (addr);
CREATE INDEX acpeerstates_index3 ON acpeerstates (public_key_fingerprint);
CREATE INDEX acpeerstates_index4 ON acpeerstates (gossip_key_fingerprint);
CREATE INDEX acpeerstates_index5 ON acpeerstates (verified_key_fingerprint);
-- Deprecated table previously used to upload sync messages using IMAP APPEND.
-- Sync messages are sent over SMTP now as they should be sent to multiple transports.
CREATE TABLE imap_send (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mime TEXT NOT NULL, -- Message content
msg_id INTEGER NOT NULL, -- ID of the message in the `msgs` table
attempts INTEGER NOT NULL DEFAULT 0 -- Number of failed attempts to send the message
);
-- Deprecated table used for a job system.
CREATE TABLE jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
added_timestamp INTEGER,
desired_timestamp INTEGER DEFAULT 0,
action INTEGER,
foreign_id INTEGER,
param TEXT DEFAULT '',
thread INTEGER DEFAULT 0,
tries INTEGER DEFAULT 0
);
CREATE INDEX jobs_index1 ON jobs (desired_timestamp);
-- Backup of the keypairs left after migration 107.
-- Not used by any code, it was only for a recovery
-- in case migration 107 goes wrong.
CREATE TABLE old_keypairs (
id INTEGER PRIMARY KEY,
addr TEXT DEFAULT '' COLLATE NOCASE,
is_default INTEGER DEFAULT 0,
private_key,
public_key,
created INTEGER DEFAULT 0
);
-- Unused table, previously introduced for AEAP mechanism
-- which is replaced by key contacts.
CREATE TABLE sending_domains(
domain TEXT PRIMARY KEY,
dkim_works INTEGER DEFAULT 0
);