e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen#ifndef MAIL_INDEX_H
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen#define MAIL_INDEX_H
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "file-lock.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fsync-mode.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "guid.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-types.h"
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen#include "seq-range-array.h"
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen#define MAIL_INDEX_MAJOR_VERSION 7
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MAIL_INDEX_MINOR_VERSION 3
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen#define MAIL_INDEX_HEADER_MIN_SIZE 120
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen/* Log a warning when transaction log has been locked for this many seconds.
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen This lock is held also between mail_index_sync_begin()..commit(). */
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen#define MAIL_TRANSACTION_LOG_LOCK_WARN_SECS 30
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenenum mail_index_open_flags {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Create index if it doesn't exist */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_OPEN_FLAG_CREATE = 0x01,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Don't try to mmap() index files */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE = 0x04,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Rely on O_EXCL when creating dotlocks */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL = 0x10,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Flush NFS attr/data/write cache when necessary */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_OPEN_FLAG_NFS_FLUSH = 0x40,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Open the index read-only */
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen MAIL_INDEX_OPEN_FLAG_READONLY = 0x80,
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen /* Create backups of dovecot.index files once in a while */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS = 0x100,
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* If we run out of disk space, fail modifications instead of moving
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen indexes to memory. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY = 0x200,
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen /* We're only going to save new messages to the index.
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen Avoid unnecessary reads. */
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen MAIL_INDEX_OPEN_FLAG_SAVEONLY = 0x400,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* Enable debug logging */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_OPEN_FLAG_DEBUG = 0x800,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* MAIL_INDEX_MAIL_FLAG_DIRTY can be used as a backend-specific flag.
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen All special handling of the flag is disabled by this. */
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen MAIL_INDEX_OPEN_FLAG_NO_DIRTY = 0x1000,
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen};
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainenenum mail_index_header_compat_flags {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen};
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenenum mail_index_header_flag {
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* Index file is corrupted, reopen or recreate it. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_HDR_FLAG_CORRUPTED = 0x0001,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_HDR_FLAG_HAVE_DIRTY = 0x0002,
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen /* Index has been fsck'd. The caller may want to resync the index
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen to make sure it's valid and drop this flag. */
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen MAIL_INDEX_HDR_FLAG_FSCKD = 0x0004,
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen};
fb2e0bbb7737f3223b16aa41e4b40fb0cd5f288fTimo Sirainen
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainenenum mail_index_mail_flags {
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen /* For private use by backend. Replacing flags doesn't change this. */
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen MAIL_INDEX_MAIL_FLAG_BACKEND = 0x40,
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen /* Message flags haven't been written to backend. If
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen MAIL_INDEX_OPEN_FLAG_NO_DIRTY is set, this is treated as a
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen backend-specific flag with no special internal handling. */
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY = 0x80,
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* Force updating this message's modseq via a flag update record */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen MAIL_INDEX_MAIL_FLAG_UPDATE_MODSEQ = 0x100
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen};
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen#define MAIL_INDEX_FLAGS_MASK \
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DELETED | MAIL_SEEN | MAIL_DRAFT)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstruct mail_index_header {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* major version is increased only when you can't have backwards
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen compatibility. minor version is increased when header size is
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen increased to contain new non-critical fields. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint8_t major_version;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint8_t minor_version;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint16_t base_header_size;
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen uint32_t header_size; /* base + extended header size */
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen uint32_t record_size;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen uint8_t compat_flags; /* enum mail_index_header_compat_flags */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen uint8_t unused[3];
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t indexid;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t flags;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t uid_validity;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t next_uid;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen uint32_t messages_count;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t unused_old_recent_messages_count;
e5759add4dc24b96606dccc4a989838e260f2a12Timo Sirainen uint32_t seen_messages_count;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t deleted_messages_count;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t first_recent_uid;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* these UIDs may not exist and may not even be unseen/deleted */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t first_unseen_uid_lowwater;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t first_deleted_uid_lowwater;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t log_file_seq;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* non-external records between tail..head haven't been committed to
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mailbox yet. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t log_file_tail_offset;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t log_file_head_offset;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t unused_old_sync_size_part1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Timestamp of when .log was rotated into .log.2. This can be used to
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen optimize checking when it's time to unlink it without stat()ing it.
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen 0 = unknown, -1 = .log.2 doesn't exists. */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen uint32_t log2_rotate_time;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t last_temp_file_scan;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* daily first UIDs that have been added to index. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t day_stamp;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t day_first_uid[8];
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen};
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen#define MAIL_INDEX_RECORD_MIN_SIZE (sizeof(uint32_t) + sizeof(uint8_t))
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstruct mail_index_record {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uint32_t uid;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen uint8_t flags; /* enum mail_flags | enum mail_index_mail_flags */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen};
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstruct mail_keywords {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mail_index *index;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen unsigned int count;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen int refcount;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* variable sized list of keyword indexes */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int idx[FLEXIBLE_ARRAY_MEMBER];
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen};
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenenum mail_index_transaction_flags {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* If transaction is marked as hidden, the changes are marked with
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hidden=TRUE when the view is synchronized. */
197ad81605dc0f6d2ebc9ad99994db5ca6d76699Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_HIDE = 0x01,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* External transactions describe changes to mailbox that have already
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen happened. */
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL = 0x02,
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen /* Don't add flag updates unless they actually change something.
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen This is reliable only when syncing, otherwise someone else might
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen have already committed a transaction that had changed the flags. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES = 0x04,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* fsync() this transaction (unless fsyncs are disabled) */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_FSYNC = 0x08,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Sync transaction describes changes to mailbox that already happened
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen to another mailbox with whom we're syncing with (dsync) */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_SYNC = 0x10
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen};
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenenum mail_index_sync_type {
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen MAIL_INDEX_SYNC_TYPE_EXPUNGE = 0x02,
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD = 0x08,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE = 0x10
d22301419109ed4a38351715e6760011421dadecTimo Sirainen};
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenenum mail_index_fsync_mask {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_FSYNC_MASK_APPENDS = 0x01,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_FSYNC_MASK_EXPUNGES = 0x02,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_FSYNC_MASK_FLAGS = 0x04,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_FSYNC_MASK_KEYWORDS = 0x08
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen};
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenenum mail_index_sync_flags {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Resync all dirty messages' flags. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY = 0x01,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Drop recent flags from all messages */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_FLAG_DROP_RECENT = 0x02,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Create the transaction with AVOID_FLAG_UPDATES flag */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES = 0x04,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* If there are no new transactions and nothing else to do,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return 0 in mail_index_sync_begin() */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES = 0x08,
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen /* Create the transaction with FSYNC flag */
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen MAIL_INDEX_SYNC_FLAG_FSYNC = 0x10,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* If we see "delete index" request transaction, finish it.
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen This flag also allows committing more changes to a deleted index. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_FLAG_DELETING_INDEX = 0x20,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Same as MAIL_INDEX_SYNC_FLAG_DELETING_INDEX, but finish index
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen deletion only once and fail the rest (= avoid race conditions when
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen multiple processes try to mark the index deleted) */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX = 0x40,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Update header's tail_offset to head_offset, even if it's the only
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen thing we do and there's no strict need for it. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_SYNC_FLAG_UPDATE_TAIL_OFFSET = 0x80
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenenum mail_index_view_sync_flags {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Don't sync expunges */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES = 0x01,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Make sure view isn't inconsistent after syncing. This also means
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen that you don't care about view_sync_next()'s output, so it won't
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen return anything. */
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT = 0x02
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen};
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainenstruct mail_index_sync_rec {
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen uint32_t uid1, uid2;
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen enum mail_index_sync_type type;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* MAIL_INDEX_SYNC_TYPE_FLAGS: */
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen uint8_t add_flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint8_t remove_flags;
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen /* MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD, .._REMOVE: */
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen unsigned int keyword_idx;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* MAIL_INDEX_SYNC_TYPE_EXPUNGE: */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen guid_128_t guid_128;
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen};
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenenum mail_index_view_sync_type {
58eb2cb24dbeadd94500670acad7ceb1c8b0d9b4Timo Sirainen /* Flags or keywords changed */
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen MAIL_INDEX_VIEW_SYNC_TYPE_FLAGS = 0x01,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen MAIL_INDEX_VIEW_SYNC_TYPE_MODSEQ = 0x02
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_index_view_sync_rec {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t uid1, uid2;
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen enum mail_index_view_sync_type type;
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* TRUE if this was a hidden transaction. */
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen bool hidden:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenenum mail_index_transaction_change {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_APPEND = BIT(0),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_EXPUNGE = BIT(1),
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_FLAGS = BIT(2),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_KEYWORDS = BIT(3),
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_MODSEQ = BIT(4),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_ATTRIBUTE = BIT(5),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_INDEX_TRANSACTION_CHANGE_OTHERS = BIT(30),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstruct mail_index_transaction_commit_result {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* seq/offset points to end of transaction */
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen uint32_t log_file_seq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t log_file_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* number of bytes in the written transaction.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen all of it was written to the same file. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t commit_size;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen enum mail_index_transaction_change changes_mask;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen unsigned int ignored_modseq_changes;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen};
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_index_base_optimization_settings {
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen /* Rewrite the index when the number of bytes that needs to be read
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen from the .log on refresh is between these min/max values. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uoff_t rewrite_min_log_bytes;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t rewrite_max_log_bytes;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainenstruct mail_index_log_optimization_settings {
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen /* Rotate transaction log after it's a) min_size or larger and it was
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen created at least min_age_secs or b) larger than max_size. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uoff_t min_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t max_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int min_age_secs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Delete .log.2 when it's older than log2_stale_secs. Don't be too
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen eager, because older files are useful for QRESYNC and dsync. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int log2_max_age_secs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_index_cache_optimization_settings {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Drop fields that haven't been accessed for n seconds */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int unaccessed_field_drop_secs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* If cache record becomes larger than this, don't add it. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int record_max_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Never compress the file if it's smaller than this */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen uoff_t compress_min_size;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Compress the file when n% of records are deleted */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen unsigned int compress_delete_percentage;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Compress the file when n% of rows contain continued rows.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen For example 200% means that the record has 2 continued rows, i.e.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it exists in 3 separate segments in the cache file. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int compress_continued_percentage;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Compress the file when we need to follow more than n next_offsets to
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen find the latest cache header. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen unsigned int compress_header_continue_count;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_index_optimization_settings {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct mail_index_base_optimization_settings index;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct mail_index_log_optimization_settings log;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct mail_index_cache_optimization_settings cache;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen};
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstruct mail_index;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstruct mail_index_map;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstruct mail_index_view;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstruct mail_index_transaction;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainenstruct mail_index_sync_ctx;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainenstruct mail_index_view_sync_ctx;
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainenstruct mail_index *mail_index_alloc(struct event *parent_event,
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen const char *dir, const char *prefix);
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainenvoid mail_index_free(struct mail_index **index);
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen/* Change .cache file's directory. */
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainenvoid mail_index_set_cache_dir(struct mail_index *index, const char *dir);
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen/* Specify how often to do fsyncs. If mode is FSYNC_MODE_OPTIMIZED, the mask
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainen can be used to specify which transaction types to fsync. */
92139717fd109c34692670df54d157d8c4df9b71Timo Sirainenvoid mail_index_set_fsync_mode(struct mail_index *index, enum fsync_mode mode,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen enum mail_index_fsync_mask mask);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* Try to set the index's permissions based on its index directory. Returns
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen TRUE if successful (directory existed), FALSE if mail_index_set_permissions()
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen should be called. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenbool mail_index_use_existing_permissions(struct mail_index *index);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mode_t mode, gid_t gid, const char *gid_origin);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* Set locking method and maximum time to wait for a lock
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (UINT_MAX = default). */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid mail_index_set_lock_method(struct mail_index *index,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen enum file_lock_method lock_method,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int max_timeout_secs);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* Override the default optimization-related settings. Anything set to 0 will
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen use the default. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid mail_index_set_optimization_settings(struct mail_index *index,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const struct mail_index_optimization_settings *set);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* When creating a new index file or reseting an existing one, add the given
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen extension header data immediately to it. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid mail_index_set_ext_init_data(struct mail_index *index, uint32_t ext_id,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const void *data, size_t size);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* Open index. Returns 1 if ok, 0 if index doesn't exist and CREATE flags
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen wasn't given, -1 if error. */
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainenint mail_index_open(struct mail_index *index, enum mail_index_open_flags flags);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* Open or create index. Returns 0 if ok, -1 if error. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenint mail_index_open_or_create(struct mail_index *index,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen enum mail_index_open_flags flags);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenvoid mail_index_close(struct mail_index *index);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen/* unlink() all the index files. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenint mail_index_unlink(struct mail_index *index);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen/* Returns TRUE if index is currently in memory. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenbool mail_index_is_in_memory(struct mail_index *index);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen/* Move the index into memory. Returns 0 if ok, -1 if error occurred. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenint mail_index_move_to_memory(struct mail_index *index);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstruct mail_cache *mail_index_get_cache(struct mail_index *index);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen/* Refresh index so mail_index_lookup*() will return latest values. Note that
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen immediately after this call there may already be changes, so if you need to
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen rely on validity of the returned values, use some external locking for it. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenint ATTR_NOWARN_UNUSED_RESULT
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenmail_index_refresh(struct mail_index *index);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen/* View can be used to look into index. Sequence numbers inside view change
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen only when you synchronize it. The view acquires required locks
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen automatically, but you'll have to drop them manually. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstruct mail_index_view *
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenmail_index_view_open(struct mail_index *index,
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainen const char *source_filename, unsigned int source_linenum);
51ff0538ab38def8045b3f7feb43e1e069cbe037Timo Sirainen#define mail_index_view_open(index) \
58eb2cb24dbeadd94500670acad7ceb1c8b0d9b4Timo Sirainen mail_index_view_open(index, __FILE__, __LINE__)
bf301a34ffbfd049be583094019b2644884b6d0bTimo Sirainenvoid mail_index_view_close(struct mail_index_view **view);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
2054222e84cb972842cc4de88e16516bef41b542Timo Sirainen/* Returns the index for given view. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstruct mail_index *mail_index_view_get_index(struct mail_index_view *view);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen/* Returns number of mails in view. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenuint32_t mail_index_view_get_messages_count(struct mail_index_view *view);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen/* Returns TRUE if we lost track of changes for some reason. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenbool mail_index_view_is_inconsistent(struct mail_index_view *view);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen/* Returns number of transactions open for the view. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenunsigned int
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenmail_index_view_get_transaction_count(struct mail_index_view *view);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen/* Transaction has to be opened to be able to modify index. You can have
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen multiple transactions open simultaneously. Committed transactions won't
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen show up until you've synchronized the view. Expunges won't show up until
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen you've synchronized the mailbox (mail_index_sync_begin). */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenstruct mail_index_transaction *
a60c1c1fca85402e6fccbf3ae0784b7179ae186cTimo Sirainenmail_index_transaction_begin(struct mail_index_view *view,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen enum mail_index_transaction_flags flags);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_transaction_commit(struct mail_index_transaction **t);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_transaction_commit_full(struct mail_index_transaction **t,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct mail_index_transaction_commit_result *result_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction **t);
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen/* Discard all changes in the transaction. */
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainenvoid mail_index_transaction_reset(struct mail_index_transaction *t);
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen/* When committing transaction, drop flag/keyword updates for messages whose
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mdoseq is larger than max_modseq. Save those messages' sequences to the
08fa343b3aace9343da3195686c65c5326eda207Timo Sirainen given array. */
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainenvoid mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen uint64_t max_modseq,
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen ARRAY_TYPE(seq_range) *seqs);
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen/* Returns the resulting highest-modseq after this commit. This can be called
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen only if transaction log is locked, which normally means only during mail
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen index syncing. If there are any appends, they all must have been assigned
1cd97699af9c77d8f5920832ec3374884544fd68Timo Sirainen UIDs before calling this. */
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainenuint64_t mail_index_transaction_get_highest_modseq(struct mail_index_transaction *t);
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Returns the view transaction was created for. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstruct mail_index_view *
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenmail_index_transaction_get_view(struct mail_index_transaction *t);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen/* Returns TRUE if the given sequence is being expunged in this transaction. */
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenbool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen uint32_t seq);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen/* Returns a view containing the mailbox state after changes in transaction
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen are applied. The view can still be used after transaction has been
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen committed. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstruct mail_index_view *
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenmail_index_transaction_open_updated_view(struct mail_index_transaction *t);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen/* Begin synchronizing mailbox with index file. Returns 1 if ok,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen 0 if MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES is set and there's nothing to
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen sync, -1 if error.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen mail_index_sync_next() returns all changes from previously committed
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen transactions which haven't yet been committed to the actual mailbox.
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen They're returned in ascending order and they never overlap (if we add more
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen sync types, then they might). You must go through all of them and update
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen the mailbox accordingly.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen Changes done to the returned transaction are expected to describe the
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mailbox's current state.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen The returned view already contains all the changes (except expunge
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen requests). After applying sync records on top of backend flags they should
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen match flags in the view. If they don't, there have been external changes.
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen Returned expunges are treated as expunge requests. They're not really
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen removed from the index until you mark them expunged to the returned
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen transaction. If it's not possible to expunge the message (e.g. permission
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen denied), simply don't mark them expunged.
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen Returned sequence numbers describe the mailbox state at the beginning of
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen synchronization, ie. expunges don't affect them. */
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainenint mail_index_sync_begin(struct mail_index *index,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_sync_ctx **ctx_r,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_view **view_r,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_transaction **trans_r,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen enum mail_index_sync_flags flags);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen/* Like mail_index_sync_begin(), but returns 1 if OK and if index is already
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen synchronized up to the given log_file_seq+offset, the synchronization isn't
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen started and this function returns 0. This should be done when you wish to
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync your committed transaction instead of doing a full mailbox
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen synchronization. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenint mail_index_sync_begin_to(struct mail_index *index,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_sync_ctx **ctx_r,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_view **view_r,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct mail_index_transaction **trans_r,
dc52b16795b56589923ff586e5cdd0c0f1fd5931Timo Sirainen uint32_t log_file_seq, uoff_t log_file_offset,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen enum mail_index_sync_flags flags);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen/* Returns TRUE if it currently looks like syncing would return changes. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenbool mail_index_sync_have_any(struct mail_index *index,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen enum mail_index_sync_flags flags);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen/* Returns TRUE if it currently looks like syncing would return expunges. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenbool mail_index_sync_have_any_expunges(struct mail_index *index);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen/* Returns the log file seq+offsets for the area which this sync is handling. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenvoid mail_index_sync_get_offsets(struct mail_index_sync_ctx *ctx,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen uint32_t *seq1_r, uoff_t *offset1_r,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen uint32_t *seq2_r, uoff_t *offset2_r);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen/* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenbool mail_index_sync_next(struct mail_index_sync_ctx *ctx,
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct mail_index_sync_rec *sync_rec);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen/* Returns TRUE if there's more to sync. */
bool mail_index_sync_have_more(struct mail_index_sync_ctx *ctx);
/* Returns TRUE if sync has any expunges to handle. */
bool mail_index_sync_has_expunges(struct mail_index_sync_ctx *ctx);
/* Reset syncing to initial state after mail_index_sync_begin(), so you can
go through all the sync records again with mail_index_sync_next(). */
void mail_index_sync_reset(struct mail_index_sync_ctx *ctx);
/* Update result when refreshing index at the end of sync. */
void mail_index_sync_set_commit_result(struct mail_index_sync_ctx *ctx,
struct mail_index_transaction_commit_result *result);
/* Don't log a warning even if syncing took over
MAIL_TRANSACTION_LOG_LOCK_WARN_SECS seconds. Usually this is called because
the caller itself already logged a warning about it. */
void mail_index_sync_no_warning(struct mail_index_sync_ctx *ctx);
/* If a warning is logged because syncing took over
MAIL_TRANSACTION_LOG_LOCK_WARN_SECS seconds, log this as the reason for the
syncing. */
void mail_index_sync_set_reason(struct mail_index_sync_ctx *ctx,
const char *reason);
/* Commit synchronization by writing all changes to mail index file. */
int mail_index_sync_commit(struct mail_index_sync_ctx **ctx);
/* Rollback synchronization - none of the changes listed by sync_next() are
actually written to index file. */
void mail_index_sync_rollback(struct mail_index_sync_ctx **ctx);
/* Mark index file corrupted. Invalidates all views. */
void mail_index_mark_corrupted(struct mail_index *index);
/* Check and fix any found problems. Returns -1 if we couldn't lock for sync,
0 if everything went ok. */
int mail_index_fsck(struct mail_index *index);
/* Returns TRUE if mail_index_fsck() has been called since the last
mail_index_reset_fscked() call. */
bool mail_index_reset_fscked(struct mail_index *index);
/* Synchronize changes in view. You have to go through all records, or view
will be marked inconsistent. Only sync_mask type records are
synchronized. */
struct mail_index_view_sync_ctx *
mail_index_view_sync_begin(struct mail_index_view *view,
enum mail_index_view_sync_flags flags);
bool mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
struct mail_index_view_sync_rec *sync_rec);
void
mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
const ARRAY_TYPE(seq_range) **expunges_r);
int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **ctx,
bool *delayed_expunges_r);
/* Returns the index header. */
const struct mail_index_header *
mail_index_get_header(struct mail_index_view *view);
/* Returns the wanted message record. */
const struct mail_index_record *
mail_index_lookup(struct mail_index_view *view, uint32_t seq);
const struct mail_index_record *
mail_index_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r);
/* Returns TRUE if the given message has already been expunged from index. */
bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq);
/* Note that returned keyword indexes aren't sorted. */
void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
ARRAY_TYPE(keyword_indexes) *keyword_idx);
/* Return keywords from given map. */
void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq,
ARRAY_TYPE(keyword_indexes) *keyword_idx);
/* mail_index_lookup[_keywords]() returns the latest flag changes.
This function instead attempts to return the flags and keywords done by the
last view sync. */
void mail_index_lookup_view_flags(struct mail_index_view *view, uint32_t seq,
enum mail_flags *flags_r,
ARRAY_TYPE(keyword_indexes) *keyword_idx);
/* Returns the UID for given message. May be slightly faster than
mail_index_lookup()->uid. */
void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
uint32_t *uid_r);
/* Convert UID range to sequence range. If no UIDs are found, returns FALSE and
sequences are set to 0. Note that any of the returned sequences may have
been expunged already. */
bool mail_index_lookup_seq_range(struct mail_index_view *view,
uint32_t first_uid, uint32_t last_uid,
uint32_t *first_seq_r, uint32_t *last_seq_r);
bool mail_index_lookup_seq(struct mail_index_view *view,
uint32_t uid, uint32_t *seq_r);
/* Find first mail with (mail->flags & flags_mask) == flags. Useful mostly for
taking advantage of lowwater-fields in headers. */
void mail_index_lookup_first(struct mail_index_view *view,
enum mail_flags flags, uint8_t flags_mask,
uint32_t *seq_r);
/* Append a new record to index. */
void mail_index_append(struct mail_index_transaction *t, uint32_t uid,
uint32_t *seq_r);
/* Assign UIDs for mails with uid=0 or uid<first_uid. All the assigned UIDs
are higher than the highest unassigned UID (i.e. it doesn't try to fill UID
gaps). Assumes that mailbox is locked in a way that UIDs can be safely
assigned. Returns UIDs for all assigned messages, in their sequence order
(so UIDs are not necessary ascending). */
void mail_index_append_finish_uids(struct mail_index_transaction *t,
uint32_t first_uid,
ARRAY_TYPE(seq_range) *uids_r);
/* Expunge record from index. Note that this doesn't affect sequence numbers
until transaction is committed and mailbox is synced. */
void mail_index_expunge(struct mail_index_transaction *t, uint32_t seq);
/* Like mail_index_expunge(), but also write message GUID to transaction log. */
void mail_index_expunge_guid(struct mail_index_transaction *t, uint32_t seq,
const guid_128_t guid_128);
/* Revert all changes done in this transaction to the given existing mail. */
void mail_index_revert_changes(struct mail_index_transaction *t, uint32_t seq);
/* Update flags in index. */
void mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
enum mail_flags flags);
void mail_index_update_flags_range(struct mail_index_transaction *t,
uint32_t seq1, uint32_t seq2,
enum modify_type modify_type,
enum mail_flags flags);
/* Specified attribute's value was changed. This is just a notification so the
change gets assigned its own modseq and any log readers can find out about
this change. */
void mail_index_attribute_set(struct mail_index_transaction *t,
bool pvt, const char *key,
time_t timestamp, uint32_t value_len);
/* Attribute was deleted. */
void mail_index_attribute_unset(struct mail_index_transaction *t,
bool pvt, const char *key, time_t timestamp);
/* Update message's modseq to be at least min_modseq. */
void mail_index_update_modseq(struct mail_index_transaction *t, uint32_t seq,
uint64_t min_modseq);
/* Update highest modseq to be at least min_modseq. */
void mail_index_update_highest_modseq(struct mail_index_transaction *t,
uint64_t min_modseq);
/* Reset the index before committing this transaction. This is usually done
only when UIDVALIDITY changes. */
void mail_index_reset(struct mail_index_transaction *t);
/* Remove MAIL_INDEX_HDR_FLAG_FSCKD from header if it exists. This must be
called only during syncing so that the mailbox is locked. */
void mail_index_unset_fscked(struct mail_index_transaction *t);
/* Mark index deleted. No further changes will be possible after the
transaction has been committed. */
void mail_index_set_deleted(struct mail_index_transaction *t);
/* Mark a deleted index as undeleted. Afterwards index can be changed again. */
void mail_index_set_undeleted(struct mail_index_transaction *t);
/* Returns TRUE if index has been set deleted. This gets set only after
index has been opened/refreshed and the transaction has been seen. */
bool mail_index_is_deleted(struct mail_index *index);
/* Returns the last time the index was modified. This can be called even if the
index isn't open. If the index doesn't exist, sets mtime to 0. */
int mail_index_get_modification_time(struct mail_index *index, time_t *mtime_r);
/* Lookup a keyword, returns TRUE if found, FALSE if not. */
bool mail_index_keyword_lookup(struct mail_index *index,
const char *keyword, unsigned int *idx_r);
void mail_index_keyword_lookup_or_create(struct mail_index *index,
const char *keyword,
unsigned int *idx_r);
/* Return a pointer to array of NULL-terminated list of keywords. Note that
the array contents (and thus pointers inside it) may change after calling
mail_index_keywords_create() or mail_index_sync_begin(). */
const ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index);
/* Create a keyword list structure. */
struct mail_keywords *
mail_index_keywords_create(struct mail_index *index,
const char *const keywords[]) ATTR_NULL(2);
struct mail_keywords *
mail_index_keywords_create_from_indexes(struct mail_index *index,
const ARRAY_TYPE(keyword_indexes)
*keyword_indexes);
void mail_index_keywords_ref(struct mail_keywords *keywords);
void mail_index_keywords_unref(struct mail_keywords **keywords);
/* Update keywords for given message. */
void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
struct mail_keywords *keywords);
/* Update field in header. If prepend is TRUE, the header change is visible
before message syncing begins. */
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size,
bool prepend);
/* Returns the full error message for last error. This message may
contain paths etc. so it shouldn't be shown to users. */
const char *mail_index_get_error_message(struct mail_index *index);
/* Reset the error message. */
void mail_index_reset_error(struct mail_index *index);
/* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given
flags variable. */
void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
uint8_t *flags);
/* Apply changes in MAIL_INDEX_SYNC_TYPE_KEYWORD_* typed sync records to given
keywords array. Returns TRUE If something was changed. */
bool mail_index_sync_keywords_apply(const struct mail_index_sync_rec *sync_rec,
ARRAY_TYPE(keyword_indexes) *keywords);
/* register index extension. name is a unique identifier for the extension.
returns unique identifier for the name. */
uint32_t mail_index_ext_register(struct mail_index *index, const char *name,
uint32_t default_hdr_size,
uint16_t default_record_size,
uint16_t default_record_align);
/* Change an already registered extension's default sizes. */
void mail_index_ext_register_resize_defaults(struct mail_index *index,
uint32_t ext_id,
uint32_t default_hdr_size,
uint16_t default_record_size,
uint16_t default_record_align);
/* Returns TRUE and sets ext_id_r if extension with given name is registered. */
bool mail_index_ext_lookup(struct mail_index *index, const char *name,
uint32_t *ext_id_r);
/* Resize existing extension data. If size is grown, the new data will be
zero-filled. If size is shrinked, the data is simply dropped. */
void mail_index_ext_resize(struct mail_index_transaction *t, uint32_t ext_id,
uint32_t hdr_size, uint16_t record_size,
uint16_t record_align);
/* Resize header, keeping the old record size. */
void mail_index_ext_resize_hdr(struct mail_index_transaction *t,
uint32_t ext_id, uint32_t hdr_size);
/* Reset extension. Any updates for this extension which were issued before the
writer had seen this reset are discarded. reset_id is used to figure this
out, so it must be different every time. If clear_data=TRUE, records and
header is zeroed. */
void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
uint32_t reset_id, bool clear_data);
/* Like mail_index_ext_reset(), but increase extension's reset_id atomically
when the transaction is being committed. If prev_reset_id doesn't match the
latest reset_id, the reset_id isn't increased and all extension changes are
ignored. */
void mail_index_ext_reset_inc(struct mail_index_transaction *t, uint32_t ext_id,
uint32_t prev_reset_id, bool clear_data);
/* Discard existing extension updates in this transaction and write new updates
using the given reset_id. The difference to mail_index_ext_reset() is that
this doesn't clear any existing record or header data. */
void mail_index_ext_set_reset_id(struct mail_index_transaction *t,
uint32_t ext_id, uint32_t reset_id);
/* Get the current reset_id for given extension. Returns TRUE if it exists. */
bool mail_index_ext_get_reset_id(struct mail_index_view *view,
struct mail_index_map *map,
uint32_t ext_id, uint32_t *reset_id_r);
/* Returns extension header. */
void mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id,
const void **data_r, size_t *data_size_r);
void mail_index_map_get_header_ext(struct mail_index_view *view,
struct mail_index_map *map, uint32_t ext_id,
const void **data_r, size_t *data_size_r);
/* Returns the wanted extension record for given message. If it doesn't exist,
*data_r is set to NULL. expunged_r is TRUE if the message has already been
expunged from the index. */
void mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, const void **data_r,
bool *expunged_r);
void mail_index_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, struct mail_index_map **map_r,
const void **data_r, bool *expunged_r);
/* Get current extension sizes. Returns 1 if ok, 0 if extension doesn't exist
in view. Any of the _r parameters may be NULL. */
void mail_index_ext_get_size(struct mail_index_map *map, uint32_t ext_id,
uint32_t *hdr_size_r, uint16_t *record_size_r,
uint16_t *record_align_r);
/* Update extension header field. */
void mail_index_update_header_ext(struct mail_index_transaction *t,
uint32_t ext_id, size_t offset,
const void *data, size_t size);
/* Update extension record. If old_data_r is non-NULL and the record extension
was already updated in this transaction, it's set to contain the data it's
now overwriting. */
void mail_index_update_ext(struct mail_index_transaction *t, uint32_t seq,
uint32_t ext_id, const void *data, void *old_data)
ATTR_NULL(5);
/* Increase/decrease number in extension atomically. Returns the sum of the
diffs for this seq. */
int mail_index_atomic_inc_ext(struct mail_index_transaction *t,
uint32_t seq, uint32_t ext_id, int diff);
#endif