1 #ifndef MAIL_INDEX_H 2 #define MAIL_INDEX_H 3 4 #include "file-lock.h" 5 #include "fsync-mode.h" 6 #include "guid.h" 7 #include "mail-types.h" 8 #include "seq-range-array.h" 9 10 #define MAIL_INDEX_MAJOR_VERSION 7 11 #define MAIL_INDEX_MINOR_VERSION 3 12 13 #define MAIL_INDEX_HEADER_MIN_SIZE 120 14 15 /* Log a warning when transaction log has been locked for this many seconds. 16 This lock is held also between mail_index_sync_begin()..commit(). */ 17 #define MAIL_TRANSACTION_LOG_LOCK_WARN_SECS 30 18 19 enum mail_index_open_flags { 20 /* Create index if it doesn't exist */ 21 MAIL_INDEX_OPEN_FLAG_CREATE = 0x01, 22 /* Don't try to mmap() index files */ 23 MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE = 0x04, 24 /* Rely on O_EXCL when creating dotlocks */ 25 MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL = 0x10, 26 /* Flush NFS attr/data/write cache when necessary */ 27 MAIL_INDEX_OPEN_FLAG_NFS_FLUSH = 0x40, 28 /* Open the index read-only */ 29 MAIL_INDEX_OPEN_FLAG_READONLY = 0x80, 30 /* Create backups of dovecot.index files once in a while */ 31 MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS = 0x100, 32 /* If we run out of disk space, fail modifications instead of moving 33 indexes to memory. */ 34 MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY = 0x200, 35 /* We're only going to save new messages to the index. 36 Avoid unnecessary reads. */ 37 MAIL_INDEX_OPEN_FLAG_SAVEONLY = 0x400, 38 /* Enable debug logging */ 39 MAIL_INDEX_OPEN_FLAG_DEBUG = 0x800, 40 /* MAIL_INDEX_MAIL_FLAG_DIRTY can be used as a backend-specific flag. 41 All special handling of the flag is disabled by this. */ 42 MAIL_INDEX_OPEN_FLAG_NO_DIRTY = 0x1000, 43 }; 44 45 enum mail_index_header_compat_flags { 46 /* All fields in these index files are in little-endian format. 47 If the current CPU endianess doesn't match this, the indexes can't 48 be used. There is currently no support to translate endianess. */ 49 MAIL_INDEX_COMPAT_LITTLE_ENDIAN = 0x01 50 }; 51 52 enum mail_index_header_flag { 53 /* mail_index_mark_corrupted() was just called by this process. 54 Reopen or recreate it. This flag is never actually written to 55 disk. */ 56 MAIL_INDEX_HDR_FLAG_CORRUPTED = 0x0001, 57 /* There are messages with MAIL_INDEX_MAIL_FLAG_DIRTY flag. */ 58 MAIL_INDEX_HDR_FLAG_HAVE_DIRTY = 0x0002, 59 /* Index has been fsck'd. The caller may want to resync the index 60 to make sure it's valid and drop this flag. */ 61 MAIL_INDEX_HDR_FLAG_FSCKD = 0x0004, 62 }; 63 64 enum mail_index_mail_flags { 65 /* This flag used to contain MAIL_RECENT flag, but is always zero 66 with the current index file format. */ 67 MAIL_INDEX_MAIL_FLAG_UNUSED = 0x20, 68 /* For private use by backend. Replacing flags doesn't change this. */ 69 MAIL_INDEX_MAIL_FLAG_BACKEND = 0x40, 70 /* Message flags haven't been written to backend. If 71 MAIL_INDEX_OPEN_FLAG_NO_DIRTY is set, this is treated as a 72 backend-specific flag with no special internal handling. */ 73 MAIL_INDEX_MAIL_FLAG_DIRTY = 0x80, 74 75 /* Force updating this message's modseq via a flag update record. 76 Note that this flag isn't saved to disk. */ 77 MAIL_INDEX_MAIL_FLAG_UPDATE_MODSEQ = 0x100 78 }; 79 80 #define MAIL_INDEX_FLAGS_MASK \ 81 (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DELETED | MAIL_SEEN | MAIL_DRAFT) 82 83 struct mail_index_header { 84 /* Major version is increased only when you can't have backwards 85 compatibility. If the field doesn't match MAIL_INDEX_MAJOR_VERSION, 86 don't even try to read it. */ 87 uint8_t major_version; 88 /* Minor version is increased when the file format changes in a 89 backwards compatible way. If the field is smaller than 90 MAIL_INDEX_MINOR_VERSION, upgrade the file format and update the 91 minor_version field as well. If minor_version is higher than 92 MAIL_INDEX_MINOR_VERSION, leave it as it is. It likely means that a 93 new Dovecot version is currently being upgraded to, but the file was 94 still accessed by an old version. */ 95 uint8_t minor_version; 96 97 /* sizeof(struct mail_index_header) when creating a new index. If the 98 header is smaller, fill the missing fields with 0. If the header is 99 larger, preserve the size and unknown fields. */ 100 uint16_t base_header_size; 101 uint32_t header_size; /* base + extended header size */ 102 /* sizeof(struct mail_index_record) + extensions */ 103 uint32_t record_size; 104 105 uint8_t compat_flags; /* enum mail_index_header_compat_flags */ 106 uint8_t unused[3]; 107 108 /* Unique index file ID. Initialized with the current UNIX timestamp. 109 This is used to make sure that the main index, transaction log and 110 cache file are all part of the same index. */ 111 uint32_t indexid; 112 uint32_t flags; /* enum mail_index_header_flag */ 113 114 /* IMAP UIDVALIDITY. Initially can be 0, but must be non-0 after the 115 first mailbox sync. The UIDVALIDITY shouldn't normally change after 116 the mailbox is created. */ 117 uint32_t uid_validity; 118 /* UID for the next saved message (must not be lower than this). This 119 value can only increase. */ 120 uint32_t next_uid; 121 122 /* Number of messages in the index */ 123 uint32_t messages_count; 124 uint32_t unused_old_recent_messages_count; 125 /* Number of messages with MAIL_SEEN flag */ 126 uint32_t seen_messages_count; 127 /* Number of messages with MAIL_DELETED flag */ 128 uint32_t deleted_messages_count; 129 130 /* The specified UID and all mails after it have MAIL_RECENT flag */ 131 uint32_t first_recent_uid; 132 /* There are no UIDs lower than this without MAIL_SEEN flag. There are 133 no guarantees whether this UID has MAIL_SEEN flag, or whether the it 134 even exists. Used to optimize finding the first unseen message. */ 135 uint32_t first_unseen_uid_lowwater; 136 /* Similarly to above, used to optimize finding the first deleted 137 message. */ 138 uint32_t first_deleted_uid_lowwater; 139 140 /* The index is synced up to this log_file_seq and 141 log_file_head_offset. However, non-external transaction records 142 between tail_offset..head_offset haven't been synced to the 143 mailbox yet. For example there may be pending expunges or flag 144 changes, which will be synced on the next mail_index_sync_*() 145 calls. */ 146 uint32_t log_file_seq; 147 uint32_t log_file_tail_offset; 148 uint32_t log_file_head_offset; 149 150 uint32_t unused_old_sync_size_part1; 151 /* Timestamp of when .log was rotated into .log.2. This can be used to 152 optimize checking when it's time to unlink it without stat()ing it. 153 0 = unknown, -1 = .log.2 doesn't exists. */ 154 uint32_t log2_rotate_time; 155 /* Timestamp when the mailbox backend-specific code last checked 156 whether there are old temporary files (left by crashes) that should 157 be deleted. 0 = unknown. */ 158 uint32_t last_temp_file_scan; 159 160 /* UNIX timestamp to the beginning of the day (in server's local 161 timezone) when new messages were last added to the index file. */ 162 uint32_t day_stamp; 163 /* These fields are updated when day_stamp < today. The [0..6] are 164 first moved to [1..7], then [0] is set to the first appended UID. So 165 they contain the first UID of the day for last 8 days when messages 166 were appended. 167 168 These are used by cache purging to decide when to drop 169 MAIL_CACHE_DECISION_TEMP fields. */ 170 uint32_t day_first_uid[8]; 171 }; 172 173 #define MAIL_INDEX_RECORD_MIN_SIZE (sizeof(uint32_t) + sizeof(uint8_t)) 174 struct mail_index_record { 175 uint32_t uid; 176 uint8_t flags; /* enum mail_flags | enum mail_index_mail_flags */ 177 }; 178 179 struct mail_keywords { 180 struct mail_index *index; 181 unsigned int count; 182 int refcount; 183 184 /* variable sized list of keyword indexes */ 185 unsigned int idx[FLEXIBLE_ARRAY_MEMBER]; 186 }; 187 188 enum mail_index_transaction_flags { 189 /* If transaction is marked as hidden, the changes are marked with 190 hidden=TRUE when the view is synchronized. */ 191 MAIL_INDEX_TRANSACTION_FLAG_HIDE = 0x01, 192 /* External transactions describe changes to mailbox that have already 193 happened. */ 194 MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL = 0x02, 195 /* Don't add flag updates unless they actually change something. 196 This is reliable only when syncing, otherwise someone else might 197 have already committed a transaction that had changed the flags. */ 198 MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES = 0x04, 199 /* fsync() this transaction (unless fsyncs are disabled) */ 200 MAIL_INDEX_TRANSACTION_FLAG_FSYNC = 0x08, 201 /* Sync transaction describes changes to mailbox that already happened 202 to another mailbox with whom we're syncing with (dsync) */ 203 MAIL_INDEX_TRANSACTION_FLAG_SYNC = 0x10 204 }; 205 206 enum mail_index_sync_type { 207 MAIL_INDEX_SYNC_TYPE_EXPUNGE = 0x02, 208 MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04, 209 MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD = 0x08, 210 MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE = 0x10 211 }; 212 213 enum mail_index_fsync_mask { 214 MAIL_INDEX_FSYNC_MASK_APPENDS = 0x01, 215 MAIL_INDEX_FSYNC_MASK_EXPUNGES = 0x02, 216 MAIL_INDEX_FSYNC_MASK_FLAGS = 0x04, 217 MAIL_INDEX_FSYNC_MASK_KEYWORDS = 0x08 218 }; 219 220 enum mail_index_sync_flags { 221 /* Resync all dirty messages' flags. */ 222 MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY = 0x01, 223 /* Drop recent flags from all messages */ 224 MAIL_INDEX_SYNC_FLAG_DROP_RECENT = 0x02, 225 /* Create the transaction with AVOID_FLAG_UPDATES flag */ 226 MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES = 0x04, 227 /* If there are no new transactions and nothing else to do, 228 return 0 in mail_index_sync_begin() */ 229 MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES = 0x08, 230 /* Create the transaction with FSYNC flag */ 231 MAIL_INDEX_SYNC_FLAG_FSYNC = 0x10, 232 /* If we see "delete index" request transaction, finish it. 233 This flag also allows committing more changes to a deleted index. */ 234 MAIL_INDEX_SYNC_FLAG_DELETING_INDEX = 0x20, 235 /* Same as MAIL_INDEX_SYNC_FLAG_DELETING_INDEX, but finish index 236 deletion only once and fail the rest (= avoid race conditions when 237 multiple processes try to mark the index deleted) */ 238 MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX = 0x40, 239 /* Update header's tail_offset to head_offset, even if it's the only 240 thing we do and there's no strict need for it. */ 241 MAIL_INDEX_SYNC_FLAG_UPDATE_TAIL_OFFSET = 0x80 242 }; 243 244 enum mail_index_view_sync_flags { 245 /* Don't sync expunges */ 246 MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES = 0x01, 247 /* Make sure view isn't inconsistent after syncing. This also means 248 that you don't care about view_sync_next()'s output, so it won't 249 return anything. */ 250 MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT = 0x02, 251 /* Indicate that this is a secondary view, this can be used to indicate 252 that inconsistencies can be expected and if found should be fixed 253 by fully syncing. */ 254 MAIL_INDEX_VIEW_SYNC_FLAG_2ND_INDEX = 0x04, 255 }; 256 257 struct mail_index_sync_rec { 258 uint32_t uid1, uid2; 259 enum mail_index_sync_type type; 260 261 /* MAIL_INDEX_SYNC_TYPE_FLAGS: */ 262 uint8_t add_flags; 263 uint8_t remove_flags; 264 265 /* MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD, .._REMOVE: */ 266 unsigned int keyword_idx; 267 268 /* MAIL_INDEX_SYNC_TYPE_EXPUNGE: */ 269 guid_128_t guid_128; 270 }; 271 272 enum mail_index_view_sync_type { 273 /* Flags or keywords changed */ 274 MAIL_INDEX_VIEW_SYNC_TYPE_FLAGS = 0x01, 275 MAIL_INDEX_VIEW_SYNC_TYPE_MODSEQ = 0x02 276 }; 277 278 struct mail_index_view_sync_rec { 279 uint32_t uid1, uid2; 280 enum mail_index_view_sync_type type; 281 282 /* TRUE if this was a hidden transaction. */ 283 bool hidden:1; 284 }; 285 286 enum mail_index_transaction_change { 287 MAIL_INDEX_TRANSACTION_CHANGE_APPEND = BIT(0), 288 MAIL_INDEX_TRANSACTION_CHANGE_EXPUNGE = BIT(1), 289 MAIL_INDEX_TRANSACTION_CHANGE_FLAGS = BIT(2), 290 MAIL_INDEX_TRANSACTION_CHANGE_KEYWORDS = BIT(3), 291 MAIL_INDEX_TRANSACTION_CHANGE_MODSEQ = BIT(4), 292 MAIL_INDEX_TRANSACTION_CHANGE_ATTRIBUTE = BIT(5), 293 294 MAIL_INDEX_TRANSACTION_CHANGE_OTHERS = BIT(30), 295 }; 296 297 struct mail_index_transaction_commit_result { 298 /* seq/offset points to end of transaction */ 299 uint32_t log_file_seq; 300 uoff_t log_file_offset; 301 /* number of bytes in the written transaction. 302 all of it was written to the same file. */ 303 uoff_t commit_size; 304 305 enum mail_index_transaction_change changes_mask; 306 unsigned int ignored_modseq_changes; 307 }; 308 309 struct mail_index_base_optimization_settings { 310 /* Rewrite the index when the number of bytes that needs to be read 311 from the .log on refresh is between these min/max values. */ 312 uoff_t rewrite_min_log_bytes; 313 uoff_t rewrite_max_log_bytes; 314 }; 315 316 struct mail_index_log_optimization_settings { 317 /* Rotate transaction log after it's a) min_size or larger and it was 318 created at least min_age_secs or b) larger than max_size. */ 319 uoff_t min_size; 320 uoff_t max_size; 321 unsigned int min_age_secs; 322 323 /* Delete .log.2 when it's older than log2_stale_secs. Don't be too 324 eager, because older files are useful for QRESYNC and dsync. */ 325 unsigned int log2_max_age_secs; 326 }; 327 328 struct mail_index_cache_optimization_settings { 329 /* Drop fields that haven't been accessed for n seconds */ 330 unsigned int unaccessed_field_drop_secs; 331 /* If cache record becomes larger than this, don't add it. */ 332 unsigned int record_max_size; 333 334 /* Maximum size for the cache file. Internally the limit is 1 GB. */ 335 uoff_t max_size; 336 /* Never purge the file if it's smaller than this */ 337 uoff_t purge_min_size; 338 /* Purge the file when n% of records are deleted */ 339 unsigned int purge_delete_percentage; 340 /* Purge the file when n% of rows contain continued rows. 341 For example 200% means that the record has 2 continued rows, i.e. 342 it exists in 3 separate segments in the cache file. */ 343 unsigned int purge_continued_percentage; 344 /* Purge the file when we need to follow more than n next_offsets to 345 find the latest cache header. */ 346 unsigned int purge_header_continue_count; 347 }; 348 349 struct mail_index_optimization_settings { 350 struct mail_index_base_optimization_settings index; 351 struct mail_index_log_optimization_settings log; 352 struct mail_index_cache_optimization_settings cache; 353 }; 354 355 struct mail_index; 356 struct mail_index_map; 357 struct mail_index_view; 358 struct mail_index_transaction; 359 struct mail_index_sync_ctx; 360 struct mail_index_view_sync_ctx; 361 362 struct mail_index *mail_index_alloc(struct event *parent_event, 363 const char *dir, const char *prefix); 364 void mail_index_free(struct mail_index **index); 365 366 /* Change .cache file's directory. */ 367 void mail_index_set_cache_dir(struct mail_index *index, const char *dir); 368 /* Specify how often to do fsyncs. If mode is FSYNC_MODE_OPTIMIZED, the mask 369 can be used to specify which transaction types to fsync. */ 370 void mail_index_set_fsync_mode(struct mail_index *index, enum fsync_mode mode, 371 enum mail_index_fsync_mask mask); 372 /* Try to set the index's permissions based on its index directory. Returns 373 TRUE if successful (directory existed), FALSE if mail_index_set_permissions() 374 should be called. */ 375 bool mail_index_use_existing_permissions(struct mail_index *index); 376 void mail_index_set_permissions(struct mail_index *index, 377 mode_t mode, gid_t gid, const char *gid_origin); 378 /* Set locking method and maximum time to wait for a lock 379 (UINT_MAX = default). */ 380 void mail_index_set_lock_method(struct mail_index *index, 381 enum file_lock_method lock_method, 382 unsigned int max_timeout_secs); 383 /* Override the default optimization-related settings. Anything set to 0 will 384 use the default. */ 385 void mail_index_set_optimization_settings(struct mail_index *index, 386 const struct mail_index_optimization_settings *set); 387 /* When creating a new index file or reseting an existing one, add the given 388 extension header data immediately to it. */ 389 void mail_index_set_ext_init_data(struct mail_index *index, uint32_t ext_id, 390 const void *data, size_t size); 391 392 /* Open index. Returns 1 if ok, 0 if index doesn't exist and CREATE flags 393 wasn't given, -1 if error. */ 394 int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags); 395 /* Open or create index. Returns 0 if ok, -1 if error. */ 396 int mail_index_open_or_create(struct mail_index *index, 397 enum mail_index_open_flags flags); 398 void mail_index_close(struct mail_index *index); 399 /* unlink() all the index files. */ 400 int mail_index_unlink(struct mail_index *index); 401 402 /* Returns TRUE if index is currently in memory. */ 403 bool mail_index_is_in_memory(struct mail_index *index); 404 /* Move the index into memory. Returns 0 if ok, -1 if error occurred. */ 405 int mail_index_move_to_memory(struct mail_index *index); 406 407 struct mail_cache *mail_index_get_cache(struct mail_index *index); 408 409 /* Refresh index so mail_index_lookup*() will return latest values. Note that 410 immediately after this call there may already be changes, so if you need to 411 rely on validity of the returned values, use some external locking for it. */ 412 int ATTR_NOWARN_UNUSED_RESULT 413 mail_index_refresh(struct mail_index *index); 414 415 /* View can be used to look into index. Sequence numbers inside view change 416 only when you synchronize it. The view acquires required locks 417 automatically, but you'll have to drop them manually. */ 418 struct mail_index_view * 419 mail_index_view_open(struct mail_index *index, 420 const char *source_filename, unsigned int source_linenum); 421 #define mail_index_view_open(index) \ 422 mail_index_view_open(index, __FILE__, __LINE__) 423 void mail_index_view_close(struct mail_index_view **view); 424 425 /* Returns the index for given view. */ 426 struct mail_index *mail_index_view_get_index(struct mail_index_view *view); 427 /* Returns number of mails in view. */ 428 uint32_t mail_index_view_get_messages_count(struct mail_index_view *view); 429 /* Returns TRUE if we lost track of changes for some reason. */ 430 bool mail_index_view_is_inconsistent(struct mail_index_view *view); 431 /* Returns TRUE if there are open transactions open for the view. */ 432 bool mail_index_view_have_transactions(struct mail_index_view *view); 433 434 /* Transaction has to be opened to be able to modify index. You can have 435 multiple transactions open simultaneously. Committed transactions won't 436 show up until you've synchronized the view. Expunges won't show up until 437 you've synchronized the mailbox (mail_index_sync_begin). */ 438 struct mail_index_transaction * 439 mail_index_transaction_begin(struct mail_index_view *view, 440 enum mail_index_transaction_flags flags); 441 int mail_index_transaction_commit(struct mail_index_transaction **t); 442 int mail_index_transaction_commit_full(struct mail_index_transaction **t, 443 struct mail_index_transaction_commit_result *result_r); 444 void mail_index_transaction_rollback(struct mail_index_transaction **t); 445 /* Discard all changes in the transaction. */ 446 void mail_index_transaction_reset(struct mail_index_transaction *t); 447 /* When committing transaction, drop flag/keyword updates for messages whose 448 mdoseq is larger than max_modseq. Save those messages' sequences to the 449 given array. */ 450 void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t, 451 uint64_t max_modseq, 452 ARRAY_TYPE(seq_range) *seqs); 453 454 /* Returns the view transaction was created for. */ 455 struct mail_index_view * 456 mail_index_transaction_get_view(struct mail_index_transaction *t); 457 /* Returns TRUE if the given sequence is being expunged in this transaction. */ 458 bool mail_index_transaction_is_expunged(struct mail_index_transaction *t, 459 uint32_t seq); 460 461 /* Returns a view containing the mailbox state after changes in transaction 462 are applied. The view can still be used after transaction has been 463 committed. */ 464 struct mail_index_view * 465 mail_index_transaction_open_updated_view(struct mail_index_transaction *t); 466 467 /* Begin synchronizing mailbox with index file. Returns 1 if ok, 468 0 if MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES is set and there's nothing to 469 sync, -1 if error. 470 471 mail_index_sync_next() returns all changes from previously committed 472 transactions which haven't yet been committed to the actual mailbox. 473 They're returned in ascending order and they never overlap (if we add more 474 sync types, then they might). You must go through all of them and update 475 the mailbox accordingly. 476 477 Changes done to the returned transaction are expected to describe the 478 mailbox's current state. 479 480 The returned view already contains all the changes (except expunge 481 requests). After applying sync records on top of backend flags they should 482 match flags in the view. If they don't, there have been external changes. 483 484 Returned expunges are treated as expunge requests. They're not really 485 removed from the index until you mark them expunged to the returned 486 transaction. If it's not possible to expunge the message (e.g. permission 487 denied), simply don't mark them expunged. 488 489 Returned sequence numbers describe the mailbox state at the beginning of 490 synchronization, ie. expunges don't affect them. */ 491 int mail_index_sync_begin(struct mail_index *index, 492 struct mail_index_sync_ctx **ctx_r, 493 struct mail_index_view **view_r, 494 struct mail_index_transaction **trans_r, 495 enum mail_index_sync_flags flags); 496 /* Like mail_index_sync_begin(), but returns 1 if OK and if index is already 497 synchronized up to the given log_file_seq+offset, the synchronization isn't 498 started and this function returns 0. This should be done when you wish to 499 sync your committed transaction instead of doing a full mailbox 500 synchronization. */ 501 int mail_index_sync_begin_to(struct mail_index *index, 502 struct mail_index_sync_ctx **ctx_r, 503 struct mail_index_view **view_r, 504 struct mail_index_transaction **trans_r, 505 uint32_t log_file_seq, uoff_t log_file_offset, 506 enum mail_index_sync_flags flags); 507 /* Returns TRUE if it currently looks like syncing would return changes. */ 508 bool mail_index_sync_have_any(struct mail_index *index, 509 enum mail_index_sync_flags flags); 510 /* Returns TRUE if it currently looks like syncing would return expunges. */ 511 bool mail_index_sync_have_any_expunges(struct mail_index *index); 512 /* Returns the log file seq+offsets for the area which this sync is handling. */ 513 void mail_index_sync_get_offsets(struct mail_index_sync_ctx *ctx, 514 uint32_t *seq1_r, uoff_t *offset1_r, 515 uint32_t *seq2_r, uoff_t *offset2_r); 516 /* Returns -1 if error, 0 if sync is finished, 1 if record was filled. */ 517 bool mail_index_sync_next(struct mail_index_sync_ctx *ctx, 518 struct mail_index_sync_rec *sync_rec); 519 /* Returns TRUE if there's more to sync. */ 520 bool mail_index_sync_have_more(struct mail_index_sync_ctx *ctx); 521 /* Returns TRUE if sync has any expunges to handle. */ 522 bool mail_index_sync_has_expunges(struct mail_index_sync_ctx *ctx); 523 /* Reset syncing to initial state after mail_index_sync_begin(), so you can 524 go through all the sync records again with mail_index_sync_next(). */ 525 void mail_index_sync_reset(struct mail_index_sync_ctx *ctx); 526 /* Update result when refreshing index at the end of sync. */ 527 void mail_index_sync_set_commit_result(struct mail_index_sync_ctx *ctx, 528 struct mail_index_transaction_commit_result *result); 529 /* Don't log a warning even if syncing took over 530 MAIL_TRANSACTION_LOG_LOCK_WARN_SECS seconds. Usually this is called because 531 the caller itself already logged a warning about it. */ 532 void mail_index_sync_no_warning(struct mail_index_sync_ctx *ctx); 533 /* If a warning is logged because syncing took over 534 MAIL_TRANSACTION_LOG_LOCK_WARN_SECS seconds, log this as the reason for the 535 syncing. */ 536 void mail_index_sync_set_reason(struct mail_index_sync_ctx *ctx, 537 const char *reason); 538 /* Commit synchronization by writing all changes to mail index file. */ 539 int mail_index_sync_commit(struct mail_index_sync_ctx **ctx); 540 /* Rollback synchronization - none of the changes listed by sync_next() are 541 actually written to index file. */ 542 void mail_index_sync_rollback(struct mail_index_sync_ctx **ctx); 543 544 /* Lock the index exclusively. This is the same locking as what happens when 545 syncing the index. It's not necessary to normally call this function, unless 546 doing something special such as rebuilding the index outside syncing. 547 Returns 0 on success, -1 if locking failed for any reason. */ 548 int mail_index_lock_sync(struct mail_index *index, const char *lock_reason); 549 /* Unlock the locked index. The index must have been locked previously with 550 mail_index_lock_sync(). If the lock had been kept for excessively long, 551 a warning is logged with the long_lock_reason. */ 552 void mail_index_unlock(struct mail_index *index, const char *long_lock_reason); 553 /* Returns TRUE if index is currently exclusively locked. */ 554 bool mail_index_is_locked(struct mail_index *index); 555 556 /* Mark index file corrupted in memory and delete it from disk. 557 Invalidates all views. This should be called only for index files that can 558 safely be recreated without any data loss. */ 559 void mail_index_mark_corrupted(struct mail_index *index); 560 /* Check and fix any found problems. Returns -1 if we couldn't lock for sync, 561 0 if everything went ok. */ 562 int mail_index_fsck(struct mail_index *index); 563 /* Returns TRUE if mail_index_fsck() has been called since the last 564 mail_index_reset_fscked() call. */ 565 bool mail_index_reset_fscked(struct mail_index *index); 566 567 /* Synchronize changes in view. You have to go through all records, or view 568 will be marked inconsistent. Only sync_mask type records are 569 synchronized. */ 570 struct mail_index_view_sync_ctx * 571 mail_index_view_sync_begin(struct mail_index_view *view, 572 enum mail_index_view_sync_flags flags); 573 bool mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx, 574 struct mail_index_view_sync_rec *sync_rec); 575 void 576 mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx, 577 const ARRAY_TYPE(seq_range) **expunges_r); 578 int mail_index_view_sync_commit(struct mail_index_view_sync_ctx **ctx, 579 bool *delayed_expunges_r); 580 581 /* Returns the index header. */ 582 const struct mail_index_header * 583 mail_index_get_header(struct mail_index_view *view); 584 /* Returns the wanted message record. */ 585 const struct mail_index_record * 586 mail_index_lookup(struct mail_index_view *view, uint32_t seq); 587 const struct mail_index_record * 588 mail_index_lookup_full(struct mail_index_view *view, uint32_t seq, 589 struct mail_index_map **map_r); 590 /* Returns TRUE if the given message has already been expunged from index. */ 591 bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq); 592 /* Note that returned keyword indexes aren't sorted. */ 593 void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq, 594 ARRAY_TYPE(keyword_indexes) *keyword_idx); 595 /* Return keywords from given map. */ 596 void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq, 597 ARRAY_TYPE(keyword_indexes) *keyword_idx); 598 /* mail_index_lookup[_keywords]() returns the latest flag changes. 599 This function instead attempts to return the flags and keywords done by the 600 last view sync. */ 601 void mail_index_lookup_view_flags(struct mail_index_view *view, uint32_t seq, 602 enum mail_flags *flags_r, 603 ARRAY_TYPE(keyword_indexes) *keyword_idx); 604 /* Returns the UID for given message. May be slightly faster than 605 mail_index_lookup()->uid. */ 606 void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq, 607 uint32_t *uid_r); 608 /* Convert UID range to sequence range. If no UIDs are found, returns FALSE and 609 sequences are set to 0. Note that any of the returned sequences may have 610 been expunged already. */ 611 bool mail_index_lookup_seq_range(struct mail_index_view *view, 612 uint32_t first_uid, uint32_t last_uid, 613 uint32_t *first_seq_r, uint32_t *last_seq_r); 614 bool mail_index_lookup_seq(struct mail_index_view *view, 615 uint32_t uid, uint32_t *seq_r); 616 /* Find first mail with (mail->flags & flags_mask) == flags. Useful mostly for 617 taking advantage of lowwater-fields in headers. */ 618 void mail_index_lookup_first(struct mail_index_view *view, 619 enum mail_flags flags, uint8_t flags_mask, 620 uint32_t *seq_r); 621 622 /* Append a new record to index. */ 623 void mail_index_append(struct mail_index_transaction *t, uint32_t uid, 624 uint32_t *seq_r); 625 /* Assign new UIDs for mails with uid=0 or uid<min_allowed_uid. All the new 626 UIDs are >= first_new_uid, an also higher than the highest seen uid (i.e. it 627 doesn't try to fill UID gaps). Assumes that mailbox is locked in a way that 628 UIDs can be safely assigned. Returns UIDs for all assigned messages, in 629 their sequence order (so UIDs are not necessary ascending). */ 630 void mail_index_append_finish_uids_full(struct mail_index_transaction *t, 631 uint32_t min_allowed_uid, 632 uint32_t first_new_uid, 633 ARRAY_TYPE(seq_range) *uids_r); 634 /* Call mail_index_append_finish_uids_full() with first_uid used for both 635 min_allowed_uid and first_new_uid. */ 636 void mail_index_append_finish_uids(struct mail_index_transaction *t, 637 uint32_t first_uid, 638 ARRAY_TYPE(seq_range) *uids_r); 639 /* Expunge record from index. Note that this doesn't affect sequence numbers 640 until transaction is committed and mailbox is synced. */ 641 void mail_index_expunge(struct mail_index_transaction *t, uint32_t seq); 642 /* Like mail_index_expunge(), but also write message GUID to transaction log. */ 643 void mail_index_expunge_guid(struct mail_index_transaction *t, uint32_t seq, 644 const guid_128_t guid_128); 645 /* Revert all changes done in this transaction to the given existing mail. */ 646 void mail_index_revert_changes(struct mail_index_transaction *t, uint32_t seq); 647 /* Update flags in index. */ 648 void mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq, 649 enum modify_type modify_type, 650 enum mail_flags flags); 651 void mail_index_update_flags_range(struct mail_index_transaction *t, 652 uint32_t seq1, uint32_t seq2, 653 enum modify_type modify_type, 654 enum mail_flags flags); 655 /* Specified attribute's value was changed. This is just a notification so the 656 change gets assigned its own modseq and any log readers can find out about 657 this change. */ 658 void mail_index_attribute_set(struct mail_index_transaction *t, 659 bool pvt, const char *key, 660 time_t timestamp, uint32_t value_len); 661 /* Attribute was deleted. */ 662 void mail_index_attribute_unset(struct mail_index_transaction *t, 663 bool pvt, const char *key, time_t timestamp); 664 /* Update message's modseq to be at least min_modseq. */ 665 void mail_index_update_modseq(struct mail_index_transaction *t, uint32_t seq, 666 uint64_t min_modseq); 667 /* Update highest modseq to be at least min_modseq. */ 668 void mail_index_update_highest_modseq(struct mail_index_transaction *t, 669 uint64_t min_modseq); 670 /* Reset the index before committing this transaction. This is usually done 671 only when UIDVALIDITY changes. */ 672 void mail_index_reset(struct mail_index_transaction *t); 673 /* Remove MAIL_INDEX_HDR_FLAG_FSCKD from header if it exists. This must be 674 called only during syncing so that the mailbox is locked. */ 675 void mail_index_unset_fscked(struct mail_index_transaction *t); 676 /* Mark index deleted. No further changes will be possible after the 677 transaction has been committed. */ 678 void mail_index_set_deleted(struct mail_index_transaction *t); 679 /* Mark a deleted index as undeleted. Afterwards index can be changed again. */ 680 void mail_index_set_undeleted(struct mail_index_transaction *t); 681 /* Returns TRUE if index has been set deleted. This gets set only after 682 index has been opened/refreshed and the transaction has been seen. */ 683 bool mail_index_is_deleted(struct mail_index *index); 684 /* Returns the last time the index was modified. This can be called even if the 685 index isn't open. If the index doesn't exist, sets mtime to 0. */ 686 int mail_index_get_modification_time(struct mail_index *index, time_t *mtime_r); 687 688 /* Lookup a keyword, returns TRUE if found, FALSE if not. */ 689 bool mail_index_keyword_lookup(struct mail_index *index, 690 const char *keyword, unsigned int *idx_r); 691 void mail_index_keyword_lookup_or_create(struct mail_index *index, 692 const char *keyword, 693 unsigned int *idx_r); 694 /* Return a pointer to array of NULL-terminated list of keywords. Note that 695 the array contents (and thus pointers inside it) may change after calling 696 mail_index_keywords_create() or mail_index_sync_begin(). */ 697 const ARRAY_TYPE(keywords) *mail_index_get_keywords(struct mail_index *index); 698 699 /* Create a keyword list structure. */ 700 struct mail_keywords * 701 mail_index_keywords_create(struct mail_index *index, 702 const char *const keywords[]) ATTR_NULL(2); 703 struct mail_keywords * 704 mail_index_keywords_create_from_indexes(struct mail_index *index, 705 const ARRAY_TYPE(keyword_indexes) 706 *keyword_indexes); 707 void mail_index_keywords_ref(struct mail_keywords *keywords); 708 void mail_index_keywords_unref(struct mail_keywords **keywords); 709 710 /* Update keywords for given message. */ 711 void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq, 712 enum modify_type modify_type, 713 struct mail_keywords *keywords); 714 715 /* Update field in header. If prepend is TRUE, the header change is visible 716 before message syncing begins. */ 717 void mail_index_update_header(struct mail_index_transaction *t, 718 size_t offset, const void *data, size_t size, 719 bool prepend); 720 721 /* Returns the full error message for last error. This message may 722 contain paths etc. so it shouldn't be shown to users. */ 723 const char *mail_index_get_error_message(struct mail_index *index); 724 /* Reset the error message. */ 725 void mail_index_reset_error(struct mail_index *index); 726 727 /* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given 728 flags variable. */ 729 void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec, 730 uint8_t *flags); 731 /* Apply changes in MAIL_INDEX_SYNC_TYPE_KEYWORD_* typed sync records to given 732 keywords array. Returns TRUE If something was changed. */ 733 bool mail_index_sync_keywords_apply(const struct mail_index_sync_rec *sync_rec, 734 ARRAY_TYPE(keyword_indexes) *keywords); 735 736 /* register index extension. name is a unique identifier for the extension. 737 returns unique identifier for the name. */ 738 uint32_t mail_index_ext_register(struct mail_index *index, const char *name, 739 uint32_t default_hdr_size, 740 uint16_t default_record_size, 741 uint16_t default_record_align); 742 /* Change an already registered extension's default sizes. */ 743 void mail_index_ext_register_resize_defaults(struct mail_index *index, 744 uint32_t ext_id, 745 uint32_t default_hdr_size, 746 uint16_t default_record_size, 747 uint16_t default_record_align); 748 /* Returns TRUE and sets ext_id_r if extension with given name is registered. */ 749 bool mail_index_ext_lookup(struct mail_index *index, const char *name, 750 uint32_t *ext_id_r); 751 /* Resize existing extension data. If size is grown, the new data will be 752 zero-filled. If size is shrinked, the data is simply dropped. */ 753 void mail_index_ext_resize(struct mail_index_transaction *t, uint32_t ext_id, 754 uint32_t hdr_size, uint16_t record_size, 755 uint16_t record_align); 756 /* Resize header, keeping the old record size. */ 757 void mail_index_ext_resize_hdr(struct mail_index_transaction *t, 758 uint32_t ext_id, uint32_t hdr_size); 759 760 /* Reset extension. Any updates for this extension which were issued before the 761 writer had seen this reset are discarded. reset_id is used to figure this 762 out, so it must be different every time. If clear_data=TRUE, records and 763 header is zeroed. */ 764 void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id, 765 uint32_t reset_id, bool clear_data); 766 /* Like mail_index_ext_reset(), but increase extension's reset_id atomically 767 when the transaction is being committed. If prev_reset_id doesn't match the 768 latest reset_id, the reset_id isn't increased and all extension changes are 769 ignored. */ 770 void mail_index_ext_reset_inc(struct mail_index_transaction *t, uint32_t ext_id, 771 uint32_t prev_reset_id, bool clear_data); 772 /* Discard existing extension updates in this transaction and write new updates 773 using the given reset_id. The difference to mail_index_ext_reset() is that 774 this doesn't clear any existing record or header data. */ 775 void mail_index_ext_set_reset_id(struct mail_index_transaction *t, 776 uint32_t ext_id, uint32_t reset_id); 777 /* Get the current reset_id for given extension. Returns TRUE if it exists. */ 778 bool mail_index_ext_get_reset_id(struct mail_index_view *view, 779 struct mail_index_map *map, 780 uint32_t ext_id, uint32_t *reset_id_r); 781 782 /* Returns extension header. */ 783 void mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id, 784 const void **data_r, size_t *data_size_r); 785 void mail_index_map_get_header_ext(struct mail_index_view *view, 786 struct mail_index_map *map, uint32_t ext_id, 787 const void **data_r, size_t *data_size_r); 788 /* Returns the wanted extension record for given message. If it doesn't exist, 789 *data_r is set to NULL. expunged_r is TRUE if the message has already been 790 expunged from the index. */ 791 void mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq, 792 uint32_t ext_id, const void **data_r, 793 bool *expunged_r); 794 void mail_index_lookup_ext_full(struct mail_index_view *view, uint32_t seq, 795 uint32_t ext_id, struct mail_index_map **map_r, 796 const void **data_r, bool *expunged_r); 797 /* Get current extension sizes. Returns 1 if ok, 0 if extension doesn't exist 798 in view. Any of the _r parameters may be NULL. */ 799 void mail_index_ext_get_size(struct mail_index_map *map, uint32_t ext_id, 800 uint32_t *hdr_size_r, uint16_t *record_size_r, 801 uint16_t *record_align_r); 802 /* Update extension header field. */ 803 void mail_index_update_header_ext(struct mail_index_transaction *t, 804 uint32_t ext_id, size_t offset, 805 const void *data, size_t size); 806 /* Update extension record. If old_data_r is non-NULL and the record extension 807 was already updated in this transaction, it's set to contain the data it's 808 now overwriting. */ 809 void mail_index_update_ext(struct mail_index_transaction *t, uint32_t seq, 810 uint32_t ext_id, const void *data, void *old_data) 811 ATTR_NULL(5); 812 /* Increase/decrease number in extension atomically. Returns the sum of the 813 diffs for this seq. */ 814 int mail_index_atomic_inc_ext(struct mail_index_transaction *t, 815 uint32_t seq, uint32_t ext_id, int diff); 816 817 #endif 818