mail-index.h revision 1cfc39f5c151f51b554811336baede97c5a82c02
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 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 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 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 /* 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 (((field) & (FIELD_TYPE_FROM | FIELD_TYPE_TO | FIELD_TYPE_CC | \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (((field) & (FIELD_TYPE_BODY|FIELD_TYPE_BODYSTRUCTURE| \
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef enum {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailCustomFlags MailCustomFlags;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexHeader MailIndexHeader;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexDataHeader MailIndexDataHeader;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexRecord MailIndexRecord;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexDataRecord MailIndexDataRecord;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschtypedef struct _MailIndexUpdate MailIndexUpdate;
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen /* 0 = version
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 unsigned int indexid;
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int sync_id; /* re-mmap() when changed, required only
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch if file size is changed */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch unsigned int flags;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* these UIDs may not exist and may not even be unseen */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int indexid;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int reserved; /* for alignment mostly */
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 index_flags; /* MailIndexMailFlags */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch uoff_t body_size; /* if header_size == 0, the size of full message */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch char data[MEM_ALIGN_SIZE]; /* variable size */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE)
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size)
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);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Free index from memory. */
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 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 /* 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 /* 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 /* Verify that the index is valid. If anything invalid is found,
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch rebuild() is called. Same locking issues as with rebuild(). */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* Synchronize the index with the mailbox. Same locking issues as
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch with rebuild(). */
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);
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 /* 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 /* Find first existing UID in range. */
711e8e4c5c5d702dfa062f42a1ede5de14c151c9Stephan Bosch MailIndexRecord *(*lookup_uid_range)(MailIndex *index,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int *seq_r);
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 /* 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 /* 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 /* 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 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 /* 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 /* 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);
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 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 The files may not actually be updated until after you've unlocked
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen MailIndexUpdate *(*update_begin)(MailIndex *index,
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen void (*update_field)(MailIndexUpdate *update, MailField field,
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 /* Returns last error message */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const char *(*get_last_error)(MailIndex *index);
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* Returns TRUE if last error was because we ran out of available
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch disk space. */
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/* private: */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch char *dir; /* directory where to place the index files */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int indexid;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch unsigned int sync_id;
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 /* these fields are OR'ed to the fields in index header once we
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch get around grabbing exclusive lock */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch/* needed to remove annoying warnings about not initializing all struct
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/* 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 BoschMailIndexHeader *mail_index_get_header(MailIndex *index);
unsigned int first_uid,
unsigned int last_uid,
unsigned int *seq_r);
int external_change);
sizeof(MailIndexRecord))
#define INDEX_FILE_MIN_SIZE \
(sizeof(MailIndexHeader) + \