mail-index.h revision 8e7da21696c9f8a6d5e601243fb6172ec85d47b2
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen#ifndef __MAIL_INDEX_H
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define __MAIL_INDEX_H
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-types.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAIL_INDEX_MAJOR_VERSION 4
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAIL_INDEX_MINOR_VERSION 0
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAIL_INDEX_HEADER_MIN_SIZE 80
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen/* Number of keywords in mail_index_record. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define INDEX_KEYWORDS_COUNT (3*8)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define INDEX_KEYWORDS_BYTE_COUNT ((INDEX_KEYWORDS_COUNT+CHAR_BIT-1) / CHAR_BIT)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenenum mail_index_open_flags {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Create index if it doesn't exist */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_OPEN_FLAG_CREATE = 0x01,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Open the index as fast as possible - do only minimal checks and
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen delay opening cache/log files unless they're needed. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_OPEN_FLAG_FAST = 0x02,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Don't try to mmap() index files */
da7f1a07f583df8905684a7b78469960afd7c78dPhil Carmody MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE = 0x04,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Don't try to write() to mmap()ed index files. Required for the few
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen OSes that don't have unified buffer cache
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen (currently OpenBSD <= 3.5) */
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen MAIL_INDEX_OPEN_FLAG_MMAP_NO_WRITE = 0x08,
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen /* Don't use fcntl() locking */
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen MAIL_INDEX_OPEN_FLAG_FCNTL_LOCKS_DISABLE= 0x10
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen};
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainenenum mail_index_header_compat_flags {
da7f1a07f583df8905684a7b78469960afd7c78dPhil Carmody MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenenum mail_index_header_flag {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Index file is corrupted, reopen or recreate it. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_HDR_FLAG_CORRUPTED = 0x0001,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_HDR_FLAG_HAVE_DIRTY = 0x0002
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenenum mail_index_mail_flags {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY = 0x80
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
263fa7b43fb222f9805b80f62090907fe3f9ec13Timo Sirainenenum mail_index_error {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* No errors */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_ERROR_NONE,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Internal error, see get_error_text() for more information. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_ERROR_INTERNAL,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* We ran out of available disk space. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAIL_INDEX_ERROR_DISKSPACE
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen#define MAIL_INDEX_FLAGS_MASK \
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DELETED | MAIL_SEEN | MAIL_DRAFT)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainentypedef unsigned char keywords_mask_t[INDEX_KEYWORDS_BYTE_COUNT];
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainenstruct mail_index_header {
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen /* major version is increased only when you can't have backwards
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen compatibility. minor version is increased when header size is
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen increased to contain new non-critical fields. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint8_t major_version;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint8_t minor_version;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint16_t header_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint16_t record_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint16_t keywords_mask_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* 0 = flags
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen 1 = sizeof(uoff_t)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen 2 = sizeof(time_t)
5733207dc3ec10e6e5a6e0a8b30fbd1b061062b9Timo Sirainen 3 = unused */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint8_t compat_data[4];
861f53be0cc2fa5665f3c107a7576e2a53bb2eb0Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t indexid;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t flags;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t uid_validity;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t next_uid;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t messages_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t recent_messages_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t seen_messages_count;
df27aa70a3f0250767eb8a154981cd7f5dadcc91Timo Sirainen uint32_t deleted_messages_count;
861f53be0cc2fa5665f3c107a7576e2a53bb2eb0Timo Sirainen
861f53be0cc2fa5665f3c107a7576e2a53bb2eb0Timo Sirainen /* these UIDs may not exist and may not even be unseen */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t first_recent_uid_lowwater;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t first_unseen_uid_lowwater;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t first_deleted_uid_lowwater;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t log_file_seq;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t log_file_offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint64_t sync_size;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint32_t sync_stamp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen uint32_t cache_file_seq;
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen};
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct mail_index_record {
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen uint32_t uid;
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen uint8_t flags; /* mail_flags | mail_index_mail_flags */
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen keywords_mask_t keywords;
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen uint32_t cache_offset;
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen};
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainenenum mail_index_sync_type {
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen MAIL_INDEX_SYNC_TYPE_APPEND = 0x01,
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen MAIL_INDEX_SYNC_TYPE_EXPUNGE = 0x02,
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen};
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen#define MAIL_INDEX_SYNC_MASK_ALL 0xff
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainen
935960e45571872e38f730964f8ca1d116a1b532Timo Sirainenstruct mail_index_sync_rec {
uint32_t uid1, uid2;
enum mail_index_sync_type type;
/* MAIL_INDEX_SYNC_TYPE_FLAGS: */
uint8_t add_flags;
keywords_mask_t add_keywords;
uint8_t remove_flags;
keywords_mask_t remove_keywords;
/* MAIL_INDEX_SYNC_TYPE_APPEND: */
const struct mail_index_record *appends;
size_t appends_count;
};
struct mail_index;
struct mail_index_view;
struct mail_index_transaction;
struct mail_index_sync_ctx;
struct mail_index_view_sync_ctx;
struct mail_index *mail_index_alloc(const char *dir, const char *prefix);
void mail_index_free(struct mail_index *index);
/* register extra data to be used in mail_index_record. calls to this function
must remain in same order as long as the index exists, or it breaks.
returns the relative offset in mail_index_record for the data. */
uint16_t mail_index_register_record_extra(struct mail_index *index,
uint16_t size);
int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags);
void mail_index_close(struct mail_index *index);
/* Force checking if index can be refreshed. */
int mail_index_refresh(struct mail_index *index);
struct mail_cache *mail_index_get_cache(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. Opening view
acquires a lock immediately. */
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);
/* Call whenever you've done with requesting messages from view for a while. */
void mail_index_view_unlock(struct mail_index_view *view);
/* Returns number of mails in view. */
uint32_t mail_index_view_get_message_count(struct mail_index_view *view);
/* Returns TRUE if we lost track of changes for some reason. */
int mail_index_view_is_inconsistent(struct mail_index_view *view);
/* Transaction has to be opened to be able to modify index. You can have
multiple transactions open simultaneously. Note that committed transactions
won't show up until you've synchronized mailbox (mail_index_sync_begin). */
struct mail_index_transaction *
mail_index_transaction_begin(struct mail_index_view *view, int hide);
int mail_index_transaction_commit(struct mail_index_transaction *t,
uint32_t *log_file_seq_r,
uoff_t *log_file_offset_r);
void mail_index_transaction_rollback(struct mail_index_transaction *t);
/* Begin synchronizing mailbox with index file. This call locks the index
exclusively against other modifications. Returns 1 if ok, -1 if error.
If log_file_seq is not (uint32_t)-1 and index is already synchronized up
to given log_file_offset, the synchronization isn't started and this
function returns 0. This should be done when you wish to sync your previous
transaction instead of doing a full mailbox synchronization.
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. You must go through all of them and
update the mailbox accordingly.
None of the changes actually show up in index until at
mail_index_sync_end().
Note that there may be multiple overlapping flag changes. They're returned
sorted by their beginning sequence. They never overlap expunges however.
Returned sequence numbers describe the mailbox state at the beginning of
synchronization, ie. expunges don't affect them.
You may create a new transaction for the returned view. That transaction
acts as "external mailbox changes" transaction. Any changes done there are
expected to describe mailbox's current state. */
int mail_index_sync_begin(struct mail_index *index,
struct mail_index_sync_ctx **ctx_r,
struct mail_index_view **view_r,
uint32_t log_file_seq, uoff_t log_file_offset);
/* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */
int mail_index_sync_next(struct mail_index_sync_ctx *ctx,
struct mail_index_sync_rec *sync_rec);
/* Returns 1 if there's more to sync, 0 if not. */
int mail_index_sync_have_more(struct mail_index_sync_ctx *ctx);
/* End synchronization by unlocking the index and closing the view. */
int mail_index_sync_end(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. If index is broken beyond repair, it's
marked corrupted and 0 is returned. Otherwise returns -1 if there was some
I/O error or 1 if everything went ok. */
int mail_index_fsck(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. */
int mail_index_view_sync_begin(struct mail_index_view *view,
enum mail_index_sync_type sync_mask,
struct mail_index_view_sync_ctx **ctx_r);
/* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */
int mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
struct mail_index_sync_rec *sync_rec);
const uint32_t *
mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
size_t *count_r);
void mail_index_view_sync_end(struct mail_index_view_sync_ctx *ctx);
/* Returns the index header. */
int mail_index_get_header(struct mail_index_view *view,
const struct mail_index_header **hdr_r);
/* Returns the given message. */
int mail_index_lookup(struct mail_index_view *view, uint32_t seq,
const struct mail_index_record **rec_r);
/* Returns the UID for given message. May be slightly faster than
mail_index_lookup()->uid */
int 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, sequences are
set to 0. Note that any of the returned sequences may have been expunged
already. */
int mail_index_lookup_uid_range(struct mail_index_view *view,
uint32_t first_uid, uint32_t last_uid,
uint32_t *first_seq_r, uint32_t *last_seq_r);
/* Find first mail with (mail->flags & flags_mask) == flags. Useful mostly for
taking advantage of lowwater-fields in headers. */
int 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);
/* 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);
/* 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, keywords_mask_t keywords);
/* Update field in header. */
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size);
/* Returns the last error code. */
enum mail_index_error mail_index_get_last_error(struct mail_index *index);
/* 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);
/* Returns TRUE if index is currently only in memory. */
int mail_index_is_in_memory(struct mail_index *index);
/* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given
flags variables. */
void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
uint8_t *flags, keywords_mask_t keywords);
#endif