mail-index.h revision 7c424aa51c956c628e3512055841aa2f9eef4833
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync#ifndef __MAIL_INDEX_H
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync#define __MAIL_INDEX_H
2291faee92ebb5cc9722cd3f22e499900a5a411fvboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync#include "message-parser.h"
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync#include "imap-util.h"
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync#define MAIL_INDEX_VERSION 2
c58f1213e628a545081c70e26c6b67a841cff880vboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync#define INDEX_FILE_PREFIX ".imap.index"
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsyncenum mail_index_header_compat {
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync};
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsyncenum mail_index_header_flag {
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync /* Rebuild flag is set while index is being rebuilt or when
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync some error is noticed in the index file. If this flag is set,
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync the index shouldn't be used before rebuilding it. */
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_REBUILD = 0x01,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_FSCK = 0x02,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_CACHE_FIELDS = 0x04,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_COMPRESS = 0x08,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_COMPRESS_DATA = 0x10,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_REBUILD_TREE = 0x20,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_DIRTY_MESSAGES = 0x40,
a7a663caa646c45104af01923df3d33f90d97886vboxsync MAIL_INDEX_FLAG_DIRTY_CUSTOMFLAGS = 0x80
a7a663caa646c45104af01923df3d33f90d97886vboxsync};
a7a663caa646c45104af01923df3d33f90d97886vboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsyncenum mail_data_field {
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync DATA_FIELD_LOCATION = 0x00000001,
a7a663caa646c45104af01923df3d33f90d97886vboxsync DATA_FIELD_ENVELOPE = 0x00000002,
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync DATA_FIELD_BODY = 0x00000004,
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync DATA_FIELD_BODYSTRUCTURE = 0x00000008,
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync DATA_FIELD_MD5 = 0x00000010,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_FIELD_MESSAGEPART = 0x00000020,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_FIELD_LAST = 0x00000040,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_FIELD_MAX_BITS = 6,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* separate from above, but in same bitmask */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_HDR_INTERNAL_DATE = 0x40000000,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_HDR_VIRTUAL_SIZE = 0x20000000,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_HDR_HEADER_SIZE = 0x10000000,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_HDR_BODY_SIZE = 0x08000000
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync};
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync#define IS_BODYSTRUCTURE_FIELD(field) \
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync (((field) & (DATA_FIELD_BODY | DATA_FIELD_BODYSTRUCTURE | \
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync DATA_FIELD_MESSAGEPART)) != 0)
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsyncenum mail_index_mail_flag {
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* If binary flags are set, it's not checked whether mail is
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync missing CRs. So this flag may be set as an optimization for
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync regular non-binary mails as well if it's known that it contains
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync valid CR+LF line breaks. */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync INDEX_MAIL_FLAG_BINARY_HEADER = 0x0001,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync INDEX_MAIL_FLAG_BINARY_BODY = 0x0002,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* Currently this means with mbox format that message flags have
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync been changed in index, but not written into mbox file yet. */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync INDEX_MAIL_FLAG_DIRTY = 0x0004
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync};
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsyncenum mail_lock_type {
3386691d38a0fc7b0fae76ff19e066b4d6a3a006vboxsync MAIL_LOCK_UNLOCK = 0,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_LOCK_SHARED,
3386691d38a0fc7b0fae76ff19e066b4d6a3a006vboxsync MAIL_LOCK_EXCLUSIVE
62bc9212c624818bce3d903ee1bdb644ec9a1cdevboxsync};
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsyncenum mail_lock_notify_type {
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* Mailbox is locked, will abort in secs_left */
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync /* Mailbox lock looks stale, will override in secs_left */
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync MAIL_LOCK_NOTIFY_MAILBOX_OVERRIDE,
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync /* Index is locked, will abort in secs_left */
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync MAIL_LOCK_NOTIFY_INDEX_ABORT
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync};
5a2e131a1a9fb4c80eb1ca75668b54428424083cvboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsyncenum mail_index_error {
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* No errors */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_INDEX_ERROR_NONE,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* Internal error, see get_error_text() for more information. */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_INDEX_ERROR_INTERNAL,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* Index is now in inconsistent state with the previous known state,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync meaning that the message IDs etc. may have changed - only way to
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync recover this would be to fully close the mailbox and reopen it.
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync With IMAP this would mean a forced disconnection since we can't do
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync forced CLOSE. */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_INDEX_ERROR_INCONSISTENT,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* We ran out of available disk space. */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_INDEX_ERROR_DISKSPACE,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* Mail index locking timeouted */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_INDEX_ERROR_INDEX_LOCK_TIMEOUT,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* Mailbox locking timeouted */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync MAIL_INDEX_ERROR_MAILBOX_LOCK_TIMEOUT
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync};
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsynctypedef void mail_lock_notify_callback_t(enum mail_lock_notify_type notify_type,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned int secs_left, void *context);
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsyncstruct mail_index_header {
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned char compat_data[8];
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync /* 0 = version
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync 1 = flags,
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync 2 = sizeof(unsigned int),
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync 3 = sizeof(time_t),
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync 4 = sizeof(uoff_t),
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync 5 = MEM_ALIGN_SIZE */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned int indexid;
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned int sync_id; /* re-mmap() when changed, required only
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync if file size is changed */
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned int flags;
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned int cache_fields;
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync uoff_t used_file_size;
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync
46ba5059f2c696c77edfa9d3dc3d018be2ac6952vboxsync unsigned int first_hole_index;
a5dc49f41d7d9497f8c5d7daade92867636a090bvboxsync unsigned int first_hole_records;
a5dc49f41d7d9497f8c5d7daade92867636a090bvboxsync
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync unsigned int uid_validity;
de15f08344cc532a6e75d2d8d99ae7ed461cb810vboxsync unsigned int next_uid;
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync unsigned int messages_count;
a7a663caa646c45104af01923df3d33f90d97886vboxsync unsigned int seen_messages_count;
a7a663caa646c45104af01923df3d33f90d97886vboxsync unsigned int deleted_messages_count;
9767480f4448c2c0371c6e78cff098cbf039b031vboxsync unsigned int last_nonrecent_uid;
a5dc49f41d7d9497f8c5d7daade92867636a090bvboxsync
a5dc49f41d7d9497f8c5d7daade92867636a090bvboxsync /* these UIDs may not exist and may not even be unseen */
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync unsigned int first_unseen_uid_lowwater;
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync unsigned int first_deleted_uid_lowwater;
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync};
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync
c02305690d8da93fff98b226ed11b78f69818f5dvboxsyncstruct mail_index_data_header {
a7a663caa646c45104af01923df3d33f90d97886vboxsync unsigned int indexid;
a7a663caa646c45104af01923df3d33f90d97886vboxsync unsigned int reserved; /* for alignment mostly */
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync
a5dc49f41d7d9497f8c5d7daade92867636a090bvboxsync uoff_t used_file_size;
a5dc49f41d7d9497f8c5d7daade92867636a090bvboxsync uoff_t deleted_space;
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync};
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync
395d92a7732aad3c0b9baecedfabba5113b84485vboxsyncstruct mail_index_record {
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync unsigned int uid;
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync unsigned int msg_flags; /* enum mail_flags */
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync unsigned int index_flags; /* enum mail_index_mail_flag */
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync unsigned int data_fields; /* enum mail_data_field */
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync
395d92a7732aad3c0b9baecedfabba5113b84485vboxsync uoff_t data_position;
a7a663caa646c45104af01923df3d33f90d97886vboxsync};
a7a663caa646c45104af01923df3d33f90d97886vboxsync
a7a663caa646c45104af01923df3d33f90d97886vboxsyncstruct mail_index_data_record_header {
a7a663caa646c45104af01923df3d33f90d97886vboxsync unsigned int data_size; /* including this header */
a7a663caa646c45104af01923df3d33f90d97886vboxsync
a7a663caa646c45104af01923df3d33f90d97886vboxsync time_t internal_date;
a7a663caa646c45104af01923df3d33f90d97886vboxsync uoff_t virtual_size;
a7a663caa646c45104af01923df3d33f90d97886vboxsync
a7a663caa646c45104af01923df3d33f90d97886vboxsync uoff_t header_size;
f38e48162bbc4bab2f74875339a027edbc187974vboxsync uoff_t body_size;
a7a663caa646c45104af01923df3d33f90d97886vboxsync};
a7a663caa646c45104af01923df3d33f90d97886vboxsync
a7a663caa646c45104af01923df3d33f90d97886vboxsyncstruct mail_index_data_record {
a7a663caa646c45104af01923df3d33f90d97886vboxsync unsigned int field; /* enum mail_data_field */
20fc4a350a4a8e56ffaac6cf57dcd677a7ac36c5vboxsync unsigned int full_field_size;
20fc4a350a4a8e56ffaac6cf57dcd677a7ac36c5vboxsync char data[MEM_ALIGN_SIZE]; /* variable size */
20fc4a350a4a8e56ffaac6cf57dcd677a7ac36c5vboxsync};
20fc4a350a4a8e56ffaac6cf57dcd677a7ac36c5vboxsync
206d5dc9a25e44ee35fd2a1abf4033ee004236cavboxsync#define SIZEOF_MAIL_INDEX_DATA \
206d5dc9a25e44ee35fd2a1abf4033ee004236cavboxsync (sizeof(struct mail_index_data_record) - MEM_ALIGN_SIZE)
206d5dc9a25e44ee35fd2a1abf4033ee004236cavboxsync
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync#define DATA_RECORD_SIZE(rec) \
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size)
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync
c02305690d8da93fff98b226ed11b78f69818f5dvboxsyncstruct mail_index {
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync /* If fast is TRUE, compressing and cache updates are not performed.
a7a663caa646c45104af01923df3d33f90d97886vboxsync Note that opening same index twice in the same process is a bad
a7a663caa646c45104af01923df3d33f90d97886vboxsync idea since they share the same file locks. As soon one of the
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync indexes is closed, the locks in second index are dropped which
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync especially hurts modify log since it keeps locks all the time. */
a7a663caa646c45104af01923df3d33f90d97886vboxsync int (*open)(struct mail_index *index, int update_recent, int fast);
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync int (*open_or_create)(struct mail_index *index,
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync int update_recent, int fast);
c02305690d8da93fff98b226ed11b78f69818f5dvboxsync
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync /* Free index from memory. */
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync void (*free)(struct mail_index *index);
a7a663caa646c45104af01923df3d33f90d97886vboxsync
a7a663caa646c45104af01923df3d33f90d97886vboxsync /* Lock/unlock index. May block. Note that unlocking must not
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync reset error from get_last_error() as unlocking can be done as
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync a cleanup after some other function failed. Index is always
a7a663caa646c45104af01923df3d33f90d97886vboxsync mmap()ed after set_lock() succeeds.
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync Trying to change a shared lock into exclusive lock is a fatal
5e1277c8dc1d5200d4c8721dfd05fc04ddd4f741vboxsync error, since it may create a deadlock. Even though operating
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync system should detect it and fail, it's not a good idea to even
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync let it happen. Better ways to do this would be to a) mark the
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync data to be updated later, b) use try_lock() if the update is
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync preferred but not required, c) unlock + lock again, but make
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync sure that won't create race conditions. */
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync int (*set_lock)(struct mail_index *index,
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync enum mail_lock_type lock_type);
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync /* Try locking the index. Returns TRUE if the lock was got and
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync FALSE if lock isn't possible to get currently or some other error
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync occured. Never blocks. */
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync int (*try_lock)(struct mail_index *index,
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync enum mail_lock_type lock_type);
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync /* If we have to wait for the lock, the given lock notify function
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync is called once in a while. */
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync void (*set_lock_notify_callback)(struct mail_index *index,
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync mail_lock_notify_callback_t *callback,
ea2a3d970d6ff3c9c7c46066041dffb29185be8evboxsync void *context);
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync
4a5bd21592a01e05ffecea23584c4e8f0a36f6acvboxsync /* Rebuild the whole index. Note that this changes the indexid
so all the other files must also be rebuilt after this call.
Index MUST NOT have shared lock, but exclusive lock or no lock at
all is fine. Note that this function may leave the index
exclusively locked, and always sets index->inconsistent = TRUE. */
int (*rebuild)(struct mail_index *index);
/* Verify that the index is valid. If anything invalid is found,
index is set inconsistent and to be rebuilt at next open.
Same locking issues as with rebuild(). */
int (*fsck)(struct mail_index *index);
/* Synchronize the index with the mailbox. Index must not have shared
lock when calling this function. The data_lock_type specifies what
lock should be set to data file (mbox file). This function may
leave the index in ANY locking state. If changes is non-NULL, it's
set to TRUE if any changes were noticed. */
int (*sync_and_lock)(struct mail_index *index,
enum mail_lock_type data_lock_type, int *changes);
/* Returns the index header (never fails). The index needs to be
locked before calling this function, and must be kept locked as
long as you keep using the returned structure. */
struct mail_index_header *(*get_header)(struct mail_index *index);
/* sequence -> data lookup. The index needs to be locked before calling
this function, and must be kept locked as long as you keep using
the returned structure. */
struct mail_index_record *(*lookup)(struct mail_index *index,
unsigned int seq);
/* Return the next record after specified record, or NULL if it was
last record. The index must be locked all the time between
lookup() and last next() call. */
struct mail_index_record *(*next)(struct mail_index *index,
struct mail_index_record *rec);
/* Find first existing UID in range. Sequence number is also retrieved
if seq_r is non-NULL. */
struct mail_index_record *(*lookup_uid_range)(struct mail_index *index,
unsigned int first_uid,
unsigned int last_uid,
unsigned int *seq_r);
/* Find field from specified record, or NULL if it's not in index.
Makes sure that the field ends with \0. */
const char *(*lookup_field)(struct mail_index *index,
struct mail_index_record *rec,
enum mail_data_field field);
/* Find field from specified record, or NULL if it's not in index. */
const void *(*lookup_field_raw)(struct mail_index *index,
struct mail_index_record *rec,
enum mail_data_field field,
size_t *size);
/* Mark the fields to be cached later. If any of them is already
set in hdr->cache_fields, mark the caching to happen next time
index is opened. */
void (*cache_fields_later)(struct mail_index *index,
enum mail_data_field field);
/* Open mail file and return it as mmap()ed IStream. If we fail,
we return NULL and set deleted = TRUE if failure was because the
mail was just deleted (ie. not an error). internal_date is set
if it's non-NULL. */
struct istream *(*open_mail)(struct mail_index *index,
struct mail_index_record *rec,
time_t *internal_date, int *deleted);
/* Returns internal date of message, or (time_t)-1 if error occured. */
time_t (*get_internal_date)(struct mail_index *index,
struct mail_index_record *rec);
/* Expunge a mail from index. Tree 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)(struct mail_index *index, struct mail_index_record *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)(struct mail_index *index,
struct mail_index_record *rec,
unsigned int seq, enum mail_flags flags,
int external_change);
/* Append a new record to index. The index must be exclusively
locked before calling this function. rec->uid is updated in
append_end(). */
struct mail_index_record *(*append_begin)(struct mail_index *index);
int (*append_end)(struct mail_index *index,
struct mail_index_record *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. */
struct mail_index_update *
(*update_begin)(struct mail_index *index,
struct mail_index_record *rec);
int (*update_end)(struct mail_index_update *update);
void (*update_field)(struct mail_index_update *update,
enum mail_data_field field,
const char *value, size_t extra_space);
/* Just remember that full_field_size will be MEM_ALIGNed, so
it may differer from the given size parameter. */
void (*update_field_raw)(struct mail_index_update *update,
enum mail_data_field field,
const void *value, size_t size);
/* Returns the last error code. */
enum mail_index_error (*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 *(*get_last_error_text)(struct mail_index *index);
/* private: */
struct mail_index_data *data;
struct mail_tree *tree;
struct mail_modify_log *modifylog;
struct mail_custom_flags *custom_flags;
char *dir; /* directory where to place the index files */
char *filepath; /* index file path */
char *mailbox_path; /* file/directory for mailbox location */
enum mail_data_field default_cache_fields, never_cache_fields;
unsigned int indexid;
unsigned int sync_id;
/* updated whenever exclusive lock is set/unset */
unsigned int excl_lock_counter;
int mbox_fd;
struct istream *mbox_stream;
enum mail_lock_type mbox_lock_type;
dev_t mbox_dotlock_dev;
ino_t mbox_dotlock_ino;
/* these counters can be used to check that we've synced the mailbox
after locking it */
unsigned int mbox_lock_counter;
unsigned int mbox_sync_counter;
/* last mbox sync: */
uoff_t mbox_size;
dev_t mbox_dev;
ino_t mbox_ino;
int fd; /* opened index file */
char *error; /* last error message */
void *mmap_base;
size_t mmap_used_length;
size_t mmap_full_length;
struct mail_index_header *header;
enum mail_lock_type lock_type;
time_t file_sync_stamp;
unsigned int first_recent_uid;
mail_lock_notify_callback_t *lock_notify_cb;
void *lock_notify_context;
/* these fields are OR'ed to the fields in index header once we
get around grabbing exclusive lock */
unsigned int set_flags;
enum mail_data_field set_cache_fields;
unsigned int anon_mmap:1;
unsigned int opened:1;
unsigned int mail_read_mmaped:1;
unsigned int inconsistent:1;
unsigned int nodiskspace:1;
unsigned int index_lock_timeout:1;
unsigned int mailbox_lock_timeout:1;
};
#ifdef DEV_T_STRUCT
/* we can't initialize dev_t as 0, and we don't know what it actually
contains, so don't initialize them. gcc's -W option should be disabled
with this or we get warnings.. */
# define MAIL_INDEX_PRIVATE_FILL 0
#else
/* 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, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0
#endif
/* defaults - same as above but prefixed with mail_index_. */
int mail_index_open(struct mail_index *index, int update_recent, int fast);
int mail_index_open_or_create(struct mail_index *index,
int update_recent, int fast);
int mail_index_set_lock(struct mail_index *index,
enum mail_lock_type lock_type);
int mail_index_try_lock(struct mail_index *index,
enum mail_lock_type lock_type);
void mail_index_set_lock_notify_callback(struct mail_index *index,
mail_lock_notify_callback_t *callback,
void *context);
int mail_index_fsck(struct mail_index *index);
struct mail_index_header *mail_index_get_header(struct mail_index *index);
struct mail_index_record *mail_index_lookup(struct mail_index *index,
unsigned int seq);
struct mail_index_record *mail_index_next(struct mail_index *index,
struct mail_index_record *rec);
struct mail_index_record *
mail_index_lookup_uid_range(struct mail_index *index, unsigned int first_uid,
unsigned int last_uid, unsigned int *seq_r);
const char *mail_index_lookup_field(struct mail_index *index,
struct mail_index_record *rec,
enum mail_data_field field);
const void *mail_index_lookup_field_raw(struct mail_index *index,
struct mail_index_record *rec,
enum mail_data_field field,
size_t *size);
void mail_index_cache_fields_later(struct mail_index *index,
enum mail_data_field field);
int mail_index_expunge(struct mail_index *index, struct mail_index_record *rec,
unsigned int seq, int external_change);
int mail_index_update_flags(struct mail_index *index,
struct mail_index_record *rec,
unsigned int seq, enum mail_flags flags,
int external_change);
struct mail_index_record *mail_index_append_begin(struct mail_index *index);
int mail_index_append_end(struct mail_index *index,
struct mail_index_record *rec);
struct mail_index_update *
mail_index_update_begin(struct mail_index *index,
struct mail_index_record *rec);
int mail_index_update_end(struct mail_index_update *update);
void mail_index_update_field(struct mail_index_update *update,
enum mail_data_field field,
const char *value, size_t extra_space);
void mail_index_update_field_raw(struct mail_index_update *update,
enum mail_data_field field,
const void *value, size_t size);
time_t mail_get_internal_date(struct mail_index *index,
struct mail_index_record *rec);
enum mail_index_error mail_index_get_last_error(struct mail_index *index);
const char *mail_index_get_last_error_text(struct mail_index *index);
/* INTERNAL: */
void mail_index_init(struct mail_index *index, const char *dir);
int mail_index_mmap_update(struct mail_index *index);
void mail_index_init_header(struct mail_index *index,
struct mail_index_header *hdr);
void mail_index_close(struct mail_index *index);
int mail_index_fmdatasync(struct mail_index *index, size_t size);
int mail_index_verify_hole_range(struct mail_index *index);
void mail_index_mark_flag_changes(struct mail_index *index,
struct mail_index_record *rec,
enum mail_flags old_flags,
enum mail_flags new_flags);
void mail_index_update_headers(struct mail_index_update *update,
struct istream *input,
enum mail_data_field cache_fields,
message_header_callback_t *header_cb,
void *context);
int mail_index_update_cache(struct mail_index *index);
int mail_index_compress(struct mail_index *index);
int mail_index_compress_data(struct mail_index *index);
int mail_index_truncate(struct mail_index *index);
/* Maximum allowed UID number. */
#define MAX_ALLOWED_UID 4294967295U /* 2^32 - 1 */
/* Max. mmap()ed size for a message */
#define MAIL_MMAP_BLOCK_SIZE (1024*256)
/* Block size when read()ing message. */
#define MAIL_READ_BLOCK_SIZE (1024*8)
/* 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)))
/* record for given index */
#define INDEX_RECORD_AT(index, idx) \
((struct mail_index_record *) \
((char *) index->mmap_base + sizeof(struct mail_index_header)) + (idx))
/* returns the next record after last one */
#define INDEX_END_RECORD(index) \
((struct mail_index_record *) \
((char *) (index)->mmap_base + (index)->mmap_used_length))
/* index number for uoff_t position */
#define INDEX_POSITION_INDEX(pos) \
(((pos) - sizeof(struct mail_index_header)) / \
sizeof(struct mail_index_record))
/* 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(struct mail_index_header)) / \
sizeof(struct mail_index_record))
/* minimum size for index file */
#define INDEX_FILE_MIN_SIZE \
(sizeof(struct mail_index_header) + \
INDEX_MIN_RECORDS_COUNT * sizeof(struct mail_index_record))
/* enum mail_lock_type to fcntl() lock type */
#define MAIL_LOCK_TO_FLOCK(lock_type) \
((lock_type) == MAIL_LOCK_EXCLUSIVE ? F_WRLCK : \
(lock_type) == MAIL_LOCK_SHARED ? F_RDLCK : F_UNLCK)
#endif