mail-index.h revision 1cfc39f5c151f51b554811336baede97c5a82c02
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen#ifndef __MAIL_INDEX_H
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define __MAIL_INDEX_H
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch#include "message-parser.h"
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch#include "imap-util.h"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define MAIL_INDEX_VERSION 1
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch#define INDEX_FILE_PREFIX ".imap.index"
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Boschenum {
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch};
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Boschenum {
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch /* Rebuild flag is set while index is being rebuilt or when
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch some error is noticed in the index file. If this flag is set,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch the index shouldn't be used before rebuilding it. */
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_REBUILD = 0x01,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_FSCK = 0x02,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_CACHE_FIELDS = 0x04,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_COMPRESS = 0x08,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_COMPRESS_DATA = 0x10,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_REBUILD_TREE = 0x20,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_DIRTY_MESSAGES = 0x40,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_INDEX_FLAG_DIRTY_CUSTOMFLAGS = 0x80
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch};
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Boschtypedef enum {
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch /* First MUST become a field that ALWAYS exists. This is because some
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch code which goes through all fields does it by calling
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch lookup_field(.., .., 1) and next() after that. If the first field
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch didn't exist, nothing would be found.
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch Location field is a good first field anyway, it's the one most
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch often needed. With maildir format, it's the file name and with
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mbox format it's the file position. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_LOCATION = 0x0001,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_ENVELOPE = 0x0002,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch FIELD_TYPE_BODY = 0x0004,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_BODYSTRUCTURE = 0x0008,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_MD5 = 0x0010,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_MESSAGEPART = 0x0020,
45324f1eafa565dbc65e4dd335de9507dead55e6Timo Sirainen
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_LAST = 0x0040,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_MAX_BITS = 6
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch} MailField;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef enum {
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch /* If binary flags are set, it's not checked whether mail is
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch missing CRs. So this flag may be set as an optimization for
833bed942977673526c72e79bccc09314fc57104Phil Carmody regular non-binary mails as well if it's known that it contains
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch valid CR+LF line breaks. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch INDEX_MAIL_FLAG_BINARY_HEADER = 0x0001,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch INDEX_MAIL_FLAG_BINARY_BODY = 0x0002,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Currently this means with mbox format that message flags have
e9228a3918aa0243eff4aae1ff5462bd3198417fTimo Sirainen been changed in index, but not written into mbox file yet. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch INDEX_MAIL_FLAG_DIRTY = 0x0004
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch} MailIndexMailFlags;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
1e9296de32c9ddda40f33c06556cd568ddadf71fTimo Sirainen#define IS_HEADER_FIELD(field) \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (((field) & (FIELD_TYPE_FROM | FIELD_TYPE_TO | FIELD_TYPE_CC | \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_BCC | FIELD_TYPE_SUBJECT)) != 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define IS_BODYSTRUCTURE_FIELD(field) \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (((field) & (FIELD_TYPE_BODY|FIELD_TYPE_BODYSTRUCTURE| \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch FIELD_TYPE_MESSAGEPART)) != 0)
1e9296de32c9ddda40f33c06556cd568ddadf71fTimo Sirainen
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef enum {
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_LOCK_UNLOCK = 0,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MAIL_LOCK_SHARED,
833bed942977673526c72e79bccc09314fc57104Phil Carmody MAIL_LOCK_EXCLUSIVE
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch} MailLockType;
833bed942977673526c72e79bccc09314fc57104Phil Carmody
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndex MailIndex;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexData MailIndexData;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailTree MailTree;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailModifyLog MailModifyLog;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailCustomFlags MailCustomFlags;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexHeader MailIndexHeader;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexDataHeader MailIndexDataHeader;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexRecord MailIndexRecord;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexDataRecord MailIndexDataRecord;
1e9296de32c9ddda40f33c06556cd568ddadf71fTimo Sirainen
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexUpdate MailIndexUpdate;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainenstruct _MailIndexHeader {
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen unsigned char compat_data[8];
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen /* 0 = version
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch 1 = flags,
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen 2 = sizeof(unsigned int),
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch 3 = sizeof(time_t),
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch 4 = sizeof(uoff_t),
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch 5 = MEM_ALIGN_SIZE */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int indexid;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int sync_id; /* re-mmap() when changed, required only
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch if file size is changed */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int flags;
14bd2410de3a0261d9c53c6120915027262216bdTimo Sirainen unsigned int cache_fields;
14bd2410de3a0261d9c53c6120915027262216bdTimo Sirainen
14bd2410de3a0261d9c53c6120915027262216bdTimo Sirainen uoff_t used_file_size;
9f8cef4cbc49797053c343209ea13022fdbc5a63Stephan Bosch
9f8cef4cbc49797053c343209ea13022fdbc5a63Stephan Bosch unsigned int first_hole_index;
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen unsigned int first_hole_records;
9f8cef4cbc49797053c343209ea13022fdbc5a63Stephan Bosch
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen unsigned int uid_validity;
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen unsigned int next_uid;
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen unsigned int messages_count;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int seen_messages_count;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int deleted_messages_count;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int last_nonrecent_uid;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* these UIDs may not exist and may not even be unseen */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int first_unseen_uid_lowwater;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int first_deleted_uid_lowwater;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch};
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Boschstruct _MailIndexDataHeader {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int indexid;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int reserved; /* for alignment mostly */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch uoff_t used_file_size;
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch uoff_t deleted_space;
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch};
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
833bed942977673526c72e79bccc09314fc57104Phil Carmodystruct _MailIndexRecord {
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch /* remember to keep uoff_t's 8 byte aligned so we don't waste space */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int uid;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int msg_flags; /* MailFlags */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch time_t internal_date;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int index_flags; /* MailIndexMailFlags */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int cached_fields; /* MailField */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int data_size;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch uoff_t data_position;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch uoff_t header_size; /* 0 if not known yet */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch uoff_t body_size; /* if header_size == 0, the size of full message */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch};
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Boschstruct _MailIndexDataRecord {
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int field; /* MailField */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int full_field_size;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch char data[MEM_ALIGN_SIZE]; /* variable size */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch};
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch#define SIZEOF_MAIL_INDEX_DATA \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define DATA_RECORD_SIZE(rec) \
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size)
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstruct _MailIndex {
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch /* If fast is TRUE, compressing and cache updates are not performed. */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch int (*open)(MailIndex *index, int update_recent, int fast);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*open_or_create)(MailIndex *index, int update_recent, int fast);
91a482473f200152d6713181c0e36f7a4f03ef6dTimo Sirainen
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Free index from memory. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch void (*free)(MailIndex *index);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Lock/unlock index. May block. Note that unlocking must not
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch reset error from get_last_error() as unlocking can be done as
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch a cleanup after some other function failed. Index is always
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mmap()ed after set_lock() succeeds.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch Trying to change a shared lock into exclusive lock is a fatal
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch error, since it may create a deadlock. Even though operating
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch system should detect it and fail, it's not a good idea to even
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch let it happen. Better ways to do this would be to a) mark the
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch data to be updated later, b) use try_lock() if the update is
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch preferred but not required, c) unlock + lock again, but make
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen sure that won't create race conditions */
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen int (*set_lock)(MailIndex *index, MailLockType lock_type);
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen /* Try locking the index. Returns TRUE if the lock was got and
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen FALSE if lock isn't possible to get currently or some other error
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen occured. Never blocks. */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch int (*try_lock)(MailIndex *index, MailLockType lock_type);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* Rebuild the whole index. Note that this changes the indexid
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch so all the other files must also be rebuilt after this call.
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch Index MUST NOT have shared lock, but exclusive lock or no lock at
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch all is fine. Note that this function may leave the index
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch exclusively locked, and always sets index->inconsistent = TRUE. */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch int (*rebuild)(MailIndex *index);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* Verify that the index is valid. If anything invalid is found,
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch rebuild() is called. Same locking issues as with rebuild(). */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch int (*fsck)(MailIndex *index);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* Synchronize the index with the mailbox. Same locking issues as
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch with rebuild(). */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch int (*sync)(MailIndex *index);
93ed69606237a08623f8294c060fa148880058f8Timo Sirainen
93ed69606237a08623f8294c060fa148880058f8Timo Sirainen /* Returns the index header (never fails). The index needs to be
93ed69606237a08623f8294c060fa148880058f8Timo Sirainen locked before calling this function, and must be kept locked as
93ed69606237a08623f8294c060fa148880058f8Timo Sirainen long as you keep using the returned structure. */
93ed69606237a08623f8294c060fa148880058f8Timo Sirainen MailIndexHeader *(*get_header)(MailIndex *index);
93ed69606237a08623f8294c060fa148880058f8Timo Sirainen
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* sequence -> data lookup. The index needs to be locked before calling
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch this function, and must be kept locked as long as you keep using
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch the returned structure. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch MailIndexRecord *(*lookup)(MailIndex *index, unsigned int seq);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Return the next record after specified record, or NULL if it was
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch last record. The index must be locked all the time between
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch lookup() and last next() call. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch MailIndexRecord *(*next)(MailIndex *index, MailIndexRecord *rec);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Find first existing UID in range. */
711e8e4c5c5d702dfa062f42a1ede5de14c151c9Stephan Bosch MailIndexRecord *(*lookup_uid_range)(MailIndex *index,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int first_uid,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int last_uid,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int *seq_r);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Find field from specified record, or NULL if it's not in index.
711e8e4c5c5d702dfa062f42a1ede5de14c151c9Stephan Bosch Makes sure that the field ends with \0. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const char *(*lookup_field)(MailIndex *index, MailIndexRecord *rec,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch MailField field);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Find field from specified record, or NULL if it's not in index. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const void *(*lookup_field_raw)(MailIndex *index, MailIndexRecord *rec,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch MailField field, size_t *size);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Open mail file and return it as mmap()ed IBuffer, or
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch NULL if failed. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch IBuffer *(*open_mail)(MailIndex *index, MailIndexRecord *rec);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Expunge a mail from index. Tree and modifylog is also updated. The
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch index must be exclusively locked before calling this function.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch If seq is 0, the modify log isn't updated. This is useful if
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch after append() something goes wrong and you wish to delete the
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mail immediately. If external_change is TRUE, the modify log is
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch always written.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch Note that the sequence numbers also update immediately after this
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch call, so if you want to delete messages 1..4 just call this
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch function 4 times with seq being 1. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*expunge)(MailIndex *index, MailIndexRecord *rec,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int seq, int external_change);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Update mail flags. The index must be exclusively locked before
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch calling this function. This shouldn't be called in the middle of
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch update_begin() as it may modify location field. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*update_flags)(MailIndex *index, MailIndexRecord *rec,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int seq, MailFlags flags,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int external_change);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Append a new record to index. The index must be exclusively
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch locked before calling this function. The record pointer is
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch updated to the mmap()ed record. rec->uid is updated in
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch append_end(). */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*append_begin)(MailIndex *index, MailIndexRecord **rec);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*append_end)(MailIndex *index, MailIndexRecord *rec);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
833bed942977673526c72e79bccc09314fc57104Phil Carmody /* Updating fields happens by calling update_begin(), one or more
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch update_field()s and finally update_end() which does the actual
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch updating. The index must be exclusively locked all this time.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch update_begin() and update_field() functions cannot fail.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch The extra_space parameter for update_field() specifies the amount
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch of extra empty space we should leave after the value, so that if
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch the field grows in future it could be expanded without copying it
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch to end of file. When the field already exists, the extra_space
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch is ignored.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch The files may not actually be updated until after you've unlocked
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch the file. */
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen MailIndexUpdate *(*update_begin)(MailIndex *index,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch MailIndexRecord *rec);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*update_end)(MailIndexUpdate *update);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen void (*update_field)(MailIndexUpdate *update, MailField field,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const char *value, size_t extra_space);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Just remember that full_field_size will be MEM_ALIGNed, so
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch it may differer from the given size parameter. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch void (*update_field_raw)(MailIndexUpdate *update, MailField field,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const void *value, size_t size);
711e8e4c5c5d702dfa062f42a1ede5de14c151c9Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Returns last error message */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const char *(*get_last_error)(MailIndex *index);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* Returns TRUE if last error was because we ran out of available
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch disk space. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*is_diskspace_error)(MailIndex *index);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Returns TRUE if index is now in inconsistent state with the
b37e11d37fb1ebf50511eef5d9d96d1205818458Stephan Bosch previous known state, meaning that the message IDs etc. may
b37e11d37fb1ebf50511eef5d9d96d1205818458Stephan Bosch have changed - only way to recover this would be to fully close
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch the mailbox and reopen it. With IMAP connection this would mean
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch a forced disconnection since we can't do forced CLOSE. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int (*is_inconsistency_error)(MailIndex *index);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* private: */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch MailIndexData *data;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch MailTree *tree;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch MailModifyLog *modifylog;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch MailCustomFlags *custom_flags;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch char *dir; /* directory where to place the index files */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch char *filepath; /* index file path */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int indexid;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int sync_id;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch char *mbox_path; /* mbox-specific path to the actual mbox file */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch uoff_t mbox_size; /* last synced size of mbox file */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch int mbox_fd;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen int mbox_locks;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen int mbox_lock_type;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen int fd; /* opened index file */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch char *error; /* last error message */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen void *mmap_base;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen size_t mmap_used_length;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen size_t mmap_full_length;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen MailLockType lock_type;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen MailIndexHeader *header;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen unsigned int first_recent_uid;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen unsigned int modifylog_id;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen time_t file_sync_stamp;
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* these fields are OR'ed to the fields in index header once we
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch get around grabbing exclusive lock */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int set_flags;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int set_cache_fields;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int anon_mmap:1;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int opened:1;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int inconsistent:1;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int nodiskspace:1;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch};
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch/* needed to remove annoying warnings about not initializing all struct
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch members.. */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch#define MAIL_INDEX_PRIVATE_FILL \
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch 0, 0, 0, 0, 0, 0, 0, 0, 0 \
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch/* defaults - same as above but prefixed with mail_index_. */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Boschint mail_index_open(MailIndex *index, int update_recent, int fast);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Boschint mail_index_open_or_create(MailIndex *index, int update_recent, int fast);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Boschint mail_index_set_lock(MailIndex *index, MailLockType lock_type);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Boschint mail_index_try_lock(MailIndex *index, MailLockType lock_type);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Boschint mail_index_fsck(MailIndex *index);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan BoschMailIndexHeader *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,
unsigned int *seq_r);
const char *mail_index_lookup_field(MailIndex *index, MailIndexRecord *rec,
MailField field);
const void *mail_index_lookup_field_raw(MailIndex *index, MailIndexRecord *rec,
MailField field, size_t *size);
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_begin(MailIndex *index, MailIndexRecord **rec);
int mail_index_append_end(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, size_t extra_space);
void mail_index_update_field_raw(MailIndexUpdate *update, MailField field,
const void *value, size_t size);
const char *mail_index_get_last_error(MailIndex *index);
int mail_index_is_diskspace_error(MailIndex *index);
int mail_index_is_inconsistency_error(MailIndex *index);
/* INTERNAL: */
int mail_index_mmap_update(MailIndex *index);
void mail_index_init_header(MailIndexHeader *hdr);
void mail_index_close(MailIndex *index);
int mail_index_fmsync(MailIndex *index, size_t size);
int mail_index_verify_hole_range(MailIndex *index);
void mail_index_mark_flag_changes(MailIndex *index, MailIndexRecord *rec,
MailFlags old_flags, MailFlags new_flags);
void mail_index_update_headers(MailIndexUpdate *update, IBuffer *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);
int mail_index_truncate(MailIndex *index);
/* Max. mmap()ed size for a message */
#define MAIL_MMAP_BLOCK_SIZE (1024*256)
/* Delete unused non-local temp files after 24h. Just to be sure we don't
delete it too early. The temp files don't harm much anyway. */
#define TEMP_FILE_TIMEOUT (60*24)
/* number of records to always keep allocated in index file,
either used or unused */
#define INDEX_MIN_RECORDS_COUNT 64
/* when empty space in index file gets full, grow the file n% larger */
#define INDEX_GROW_PERCENTAGE 10
/* ftruncate() the index file when only n% of it is in use */
#define INDEX_TRUNCATE_PERCENTAGE 30
/* don't truncate whole file anyway, keep n% of the empty space */
#define INDEX_TRUNCATE_KEEP_PERCENTAGE 10
/* Compress the file when deleted space reaches n% of total size */
#define INDEX_COMPRESS_PERCENTAGE 50
/* uoff_t to index file for given record */
#define INDEX_FILE_POSITION(index, ptr) \
((uoff_t) ((char *) (ptr) - (char *) ((index)->mmap_base)))
/* index number for uoff_t position */
#define INDEX_POSITION_INDEX(pos) \
(((pos) - sizeof(MailIndexHeader)) / sizeof(MailIndexRecord))
/* index number for given record */
#define INDEX_RECORD_INDEX(index, ptr) \
INDEX_POSITION_INDEX(INDEX_FILE_POSITION(index, ptr))
/* mark the index corrupted */
#define INDEX_MARK_CORRUPTED(index) \
STMT_START { (index)->set_flags |= MAIL_INDEX_FLAG_REBUILD; } STMT_END
/* get number of records in mmaped index */
#define MAIL_INDEX_RECORD_COUNT(index) \
((index->mmap_used_length - sizeof(MailIndexHeader)) / \
sizeof(MailIndexRecord))
/* minimum size for index file */
#define INDEX_FILE_MIN_SIZE \
(sizeof(MailIndexHeader) + \
INDEX_MIN_RECORDS_COUNT * sizeof(MailIndexRecord))
#endif