mail-index.h revision d5aa01c4d7cc8b099f47cf011cba850b1759eb2d
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch#ifndef __MAIL_INDEX_H
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#define __MAIL_INDEX_H
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "message-parser.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "imap-util.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#define MAIL_INDEX_VERSION 1
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#define INDEX_FILE_PREFIX ".imap.index"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenenum {
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen};
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenenum {
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* Rebuild flag is set while index is being rebuilt or when
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen some error is noticed in the index file. If this flag is set,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen the index shouldn't be used before rebuilding it. */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen MAIL_INDEX_FLAG_REBUILD = 0x01,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen MAIL_INDEX_FLAG_FSCK = 0x02,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen MAIL_INDEX_FLAG_CACHE_FIELDS = 0x04,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen MAIL_INDEX_FLAG_COMPRESS = 0x08,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen MAIL_INDEX_FLAG_COMPRESS_DATA = 0x10,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen MAIL_INDEX_FLAG_REBUILD_HASH = 0x20
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen};
5a8ee853d0b62692a6e624b125d08d87a79e001fTimo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainentypedef enum {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* First MUST become a field that ALWAYS exists. This is because some
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen code which goes through all fields does it by calling
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen lookup_field(.., .., 1) and next() after that. If the first field
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen didn't exist, nothing would be found.
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen Location field is a good first field anyway, it's the one most
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen often needed. With maildir format, it's the file name and with
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen mbox format it's the file position as a string. */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_LOCATION = 0x0001,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_ENVELOPE = 0x0002,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_BODY = 0x0004,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_BODYSTRUCTURE = 0x0008,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_FROM = 0x0010,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_TO = 0x0020,
5a8ee853d0b62692a6e624b125d08d87a79e001fTimo Sirainen FIELD_TYPE_CC = 0x0040,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen FIELD_TYPE_BCC = 0x0080,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_SUBJECT = 0x0100,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_MD5 = 0x0200,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_LAST = 0x0400,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_MAX_BITS = 10
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen} MailField;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen#define IS_HEADER_FIELD(field) \
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen (((field) & (FIELD_TYPE_FROM | FIELD_TYPE_TO | FIELD_TYPE_CC | \
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen FIELD_TYPE_BCC | FIELD_TYPE_SUBJECT)) != 0)
58a770f1e0ab553a0dba9cad9d6f3a6cdf2dc855Timo Sirainen
58a770f1e0ab553a0dba9cad9d6f3a6cdf2dc855Timo Sirainentypedef enum {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen MAIL_LOCK_UNLOCK = 0,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen MAIL_LOCK_SHARED,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen MAIL_LOCK_EXCLUSIVE
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen} MailLockType;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndex MailIndex;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndexData MailIndexData;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailHash MailHash;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailModifyLog MailModifyLog;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndexHeader MailIndexHeader;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndexDataHeader MailIndexDataHeader;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndexRecord MailIndexRecord;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndexDataRecord MailIndexDataRecord;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainentypedef struct _MailIndexUpdate MailIndexUpdate;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainenstruct _MailIndexHeader {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned char compat_data[4];
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* 0 = flags,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen 1 = sizeof(unsigned int),
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen 2 = sizeof(time_t),
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen 3 = sizeof(off_t) */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int version;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen unsigned int indexid;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int flags;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int cache_fields;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen off_t first_hole_position;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int first_hole_records;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int uid_validity;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int next_uid;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int messages_count;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int seen_messages_count;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int deleted_messages_count;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int last_nonrecent_uid;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* these UIDs may not exist and may not even be unseen */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int first_unseen_uid_lowwater;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int first_deleted_uid_lowwater;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int reserved_for_future_usage[5];
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen};
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainenstruct _MailIndexDataHeader {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen unsigned int indexid;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen off_t deleted_space;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen};
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenstruct _MailIndexRecord {
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen unsigned int uid;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen unsigned int msg_flags; /* MailFlags */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen time_t internal_date;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen time_t sent_date;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen off_t data_position;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen unsigned int data_size;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen unsigned int cached_fields;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen off_t header_size;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen off_t body_size;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen off_t full_virtual_size;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen};
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#define MSG_HAS_VALID_CRLF_DATA(rec) \
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen ((rec)->header_size + (rec)->body_size == (rec)->full_virtual_size)
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainenstruct _MailIndexDataRecord {
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen unsigned int field; /* MailField */
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen unsigned int full_field_size;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen char data[MEM_ALIGN_SIZE]; /* variable size */
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen};
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#define DATA_RECORD_SIZE(rec) \
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen (sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE + (rec)->full_field_size)
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainenstruct _MailIndex {
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen int (*open)(MailIndex *index, int update_recent);
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen int (*open_or_create)(MailIndex *index, int update_recent);
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* Free index from memory. */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen void (*free)(MailIndex *index);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* Lock/unlock index. May block. Note that unlocking must not
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen reset error from get_last_error() as unlocking can be done as
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen a cleanup after some other function failed. Index is always
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen mmap()ed after set_lock() succeeds.
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen Trying to change a shared lock into exclusive lock is a fatal
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen error, since it may create a deadlock. Even though operating
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen system should detect it and fail, it's not a good idea to even
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen let it happen. Better ways to do this would be to a) mark the
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen data to be updated later, b) use try_lock() if the update is
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen preferred but not required, c) unlock + lock again, but make
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen sure that won't create race conditions */
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen int (*set_lock)(MailIndex *index, MailLockType lock_type);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen /* Try locking the index. Returns TRUE if the lock was got and
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen FALSE if lock isn't possible to get currently or some other error
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen occured. Never blocks. */
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen int (*try_lock)(MailIndex *index, MailLockType lock_type);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen /* Rebuild the whole index. Note that this changes the indexid
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen so all the other files must also be rebuilt after this call.
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen Index MUST NOT have shared lock, exclusive lock or no lock at all
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen is fine. Note that this function may leave the index exclusively
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen locked. */
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen int (*rebuild)(MailIndex *index);
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen /* Verify that the index is valid. If anything invalid is found,
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen rebuild() is called. Same locking issues as with rebuild(). */
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen int (*fsck)(MailIndex *index);
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen /* Synchronize the index with the mailbox. Same locking issues as
99df8a838cd9c5257ea5a2554383a9a999191e38Pali Rohár with rebuild(). */
99df8a838cd9c5257ea5a2554383a9a999191e38Pali Rohár int (*sync)(MailIndex *index);
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen /* Returns the index header (never fails). The index needs to be
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen locked before calling this function, and must be kept locked as
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen long as you keep using the returned structure. */
99df8a838cd9c5257ea5a2554383a9a999191e38Pali Rohár MailIndexHeader *(*get_header)(MailIndex *index);
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* sequence -> data lookup. The index needs to be locked before calling
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen this function, and must be kept locked as long as you keep using
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen the returned structure. */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen MailIndexRecord *(*lookup)(MailIndex *index, unsigned int seq);
baf3e87e186453fda13bd21f7cbcb2efc8492e8bTimo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* Return the next record after specified record, or NULL if it was
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen last record. The index must be locked all the time between
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen lookup() and last next() call. */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen MailIndexRecord *(*next)(MailIndex *index, MailIndexRecord *rec);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
/* First first existing UID in range. */
MailIndexRecord *(*lookup_uid_range)(MailIndex *index,
unsigned int first_uid,
unsigned int last_uid);
/* Find field from specified record, or NULL if it's not in index. */
const char *(*lookup_field)(MailIndex *index, MailIndexRecord *rec,
MailField field);
/* Returns sequence for given message. */
unsigned int (*get_sequence)(MailIndex *index, MailIndexRecord *rec);
/* Open mail file and return it as mmap()ed IOBuffer, or
NULL if failed. */
IOBuffer *(*open_mail)(MailIndex *index, MailIndexRecord *rec);
/* Expunge a mail from index. Hash and modifylog is also updated. The
index must be exclusively locked before calling this function.
If seq is 0, the modify log isn't updated. This is useful if
after append() something goes wrong and you wish to delete the
mail immediately. If external_change is TRUE, the modify log is
always written.
Note that the sequence numbers also update immediately after this
call, so if you want to delete messages 1..4 just call this
function 4 times with seq being 1. */
int (*expunge)(MailIndex *index, MailIndexRecord *rec,
unsigned int seq, int external_change);
/* Update mail flags. The index must be exclusively locked before
calling this function. This shouldn't be called in the middle of
update_begin() as it may modify location field. */
int (*update_flags)(MailIndex *index, MailIndexRecord *rec,
unsigned int seq, MailFlags flags,
int external_change);
/* Append a new record to index. The index must be exclusively
locked before calling this function. The record pointer is
updated to the mmap()ed record. rec->uid field is updated by this
function, nothing else is touched. */
int (*append)(MailIndex *index, MailIndexRecord **rec);
/* Updating fields happens by calling update_begin(), one or more
update_field()s and finally update_end() which does the actual
updating. The index must be exclusively locked all this time.
update_begin() and update_field() functions cannot fail.
The extra_space parameter for update_field() specifies the amount
of extra empty space we should leave after the value, so that if
the field grows in future it could be expanded without copying it
to end of file. When the field already exists, the extra_space
is ignored.
The files may not actually be updated until after you've unlocked
the file. */
MailIndexUpdate *(*update_begin)(MailIndex *index,
MailIndexRecord *rec);
int (*update_end)(MailIndexUpdate *update);
void (*update_field)(MailIndexUpdate *update, MailField field,
const char *value, unsigned int extra_space);
/* Returns last error message */
const char *(*get_last_error)(MailIndex *index);
/* Returns TRUE if index is now in inconsistent state with the
previous known state, meaning that the message IDs etc. may
have changed - only way to recover this would be to fully close
the mailbox and reopen it. With IMAP connection this would mean
a forced disconnection since we can't do forced CLOSE. */
int (*is_inconsistency_error)(MailIndex *index);
/* private: */
MailIndexData *data;
MailHash *hash;
MailModifyLog *modifylog;
char *dir; /* directory where to place the index files */
char *filepath; /* index file path */
unsigned int indexid;
char *mbox_path; /* mbox-specific path to the actual mbox file */
off_t mbox_size; /* last synced size of mbox file */
int mbox_locks;
int fd; /* opened index file */
char *error; /* last error message */
void *mmap_base;
size_t mmap_length;
MailLockType lock_type;
MailIndexHeader *header;
MailIndexRecord *last_lookup;
unsigned int last_lookup_seq;
unsigned int first_recent_uid;
unsigned int modifylog_id;
time_t file_sync_stamp;
/* these fields are OR'ed to the fields in index header once we
get around grabbing exclusive lock */
unsigned int set_flags;
unsigned int set_cache_fields;
unsigned int opened:1;
unsigned int updating:1;
unsigned int inconsistent:1;
unsigned int dirty_mmap:1;
};
/* needed to remove annoying warnings about not initializing all struct
members.. */
#define MAIL_INDEX_PRIVATE_FILL \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0
/* defaults - same as above but prefixed with mail_index_. */
int mail_index_open(MailIndex *index, int update_recent);
int mail_index_open_or_create(MailIndex *index, int update_recent);
int mail_index_set_lock(MailIndex *index, MailLockType lock_type);
int mail_index_try_lock(MailIndex *index, MailLockType lock_type);
int mail_index_fsck(MailIndex *index);
MailIndexHeader *mail_index_get_header(MailIndex *index);
MailIndexRecord *mail_index_lookup(MailIndex *index, unsigned int seq);
MailIndexRecord *mail_index_next(MailIndex *index, MailIndexRecord *rec);
MailIndexRecord *mail_index_lookup_uid_range(MailIndex *index,
unsigned int first_uid,
unsigned int last_uid);
const char *mail_index_lookup_field(MailIndex *index, MailIndexRecord *rec,
MailField field);
unsigned int mail_index_get_sequence(MailIndex *index, MailIndexRecord *rec);
int mail_index_expunge(MailIndex *index, MailIndexRecord *rec,
unsigned int seq, int external_change);
int mail_index_update_flags(MailIndex *index, MailIndexRecord *rec,
unsigned int seq, MailFlags flags,
int external_change);
int mail_index_append(MailIndex *index, MailIndexRecord **rec);
MailIndexUpdate *mail_index_update_begin(MailIndex *index,
MailIndexRecord *rec);
int mail_index_update_end(MailIndexUpdate *update);
void mail_index_update_field(MailIndexUpdate *update, MailField field,
const char *value, unsigned int extra_space);
const char *mail_index_get_last_error(MailIndex *index);
int mail_index_is_inconsistency_error(MailIndex *index);
/* INTERNAL: */
void mail_index_init_header(MailIndexHeader *hdr);
void mail_index_close(MailIndex *index);
int mail_index_rebuild_all(MailIndex *index);
int mail_index_sync_file(MailIndex *index);
int mail_index_fmsync(MailIndex *index, size_t size);
void mail_index_update_headers(MailIndexUpdate *update, IOBuffer *inbuf,
MailField cache_fields,
MessageHeaderFunc header_func, void *context);
int mail_index_update_cache(MailIndex *index);
int mail_index_compress(MailIndex *index);
int mail_index_compress_data(MailIndex *index);
/* Max. mmap()ed size for a message */
#define MAIL_MMAP_BLOCK_SIZE (1024*256)
/* off_t to index file for given record */
#define INDEX_FILE_POSITION(index, ptr) \
((off_t) ((char *) (ptr) - (char *) ((index)->mmap_base)))
/* index number for off_t position */
#define INDEX_POSITION_INDEX(pos) \
(((pos) - sizeof(MailIndexHeader)) / sizeof(MailIndexRecord))
/* mark the index corrupted */
#define INDEX_MARK_CORRUPTED(index) \
STMT_START { (index)->set_flags |= MAIL_INDEX_FLAG_REBUILD; } STMT_END
#endif