mail-index.h revision 8a3f549a3cb1d6dd980a4fa3db284653e256dae7
#ifndef MAIL_INDEX_H
#define MAIL_INDEX_H
#include "file-lock.h"
#include "fsync-mode.h"
#include "guid.h"
#include "mail-types.h"
#include "seq-range-array.h"
#define MAIL_INDEX_MAJOR_VERSION 7
#define MAIL_INDEX_MINOR_VERSION 2
#define MAIL_INDEX_HEADER_MIN_SIZE 120
enum mail_index_open_flags {
/* Create index if it doesn't exist */
MAIL_INDEX_OPEN_FLAG_CREATE = 0x01,
/* Don't try to mmap() index files */
/* Rely on O_EXCL when creating dotlocks */
MAIL_INDEX_OPEN_FLAG_NFS_FLUSH = 0x40,
/* Open the index read-only */
MAIL_INDEX_OPEN_FLAG_READONLY = 0x80,
/* Create backups of dovecot.index files once in a while */
MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS = 0x100,
/* If we run out of disk space, fail modifications instead of moving
indexes to memory. */
};
};
enum mail_index_header_flag {
/* Index file is corrupted, reopen or recreate it. */
MAIL_INDEX_HDR_FLAG_CORRUPTED = 0x0001,
MAIL_INDEX_HDR_FLAG_HAVE_DIRTY = 0x0002
};
enum mail_index_mail_flags {
/* For private use by backend. Replacing flags doesn't change this. */
MAIL_INDEX_MAIL_FLAG_BACKEND = 0x40,
/* Message flags haven't been written to backend */
MAIL_INDEX_MAIL_FLAG_DIRTY = 0x80
};
#define MAIL_INDEX_FLAGS_MASK \
struct mail_index_header {
/* major version is increased only when you can't have backwards
compatibility. minor version is increased when header size is
increased to contain new non-critical fields. */
/* non-external records between tail..head haven't been committed to
mailbox yet. */
/* daily first UIDs that have been added to index. */
};
struct mail_index_record {
};
struct mail_keywords {
struct mail_index *index;
unsigned int count;
int refcount;
/* variable sized list of keyword indexes */
unsigned int idx[1];
};
enum mail_index_transaction_flags {
/* If transaction is marked as hidden, the changes are marked with
hidden=TRUE when the view is synchronized. */
MAIL_INDEX_TRANSACTION_FLAG_HIDE = 0x01,
/* External transactions describe changes to mailbox that have already
happened. */
/* Don't add flag updates unless they actually change something.
This is reliable only when syncing, otherwise someone else might
have already committed a transaction that had changed the flags. */
/* fsync() this transaction (unless fsyncs are disabled) */
};
enum mail_index_sync_type {
MAIL_INDEX_SYNC_TYPE_APPEND = 0x01,
MAIL_INDEX_SYNC_TYPE_EXPUNGE = 0x02,
MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04,
MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD = 0x08,
};
enum mail_index_sync_flags {
/* Resync all dirty messages' flags. */
MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY = 0x01,
/* Drop recent flags from all messages */
MAIL_INDEX_SYNC_FLAG_DROP_RECENT = 0x02,
/* Create the transaction with AVOID_FLAG_UPDATES flag */
/* If there are no new transactions and nothing else to do,
return 0 in mail_index_sync_begin() */
/* Create the transaction with FSYNC flag */
MAIL_INDEX_SYNC_FLAG_FSYNC = 0x10,
/* If we see "delete index" request transaction, finish it.
This flag also allows committing more changes to a deleted index. */
};
enum mail_index_view_sync_flags {
/* Don't sync expunges */
/* Make sure view isn't inconsistent after syncing. This also means
that you don't care about view_sync_next()'s output, so it won't
return anything. */
};
struct mail_index_sync_rec {
enum mail_index_sync_type type;
/* MAIL_INDEX_SYNC_TYPE_FLAGS: */
/* MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD, .._REMOVE: */
unsigned int keyword_idx;
/* MAIL_INDEX_SYNC_TYPE_EXPUNGE: */
};
enum mail_index_view_sync_type {
/* Flags or keywords changed */
};
struct mail_index_view_sync_rec {
/* TRUE if this was a hidden transaction. */
unsigned int hidden:1;
};
struct mail_index_transaction_commit_result {
/* number of bytes in the written transaction.
all of it was written to the same file. */
unsigned int ignored_modseq_changes;
};
struct mail_index;
struct mail_index_map;
struct mail_index_view;
struct mail_index_transaction;
struct mail_index_sync_ctx;
struct mail_index_view_sync_ctx;
/* Specify how often to do fsyncs. If mode is FSYNC_MODE_OPTIMIZED, the mask
can be used to specify which transaction types to fsync. */
enum mail_index_sync_type mask);
/* Set locking method and maximum time to wait for a lock (-1U = default). */
enum file_lock_method lock_method,
unsigned int max_timeout_secs);
/* Open index. Returns 1 if ok, 0 if index doesn't exist and CREATE flags
wasn't given, -1 if error. */
/* Open or create index. Returns 0 if ok, -1 if error. */
enum mail_index_open_flags flags);
/* unlink() all the index files. */
/* Returns TRUE if index is currently in memory. */
/* Move the index into memory. Returns 0 if ok, -1 if error occurred. */
/* 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. */
/* 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. */
/* Returns the index for given view. */
/* Returns number of mails in view. */
/* Returns TRUE if we lost track of changes for some reason. */
/* Returns number of transactions open for the view. */
unsigned int
/* 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 *
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);
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,
/* Returns the view transaction was created for. */
struct mail_index_view *
/* Returns TRUE if the given sequence is being expunged in this transaction. */
bool mail_index_transaction_is_expunged(struct mail_index_transaction *t,
/* 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 *
/* 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. */
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. */
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);
/* Returns TRUE if it currently looks like syncing would return changes. */
enum mail_index_sync_flags flags);
/* Returns the log file seq+offsets for the area which this sync is handling. */
/* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */
struct mail_index_sync_rec *sync_rec);
/* Returns TRUE if there's more to sync. */
/* Returns TRUE if sync has any expunges to handle. */
/* 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(). */
/* Update result when refreshing index at the end of sync. */
struct mail_index_transaction_commit_result *result);
/* Commit synchronization by writing all changes to mail index file. */
/* Rollback synchronization - none of the changes listed by sync_next() are
actually written to index file. */
/* Mark index file corrupted. Invalidates all views. */
/* Check and fix any found problems. Returns -1 if we couldn't lock for sync,
0 if everything went ok. */
/* Returns TRUE if mail_index_fsck() has been called since the last
mail_index_reset_fscked() call. */
/* 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 *
enum mail_index_view_sync_flags flags);
struct mail_index_view_sync_rec *sync_rec);
void
bool *delayed_expunges_r);
/* Returns the index header. */
const struct mail_index_header *
/* Returns the wanted message record. */
const struct mail_index_record *
const struct mail_index_record *
struct mail_index_map **map_r);
/* Returns TRUE if the given message has already been expunged from index. */
/* Note that returned keyword indexes aren't sorted. */
/* Return keywords from given map. */
/* 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. */
enum mail_flags *flags_r,
/* Returns the UID for given message. May be slightly faster than
mail_index_lookup()->uid. */
/* 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. */
/* Find first mail with (mail->flags & flags_mask) == flags. Useful mostly for
taking advantage of lowwater-fields in headers. */
/* Append a new record to index. */
/* Assign UIDs for mails with uid=0 or uid<first_uid. 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,
/* Expunge record from index. Note that this doesn't affect sequence numbers
until transaction is committed and mailbox is synced. */
/* Like mail_index_expunge(), but also write message GUID to transaction log. */
const guid_128_t guid_128);
/* Update flags in index. */
enum modify_type modify_type,
enum mail_flags flags);
void mail_index_update_flags_range(struct mail_index_transaction *t,
enum modify_type modify_type,
enum mail_flags flags);
/* Update message's modseq to be at least min_modseq. */
/* Update highest modseq to be at least min_modseq. */
void mail_index_update_highest_modseq(struct mail_index_transaction *t,
/* 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
/* Returns the last time mailbox was modified. */
/* Lookup a keyword, returns TRUE if found, FALSE if not. */
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(). */
/* Create a keyword list structure. */
struct mail_keywords *
const char *const keywords[]);
struct mail_keywords *
const ARRAY_TYPE(keyword_indexes)
/* Update keywords for given message. */
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,
bool prepend);
/* Returns the full error message for last error. This message may
contain paths etc. so it shouldn't be shown to users. */
/* Reset the error message. */
/* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given
flags variable. */
/* Apply changes in MAIL_INDEX_SYNC_TYPE_KEYWORD_* typed sync records to given
keywords array. Returns TRUE If something was changed. */
/* register index extension. name is a unique identifier for the extension.
returns unique identifier for the name. */
/* Returns TRUE and sets ext_id_r if extension with given name is registered. */
/* Resize existing extension data. If size is grown, the new data will be
zero-filled. If size is shrinked, the data is simply dropped. */
/* 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. */
/* 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. */
/* 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,
/* Get the current reset_id for given extension. Returns TRUE if it exists. */
struct mail_index_map *map,
/* Returns extension header. */
/* 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. */
bool *expunged_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. */
/* Update extension header field. */
void mail_index_update_header_ext(struct mail_index_transaction *t,
/* 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. */
diffs for this seq. */
int mail_index_atomic_inc_ext(struct mail_index_transaction *t,
#endif