mail-index.h revision 5bced341c27719fe5ec48e1cd079843f33c6d4b5
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#ifndef MAIL_INDEX_H
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAIL_INDEX_H
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "file-lock.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "fsync-mode.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "guid.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "mail-types.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "seq-range-array.h"
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen#define MAIL_INDEX_MAJOR_VERSION 7
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#define MAIL_INDEX_MINOR_VERSION 3
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#define MAIL_INDEX_HEADER_MIN_SIZE 120
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen/* Log a warning when transaction log has been locked for this many seconds.
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen This lock is held also between mail_index_sync_begin()..commit(). */
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#define MAIL_TRANSACTION_LOG_LOCK_WARN_SECS 30
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainenenum mail_index_open_flags {
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen /* Create index if it doesn't exist */
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen MAIL_INDEX_OPEN_FLAG_CREATE = 0x01,
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen /* Don't try to mmap() index files */
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE = 0x04,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen /* Rely on O_EXCL when creating dotlocks */
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL = 0x10,
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen /* Flush NFS attr/data/write cache when necessary */
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen MAIL_INDEX_OPEN_FLAG_NFS_FLUSH = 0x40,
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen /* Open the index read-only */
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen MAIL_INDEX_OPEN_FLAG_READONLY = 0x80,
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* Create backups of dovecot.index files once in a while */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS = 0x100,
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* If we run out of disk space, fail modifications instead of moving
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen indexes to memory. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY = 0x200,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* We're only going to save new messages to the index.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Avoid unnecessary reads. */
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi MAIL_INDEX_OPEN_FLAG_SAVEONLY = 0x400
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenenum mail_index_header_compat_flags {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen};
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenenum mail_index_header_flag {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* Index file is corrupted, reopen or recreate it. */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MAIL_INDEX_HDR_FLAG_CORRUPTED = 0x0001,
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MAIL_INDEX_HDR_FLAG_HAVE_DIRTY = 0x0002
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen};
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenenum mail_index_mail_flags {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* For private use by backend. Replacing flags doesn't change this. */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MAIL_INDEX_MAIL_FLAG_BACKEND = 0x40,
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* Message flags haven't been written to backend */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY = 0x80,
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* Force updating this message's modseq via a flag update record */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MAIL_INDEX_MAIL_FLAG_UPDATE_MODSEQ = 0x100
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen};
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen#define MAIL_INDEX_FLAGS_MASK \
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DELETED | MAIL_SEEN | MAIL_DRAFT)
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenstruct mail_index_header {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* major version is increased only when you can't have backwards
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen compatibility. minor version is increased when header size is
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen increased to contain new non-critical fields. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint8_t major_version;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint8_t minor_version;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint16_t base_header_size;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t header_size; /* base + extended header size */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t record_size;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint8_t compat_flags; /* enum mail_index_header_compat_flags */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint8_t unused[3];
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi uint32_t indexid;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t flags;
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen uint32_t uid_validity;
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen uint32_t next_uid;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t messages_count;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t unused_old_recent_messages_count;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t seen_messages_count;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t deleted_messages_count;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t first_recent_uid;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* these UIDs may not exist and may not even be unseen/deleted */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t first_unseen_uid_lowwater;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t first_deleted_uid_lowwater;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t log_file_seq;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* non-external records between tail..head haven't been committed to
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen mailbox yet. */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen uint32_t log_file_tail_offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t log_file_head_offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint64_t unused_old_sync_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t unused_old_sync_stamp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
009217abb57a24a4076092e8e4e165545747839eStephan Bosch /* daily first UIDs that have been added to index. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t day_stamp;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch uint32_t day_first_uid[8];
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstruct mail_index_record {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen uint32_t uid;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen uint8_t flags; /* enum mail_flags | enum mail_index_mail_flags */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct mail_keywords {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct mail_index *index;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen unsigned int count;
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen int refcount;
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* variable sized list of keyword indexes */
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen unsigned int idx[1];
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen};
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainenenum mail_index_transaction_flags {
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen /* If transaction is marked as hidden, the changes are marked with
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen hidden=TRUE when the view is synchronized. */
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_HIDE = 0x01,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* External transactions describe changes to mailbox that have already
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen happened. */
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL = 0x02,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Don't add flag updates unless they actually change something.
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen This is reliable only when syncing, otherwise someone else might
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen have already committed a transaction that had changed the flags. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES = 0x04,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* fsync() this transaction (unless fsyncs are disabled) */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_TRANSACTION_FLAG_FSYNC = 0x08,
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen /* Sync transaction describes changes to mailbox that already happened
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen to another mailbox with whom we're syncing with (dsync) */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_TRANSACTION_FLAG_SYNC = 0x10
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainenenum mail_index_sync_type {
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen MAIL_INDEX_SYNC_TYPE_EXPUNGE = 0x02,
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD = 0x08,
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE = 0x10
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainenenum mail_index_fsync_mask {
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen MAIL_INDEX_FSYNC_MASK_APPENDS = 0x01,
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen MAIL_INDEX_FSYNC_MASK_EXPUNGES = 0x02,
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen MAIL_INDEX_FSYNC_MASK_FLAGS = 0x04,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_FSYNC_MASK_KEYWORDS = 0x08
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenenum mail_index_sync_flags {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* Resync all dirty messages' flags. */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY = 0x01,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* Drop recent flags from all messages */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_SYNC_FLAG_DROP_RECENT = 0x02,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Create the transaction with AVOID_FLAG_UPDATES flag */
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES = 0x04,
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen /* If there are no new transactions and nothing else to do,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return 0 in mail_index_sync_begin() */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES = 0x08,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Create the transaction with FSYNC flag */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_SYNC_FLAG_FSYNC = 0x10,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* If we see "delete index" request transaction, finish it.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen This flag also allows committing more changes to a deleted index. */
009217abb57a24a4076092e8e4e165545747839eStephan Bosch MAIL_INDEX_SYNC_FLAG_DELETING_INDEX = 0x20,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Same as MAIL_INDEX_SYNC_FLAG_DELETING_INDEX, but finish index
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen deletion only once and fail the rest (= avoid race conditions when
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen multiple processes try to mark the index deleted) */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX = 0x40,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Update header's tail_offset to head_offset, even if it's the only
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen thing we do and there's no strict need for it. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_SYNC_FLAG_UPDATE_TAIL_OFFSET = 0x80
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen};
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainenenum mail_index_view_sync_flags {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Don't sync expunges */
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES = 0x01,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen /* Make sure view isn't inconsistent after syncing. This also means
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen that you don't care about view_sync_next()'s output, so it won't
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen return anything. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT = 0x02
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen};
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstruct mail_index_sync_rec {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen uint32_t uid1, uid2;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen enum mail_index_sync_type type;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* MAIL_INDEX_SYNC_TYPE_FLAGS: */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen uint8_t add_flags;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen uint8_t remove_flags;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD, .._REMOVE: */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen unsigned int keyword_idx;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* MAIL_INDEX_SYNC_TYPE_EXPUNGE: */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen guid_128_t guid_128;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenenum mail_index_view_sync_type {
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen /* Flags or keywords changed */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen MAIL_INDEX_VIEW_SYNC_TYPE_FLAGS = 0x01,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen MAIL_INDEX_VIEW_SYNC_TYPE_MODSEQ = 0x02
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen};
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstruct mail_index_view_sync_rec {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen uint32_t uid1, uid2;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen enum mail_index_view_sync_type type;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen /* TRUE if this was a hidden transaction. */
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen unsigned int hidden:1;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen};
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainenstruct mail_index_transaction_commit_result {
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen /* seq/offset points to end of transaction */
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen uint32_t log_file_seq;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen uoff_t log_file_offset;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen /* number of bytes in the written transaction.
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen all of it was written to the same file. */
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen uoff_t commit_size;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int ignored_modseq_changes;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen};
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenstruct mail_index;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct mail_index_map;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct mail_index_view;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct mail_index_transaction;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct mail_index_sync_ctx;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct mail_index_view_sync_ctx;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct mail_index *mail_index_alloc(const char *dir, const char *prefix);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid mail_index_free(struct mail_index **index);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen/* Specify how often to do fsyncs. If mode is FSYNC_MODE_OPTIMIZED, the mask
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen can be used to specify which transaction types to fsync. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_index_set_fsync_mode(struct mail_index *index, enum fsync_mode mode,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen enum mail_index_fsync_mask mask);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_index_set_permissions(struct mail_index *index,
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen mode_t mode, gid_t gid, const char *gid_origin);
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen/* Set locking method and maximum time to wait for a lock
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen (UINT_MAX = default). */
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainenvoid mail_index_set_lock_method(struct mail_index *index,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen enum file_lock_method lock_method,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen unsigned int max_timeout_secs);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen/* When creating a new index file or reseting an existing one, add the given
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen extension header data immediately to it. */
1df39b899804fd1dbc560f75382364822935c857Timo Sirainenvoid mail_index_set_ext_init_data(struct mail_index *index, uint32_t ext_id,
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen const void *data, size_t size);
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen/* Open index. Returns 1 if ok, 0 if index doesn't exist and CREATE flags
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen wasn't given, -1 if error. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint mail_index_open(struct mail_index *index, enum mail_index_open_flags flags);
/* Open or create index. Returns 0 if ok, -1 if error. */
int mail_index_open_or_create(struct mail_index *index,
enum mail_index_open_flags flags);
void mail_index_close(struct mail_index *index);
/* unlink() all the index files. */
int mail_index_unlink(struct mail_index *index);
/* Returns TRUE if index is currently in memory. */
bool mail_index_is_in_memory(struct mail_index *index);
/* Move the index into memory. Returns 0 if ok, -1 if error occurred. */
int mail_index_move_to_memory(struct mail_index *index);
struct mail_cache *mail_index_get_cache(struct mail_index *index);
/* Refresh index so mail_index_lookup*() will return latest values. Note that
immediately after this call there may already be changes, so if you need to
rely on validity of the returned values, use some external locking for it. */
int ATTR_NOWARN_UNUSED_RESULT
mail_index_refresh(struct mail_index *index);
/* View can be used to look into index. Sequence numbers inside view change
only when you synchronize it. The view acquires required locks
automatically, but you'll have to drop them manually. */
struct mail_index_view *mail_index_view_open(struct mail_index *index);
void mail_index_view_close(struct mail_index_view **view);
/* Returns the index for given view. */
struct mail_index *mail_index_view_get_index(struct mail_index_view *view);
/* Returns number of mails in view. */
uint32_t mail_index_view_get_messages_count(struct mail_index_view *view);
/* Returns TRUE if we lost track of changes for some reason. */
bool mail_index_view_is_inconsistent(struct mail_index_view *view);
/* Returns number of transactions open for the view. */
unsigned int
mail_index_view_get_transaction_count(struct mail_index_view *view);
/* Transaction has to be opened to be able to modify index. You can have
multiple transactions open simultaneously. Committed transactions won't
show up until you've synchronized the view. Expunges won't show up until
you've synchronized the mailbox (mail_index_sync_begin). */
struct mail_index_transaction *
mail_index_transaction_begin(struct mail_index_view *view,
enum mail_index_transaction_flags flags);
int mail_index_transaction_commit(struct mail_index_transaction **t);
int mail_index_transaction_commit_full(struct mail_index_transaction **t,
struct mail_index_transaction_commit_result *result_r);
void mail_index_transaction_rollback(struct mail_index_transaction **t);
/* Discard all changes in the transaction. */
void mail_index_transaction_reset(struct mail_index_transaction *t);
/* When committing transaction, drop flag/keyword updates for messages whose
mdoseq is larger than max_modseq. Save those messages' sequences to the
given array. */
void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
uint64_t max_modseq,
ARRAY_TYPE(seq_range) *seqs);
/* Returns the view transaction was created for. */
struct mail_index_view *
mail_index_transaction_get_view(struct mail_index_transaction *t);
/* Returns TRUE if the given sequence is being expunged in this transaction. */
bool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
uint32_t seq);
/* Returns a view containing the mailbox state after changes in transaction
are applied. The view can still be used after transaction has been
committed. */
struct mail_index_view *
mail_index_transaction_open_updated_view(struct mail_index_transaction *t);
/* Begin synchronizing mailbox with index file. Returns 1 if ok,
0 if MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES is set and there's nothing to
sync, -1 if error.
mail_index_sync_next() returns all changes from previously committed
transactions which haven't yet been committed to the actual mailbox.
They're returned in ascending order and they never overlap (if we add more
sync types, then they might). You must go through all of them and update
the mailbox accordingly.
Changes done to the returned transaction are expected to describe the
mailbox's current state.
The returned view already contains all the changes (except expunge
requests). After applying sync records on top of backend flags they should
match flags in the view. If they don't, there have been external changes.
Returned expunges are treated as expunge requests. They're not really
removed from the index until you mark them expunged to the returned
transaction. If it's not possible to expunge the message (e.g. permission
denied), simply don't mark them expunged.
Returned sequence numbers describe the mailbox state at the beginning of
synchronization, ie. expunges don't affect them. */
int mail_index_sync_begin(struct mail_index *index,
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
enum mail_index_sync_flags flags);
/* Like mail_index_sync_begin(), but returns 1 if OK and if index is already
synchronized up to the given log_file_seq+offset, the synchronization isn't
started and this function returns 0. This should be done when you wish to
sync your committed transaction instead of doing a full mailbox
synchronization. */
int mail_index_sync_begin_to(struct mail_index *index,
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
struct mail_index_transaction **trans_r,
uint32_t log_file_seq, uoff_t log_file_offset,
enum mail_index_sync_flags flags);
/* Returns TRUE if it currently looks like syncing would return changes. */
bool mail_index_sync_have_any(struct mail_index *index,
enum mail_index_sync_flags flags);
/* Returns TRUE if it currently looks like syncing would return expunges. */
bool mail_index_sync_have_any_expunges(struct mail_index *index);
/* Returns the log file seq+offsets for the area which this sync is handling. */
void mail_index_sync_get_offsets(struct mail_index_sync_ctx *ctx,
uint32_t *seq1_r, uoff_t *offset1_r,
uint32_t *seq2_r, uoff_t *offset2_r);
/* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */
bool mail_index_sync_next(struct mail_index_sync_ctx *ctx,
struct mail_index_sync_rec *sync_rec);
/* 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 asigned 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);
/* 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);
/* 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 mailbox was modified. */
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