summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/mail-storage-private.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
commitf7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch)
treea3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-storage/mail-storage-private.h
parentInitial commit. (diff)
downloaddovecot-upstream.tar.xz
dovecot-upstream.zip
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib-storage/mail-storage-private.h')
-rw-r--r--src/lib-storage/mail-storage-private.h913
1 files changed, 913 insertions, 0 deletions
diff --git a/src/lib-storage/mail-storage-private.h b/src/lib-storage/mail-storage-private.h
new file mode 100644
index 0000000..bc462bb
--- /dev/null
+++ b/src/lib-storage/mail-storage-private.h
@@ -0,0 +1,913 @@
+#ifndef MAIL_STORAGE_PRIVATE_H
+#define MAIL_STORAGE_PRIVATE_H
+
+#include "module-context.h"
+#include "unichar.h"
+#include "file-lock.h"
+#include "mail-storage.h"
+#include "mail-storage-hooks.h"
+#include "mail-storage-settings.h"
+#include "mailbox-attribute-private.h"
+#include "mail-index-private.h"
+
+struct file_lock;
+struct file_create_settings;
+struct fs;
+
+/* Default prefix for indexes */
+#define MAIL_INDEX_PREFIX "dovecot.index"
+
+/* Block size when read()ing message header. */
+#define MAIL_READ_HDR_BLOCK_SIZE (1024*4)
+/* Block size when read()ing message (header and) body. */
+#define MAIL_READ_FULL_BLOCK_SIZE IO_BLOCK_SIZE
+
+#define MAIL_SHARED_STORAGE_NAME "shared"
+
+#define MAIL_STORAGE_LOST_MAILBOX_PREFIX "recovered-lost-folder-"
+
+enum mail_storage_list_index_rebuild_reason {
+ /* Mailbox list index was found to be corrupted. */
+ MAIL_STORAGE_LIST_INDEX_REBUILD_REASON_CORRUPTED,
+ /* Mailbox list index doesn't have INBOX in an inbox=yes namespace.
+ Rebuild is done to verify whether the user really is an empty new
+ user, or if an existing user's mailbox list index was lost. Because
+ this is called in non-error conditions, the callback shouldn't log
+ any errors or warnings if it didn't find any missing mailboxes. */
+ MAIL_STORAGE_LIST_INDEX_REBUILD_REASON_NO_INBOX,
+ /* MAILBOX_SYNC_FLAG_FORCE_RESYNC is run. This is called only once
+ per list, so that doveadm force-resync '*' won't cause it to run for
+ every mailbox. */
+ MAIL_STORAGE_LIST_INDEX_REBUILD_REASON_FORCE_RESYNC,
+};
+
+struct mail_storage_module_register {
+ unsigned int id;
+};
+
+struct mail_module_register {
+ unsigned int id;
+};
+
+struct mail_storage_vfuncs {
+ const struct setting_parser_info *(*get_setting_parser_info)(void);
+
+ struct mail_storage *(*alloc)(void);
+ int (*create)(struct mail_storage *storage, struct mail_namespace *ns,
+ const char **error_r);
+ void (*destroy)(struct mail_storage *storage);
+ void (*add_list)(struct mail_storage *storage,
+ struct mailbox_list *list);
+
+ void (*get_list_settings)(const struct mail_namespace *ns,
+ struct mailbox_list_settings *set);
+ bool (*autodetect)(const struct mail_namespace *ns,
+ struct mailbox_list_settings *set);
+
+ struct mailbox *(*mailbox_alloc)(struct mail_storage *storage,
+ struct mailbox_list *list,
+ const char *vname,
+ enum mailbox_flags flags);
+ int (*purge)(struct mail_storage *storage);
+ /* Called when mailbox list index rebuild is requested.
+ The callback should add any missing mailboxes to the list index.
+ Returns 0 on success, -1 on temporary failure that didn't properly
+ rebuild the index. */
+ int (*list_index_rebuild)(struct mail_storage *storage,
+ enum mail_storage_list_index_rebuild_reason reason);
+};
+
+union mail_storage_module_context {
+ struct mail_storage_vfuncs super;
+ struct mail_storage_module_register *reg;
+};
+
+enum mail_storage_class_flags {
+ /* mailboxes are files, not directories */
+ MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE = 0x01,
+ /* root_dir points to a unique directory */
+ MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT = 0x02,
+ /* mailbox_open_stream() is supported */
+ MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS = 0x04,
+ /* never use quota for this storage (e.g. virtual mailboxes) */
+ MAIL_STORAGE_CLASS_FLAG_NOQUOTA = 0x08,
+ /* Storage doesn't need a mail root directory */
+ MAIL_STORAGE_CLASS_FLAG_NO_ROOT = 0x10,
+ /* Storage uses one file per message */
+ MAIL_STORAGE_CLASS_FLAG_FILE_PER_MSG = 0x20,
+ /* Messages have GUIDs (always set mailbox_status.have_guids=TRUE) */
+ MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS = 0x40,
+ /* mailbox_save_set_guid() works (always set
+ mailbox_status.have_save_guids=TRUE) */
+ MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_SAVE_GUIDS = 0x80,
+ /* message content can be unstructured binary data
+ (e.g. zlib plugin is allowed to compress/decompress mails) */
+ MAIL_STORAGE_CLASS_FLAG_BINARY_DATA = 0x100,
+ /* Message GUIDs can only be 128bit (always set
+ mailbox_status.have_only_guid128) */
+ MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUID128 = 0x200,
+ /* Storage deletes all files internally - mailbox list's
+ delete_mailbox() shouldn't delete anything itself. */
+ MAIL_STORAGE_CLASS_FLAG_NO_LIST_DELETES = 0x400,
+ /* Storage creates a secondary index */
+ MAIL_STORAGE_CLASS_FLAG_SECONDARY_INDEX = 0x800,
+};
+
+struct mail_binary_cache {
+ struct timeout *to;
+ struct mailbox *box;
+ uint32_t uid;
+
+ uoff_t orig_physical_pos;
+ bool include_hdr;
+ struct istream *input;
+ uoff_t size;
+};
+
+struct mail_storage_error {
+ char *error_string;
+ enum mail_error error;
+ char *last_internal_error;
+ bool last_error_is_internal;
+};
+
+struct mail_storage {
+ const char *name;
+ enum mail_storage_class_flags class_flags;
+ /* Fields that the storage backend can get by other means than parsing
+ the message header/body. For example the imapc backend can lookup
+ MAIL_FETCH_IMAP_BODYSTRUCTURE from the remote server. Adding fields
+ here avoids adding them to index_mail_data.access_part. */
+ enum mail_fetch_field nonbody_access_fields;
+ struct event_category *event_category;
+
+ struct mail_storage_vfuncs v, *vlast;
+
+/* private: */
+ pool_t pool;
+ struct mail_storage *prev, *next;
+ /* counting number of times mail_storage_create() has returned this
+ same storage. */
+ int refcount;
+ /* counting number of objects (e.g. mailbox) that have a pointer
+ to this storage. */
+ int obj_refcount;
+ /* Linked list of all mailboxes in the storage */
+ struct mailbox *mailboxes;
+ /* A "root dir" to enable storage sharing. It is only ever used for
+ * uniqueness checking (via strcmp) and never used as a path. */
+ const char *unique_root_dir;
+
+ /* prefix for lost mailbox */
+ const char *lost_mailbox_prefix;
+
+ /* Last error set in mail_storage_set_critical(). */
+ char *last_internal_error;
+
+ char *error_string;
+ enum mail_error error;
+ ARRAY(struct mail_storage_error) error_stack;
+ struct event *event;
+
+ const struct mail_storage *storage_class;
+ struct mail_user *user;
+ const char *temp_path_prefix;
+ const struct mail_storage_settings *set;
+
+ enum mail_storage_flags flags;
+
+ struct mail_storage_callbacks callbacks;
+ void *callback_context;
+
+ struct mail_binary_cache binary_cache;
+ /* Filled lazily by mailbox_attribute_*() when accessing shared
+ attributes. */
+ struct dict *_shared_attr_dict;
+
+ /* optional fs-api object for accessing mailboxes */
+ struct fs *mailboxes_fs;
+
+ /* Module-specific contexts. See mail_storage_module_id. */
+ ARRAY(union mail_storage_module_context *) module_contexts;
+
+ /* Failed to create shared attribute dict, don't try again */
+ bool shared_attr_dict_failed:1;
+ bool last_error_is_internal:1;
+ bool rebuilding_list_index:1;
+ bool rebuild_list_index:1;
+};
+
+struct mail_attachment_part {
+ struct message_part *part;
+ const char *content_type, *content_disposition;
+};
+
+struct virtual_mailbox_vfuncs {
+ /* convert backend UIDs to virtual UIDs. if some backend UID doesn't
+ exist in mailbox, it's simply ignored */
+ void (*get_virtual_uids)(struct mailbox *box,
+ struct mailbox *backend_mailbox,
+ const ARRAY_TYPE(seq_range) *backend_uids,
+ ARRAY_TYPE(seq_range) *virtual_uids_r);
+ /* like get_virtual_uids(), but if a backend UID doesn't exist,
+ convert it to 0. */
+ void (*get_virtual_uid_map)(struct mailbox *box,
+ struct mailbox *backend_mailbox,
+ const ARRAY_TYPE(seq_range) *backend_uids,
+ ARRAY_TYPE(uint32_t) *virtual_uids_r);
+ void (*get_virtual_backend_boxes)(struct mailbox *box,
+ ARRAY_TYPE(mailboxes) *mailboxes,
+ bool only_with_msgs);
+};
+
+struct mailbox_vfuncs {
+ bool (*is_readonly)(struct mailbox *box);
+
+ int (*enable)(struct mailbox *box, enum mailbox_feature features);
+ int (*exists)(struct mailbox *box, bool auto_boxes,
+ enum mailbox_existence *existence_r);
+ int (*open)(struct mailbox *box);
+ void (*close)(struct mailbox *box);
+ void (*free)(struct mailbox *box);
+
+ int (*create_box)(struct mailbox *box,
+ const struct mailbox_update *update, bool directory);
+ int (*update_box)(struct mailbox *box,
+ const struct mailbox_update *update);
+ int (*delete_box)(struct mailbox *box);
+ int (*rename_box)(struct mailbox *src, struct mailbox *dest);
+
+ int (*get_status)(struct mailbox *box, enum mailbox_status_items items,
+ struct mailbox_status *status_r);
+ int (*get_metadata)(struct mailbox *box,
+ enum mailbox_metadata_items items,
+ struct mailbox_metadata *metadata_r);
+ int (*set_subscribed)(struct mailbox *box, bool set);
+
+ int (*attribute_set)(struct mailbox_transaction_context *t,
+ enum mail_attribute_type type_flags,
+ const char *key,
+ const struct mail_attribute_value *value);
+ int (*attribute_get)(struct mailbox *box,
+ enum mail_attribute_type type_flags,
+ const char *key,
+ struct mail_attribute_value *value_r);
+ struct mailbox_attribute_iter *
+ (*attribute_iter_init)(struct mailbox *box,
+ enum mail_attribute_type type_flags,
+ const char *prefix);
+ const char *(*attribute_iter_next)(struct mailbox_attribute_iter *iter);
+ int (*attribute_iter_deinit)(struct mailbox_attribute_iter *iter);
+
+ /* Lookup sync extension record and figure out if it mailbox has
+ changed since. Returns 1 = yes, 0 = no, -1 = error. if quick==TRUE,
+ return 1 if it's too costly to find out exactly. The reason_r is
+ set if 1 is returned. */
+ int (*list_index_has_changed)(struct mailbox *box,
+ struct mail_index_view *list_view,
+ uint32_t seq, bool quick,
+ const char **reason_r);
+ /* Update the sync extension record. */
+ void (*list_index_update_sync)(struct mailbox *box,
+ struct mail_index_transaction *trans,
+ uint32_t seq);
+
+ struct mailbox_sync_context *
+ (*sync_init)(struct mailbox *box,
+ enum mailbox_sync_flags flags);
+ bool (*sync_next)(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_rec *sync_rec_r);
+ int (*sync_deinit)(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_status *status_r);
+
+ /* Called once for each expunge. Called one or more times for
+ flag/keyword changes. Once the sync is finished, called with
+ uid=0 and sync_type=0. */
+ void (*sync_notify)(struct mailbox *box, uint32_t uid,
+ enum mailbox_sync_type sync_type);
+
+ void (*notify_changes)(struct mailbox *box);
+
+ struct mailbox_transaction_context *
+ (*transaction_begin)(struct mailbox *box,
+ enum mailbox_transaction_flags flags,
+ const char *reason);
+ int (*transaction_commit)(struct mailbox_transaction_context *t,
+ struct mail_transaction_commit_changes *changes_r);
+ void (*transaction_rollback)(struct mailbox_transaction_context *t);
+
+ enum mail_flags (*get_private_flags_mask)(struct mailbox *box);
+
+ struct mail *
+ (*mail_alloc)(struct mailbox_transaction_context *t,
+ enum mail_fetch_field wanted_fields,
+ struct mailbox_header_lookup_ctx *wanted_headers);
+
+ struct mail_search_context *
+ (*search_init)(struct mailbox_transaction_context *t,
+ struct mail_search_args *args,
+ const enum mail_sort_type *sort_program,
+ enum mail_fetch_field wanted_fields,
+ struct mailbox_header_lookup_ctx *wanted_headers);
+ int (*search_deinit)(struct mail_search_context *ctx);
+ bool (*search_next_nonblock)(struct mail_search_context *ctx,
+ struct mail **mail_r, bool *tryagain_r);
+ /* Internally used by the search to find the next mail that potentially
+ matches the search query. The function performs "quick checks" on
+ the search query that can be done without initializing the mail
+ struct. For example it can filter out non-matching mails based on
+ SEARCH_SEQSET and SEARCH_UIDSET. Once a potentially matching mail is
+ found, ctx->seq is updated to it.
+
+ Plugins can use this function to skip over any mails that can't
+ match the search query. Plugins can also set
+ mail_search_arg.[non]match_always=TRUE
+ for search args that it already definitely knows will/won't match,
+ which prevents the standard search from attempting to match them
+ again.
+
+ This is used by the FTS plugin to skip over non-matching mails and
+ to initialize the [non]match_always=TRUE for the search args that
+ were matched against the FTS indexes. This prevents the standard
+ search from having to open any email bodies. */
+ bool (*search_next_update_seq)(struct mail_search_context *ctx);
+ int (*search_next_match_mail)(struct mail_search_context *ctx,
+ struct mail *mail);
+
+ struct mail_save_context *
+ (*save_alloc)(struct mailbox_transaction_context *t);
+ int (*save_begin)(struct mail_save_context *ctx, struct istream *input);
+ int (*save_continue)(struct mail_save_context *ctx);
+ int (*save_finish)(struct mail_save_context *ctx);
+ void (*save_cancel)(struct mail_save_context *ctx);
+ int (*copy)(struct mail_save_context *ctx, struct mail *mail);
+
+ /* Called during transaction commit/rollback if saving was done */
+ int (*transaction_save_commit_pre)(struct mail_save_context *save_ctx);
+ void (*transaction_save_commit_post)
+ (struct mail_save_context *save_ctx,
+ struct mail_index_transaction_commit_result *result_r);
+ void (*transaction_save_rollback)(struct mail_save_context *save_ctx);
+
+ bool (*is_inconsistent)(struct mailbox *box);
+};
+
+union mailbox_module_context {
+ struct mailbox_vfuncs super;
+ struct mail_storage_module_register *reg;
+};
+
+struct mail_msgpart_partial_cache {
+ uint32_t uid;
+ uoff_t physical_start;
+ uoff_t physical_pos, virtual_pos;
+};
+
+struct mailbox_index_vsize {
+ uint64_t vsize;
+ uint32_t highest_uid;
+ uint32_t message_count;
+};
+
+struct mailbox_index_pop3_uidl {
+ uint32_t max_uid_with_pop3_uidl;
+};
+
+struct mailbox_index_first_saved {
+ uint32_t uid;
+ uint32_t timestamp;
+};
+
+struct mailbox {
+ const char *name;
+ /* mailbox's virtual name (from mail_namespace_get_vname()) */
+ const char *vname;
+ struct mail_storage *storage;
+ struct mailbox_list *list;
+ struct event *event;
+
+ struct mailbox_vfuncs v, *vlast;
+ /* virtual mailboxes: */
+ const struct virtual_mailbox_vfuncs *virtual_vfuncs;
+/* private: */
+ pool_t pool;
+ /* Linked list of all mailboxes in this storage */
+ struct mailbox *prev, *next;
+
+ /* these won't be set until mailbox is opened: */
+ struct mail_index *index;
+ struct mail_index_view *view;
+ struct mail_cache *cache;
+ /* Private per-user index/view for shared mailboxes. These are synced
+ against the primary index and used to store per-user flags.
+ These are non-NULL only when mailbox has per-user flags. */
+ struct mail_index *index_pvt;
+ struct mail_index_view *view_pvt;
+ /* Filled lazily by mailbox_get_permissions() */
+ struct mailbox_permissions _perm;
+ /* Filled lazily when mailbox is opened, use mailbox_get_path()
+ to access it */
+ const char *_path;
+ /* Filled lazily when mailbox is opened, use mailbox_get_index_path()
+ to access it */
+ const char *_index_path;
+
+ /* default vfuncs for new struct mails. */
+ const struct mail_vfuncs *mail_vfuncs;
+ /* Mailbox settings, or NULL if defaults */
+ const struct mailbox_settings *set;
+
+ /* If non-zero, fail mailbox_open() with this error. mailbox_alloc()
+ can set this to force open to fail. */
+ enum mail_error open_error;
+
+ struct istream *input;
+ const char *index_prefix;
+ enum mailbox_flags flags;
+ unsigned int transaction_count;
+ unsigned int attribute_iter_count;
+ enum mailbox_feature enabled_features;
+ struct mail_msgpart_partial_cache partial_cache;
+ uint32_t vsize_hdr_ext_id;
+ uint32_t pop3_uidl_hdr_ext_id;
+ uint32_t box_name_hdr_ext_id;
+ uint32_t box_last_rename_stamp_ext_id;
+ uint32_t mail_vsize_ext_id;
+
+ /* MAIL_RECENT flags handling */
+ ARRAY_TYPE(seq_range) recent_flags;
+ uint32_t recent_flags_prev_uid;
+ uint32_t recent_flags_count;
+
+ struct mail_index_view *tmp_sync_view;
+
+ /* Mailbox notification settings: */
+ mailbox_notify_callback_t *notify_callback;
+ void *notify_context;
+ struct timeout *to_notify, *to_notify_delay;
+ struct mailbox_notify_file *notify_files;
+
+ /* Increased by one for each new struct mailbox. */
+ unsigned int generation_sequence;
+
+ /* Saved search results */
+ ARRAY(struct mail_search_result *) search_results;
+
+ /* Module-specific contexts. See mail_storage_module_id. */
+ ARRAY(union mailbox_module_context *) module_contexts;
+
+ /* When FAST open flag is used, the mailbox isn't actually opened until
+ it's synced for the first time. */
+ bool opened:1;
+ /* Mailbox was deleted while we had it open. */
+ bool mailbox_deleted:1;
+ /* Mailbox is being created */
+ bool creating:1;
+ /* Mailbox is being deleted */
+ bool deleting:1;
+ /* Mailbox is being undeleted */
+ bool mailbox_undeleting:1;
+ /* Don't use MAIL_INDEX_SYNC_FLAG_DELETING_INDEX for sync flag */
+ bool delete_sync_check:1;
+ /* Delete mailbox only if it's empty */
+ bool deleting_must_be_empty:1;
+ /* The backend wants to skip checking if there are 0 messages before
+ calling mailbox_list.delete_mailbox() */
+ bool delete_skip_empty_check:1;
+ /* Mailbox was already marked as deleted within this allocation. */
+ bool marked_deleted:1;
+ /* TRUE if this is an INBOX for this user */
+ bool inbox_user:1;
+ /* TRUE if this is an INBOX for this namespace (user or shared) */
+ bool inbox_any:1;
+ /* When copying to this mailbox, require that mailbox_copy() uses
+ mailbox_save_*() to actually save a new physical copy rather than
+ simply incrementing a reference count (e.g. via hard link) */
+ bool disable_reflink_copy_to:1;
+ /* Don't allow creating any new keywords */
+ bool disallow_new_keywords:1;
+ /* Mailbox has been synced at least once */
+ bool synced:1;
+ /* Updating cache file is disabled */
+ bool mail_cache_disabled:1;
+ /* Update first_saved field to mailbox list index. */
+ bool update_first_saved:1;
+ /* mailbox_verify_create_name() only checks for mailbox_verify_name() */
+ bool skip_create_name_restrictions:1;
+ /* Using LAYOUT=index and mailbox is being opened with a corrupted
+ mailbox name. Try to revert to the previously known good name. */
+ bool corrupted_mailbox_name:1;
+ /* mailbox_open() returned MAIL_ERROR_NOTFOUND because the mailbox
+ doesn't have the LOOKUP ACL right. */
+ bool acl_no_lookup_right:1;
+};
+
+struct mail_vfuncs {
+ void (*close)(struct mail *mail);
+ void (*free)(struct mail *mail);
+ void (*set_seq)(struct mail *mail, uint32_t seq, bool saving);
+ bool (*set_uid)(struct mail *mail, uint32_t uid);
+ void (*set_uid_cache_updates)(struct mail *mail, bool set);
+ bool (*prefetch)(struct mail *mail);
+ int (*precache)(struct mail *mail);
+ void (*add_temp_wanted_fields)(struct mail *mail,
+ enum mail_fetch_field fields,
+ struct mailbox_header_lookup_ctx *headers);
+
+ enum mail_flags (*get_flags)(struct mail *mail);
+ const char *const *(*get_keywords)(struct mail *mail);
+ const ARRAY_TYPE(keyword_indexes) *
+ (*get_keyword_indexes)(struct mail *mail);
+ uint64_t (*get_modseq)(struct mail *mail);
+ uint64_t (*get_pvt_modseq)(struct mail *mail);
+
+ int (*get_parts)(struct mail *mail,
+ struct message_part **parts_r);
+ int (*get_date)(struct mail *mail, time_t *date_r, int *timezone_r);
+ int (*get_received_date)(struct mail *mail, time_t *date_r);
+ int (*get_save_date)(struct mail *mail, time_t *date_r);
+ int (*get_virtual_size)(struct mail *mail, uoff_t *size_r);
+ int (*get_physical_size)(struct mail *mail, uoff_t *size_r);
+
+ int (*get_first_header)(struct mail *mail, const char *field,
+ bool decode_to_utf8, const char **value_r);
+ int (*get_headers)(struct mail *mail, const char *field,
+ bool decode_to_utf8, const char *const **value_r);
+ int (*get_header_stream)(struct mail *mail,
+ struct mailbox_header_lookup_ctx *headers,
+ struct istream **stream_r);
+ int (*get_stream)(struct mail *mail, bool get_body,
+ struct message_size *hdr_size,
+ struct message_size *body_size,
+ struct istream **stream_r);
+ int (*get_binary_stream)(struct mail *mail,
+ const struct message_part *part,
+ bool include_hdr, uoff_t *size_r,
+ unsigned int *lines_r, bool *binary_r,
+ struct istream **stream_r);
+
+ int (*get_special)(struct mail *mail, enum mail_fetch_field field,
+ const char **value_r);
+ int (*get_backend_mail)(struct mail *mail, struct mail **real_mail_r);
+
+ void (*update_flags)(struct mail *mail, enum modify_type modify_type,
+ enum mail_flags flags);
+ void (*update_keywords)(struct mail *mail, enum modify_type modify_type,
+ struct mail_keywords *keywords);
+ void (*update_modseq)(struct mail *mail, uint64_t min_modseq);
+ void (*update_pvt_modseq)(struct mail *mail, uint64_t min_pvt_modseq);
+ void (*update_pop3_uidl)(struct mail *mail, const char *uidl);
+ void (*expunge)(struct mail *mail);
+ void (*set_cache_corrupted)(struct mail *mail,
+ enum mail_fetch_field field,
+ const char *reason);
+ int (*istream_opened)(struct mail *mail, struct istream **input);
+};
+
+union mail_module_context {
+ struct mail_vfuncs super;
+ struct mail_module_register *reg;
+};
+
+struct mail_private {
+ struct mail mail;
+ struct mail_vfuncs v, *vlast;
+ /* normally NULL, but in case this is a "backend mail" for a mail
+ created by virtual storage, this points back to the original virtual
+ mail. at least mailbox_copy() bypasses the virtual storage, so this
+ allows mail_log plugin to log the copy operation using the original
+ mailbox name. */
+ struct mail *vmail;
+ /* Event is created lazily. Use mail_event() to access it. */
+ struct event *_event;
+
+ uint32_t seq_pvt;
+
+ /* initial wanted fields/headers, set by mail_alloc(): */
+ enum mail_fetch_field wanted_fields;
+ struct mailbox_header_lookup_ctx *wanted_headers;
+
+ pool_t pool, data_pool;
+ ARRAY(union mail_module_context *) module_contexts;
+
+ const char *get_stream_reason;
+
+ bool autoexpunged:1;
+ /* mail created by mailbox_search_*() */
+ bool search_mail:1;
+};
+
+struct mailbox_list_context {
+ struct mail_storage *storage;
+ enum mailbox_list_flags flags;
+ bool failed;
+};
+
+union mailbox_transaction_module_context {
+ struct mail_storage_module_register *reg;
+};
+
+struct mailbox_transaction_stats {
+ unsigned long open_lookup_count;
+ unsigned long stat_lookup_count;
+ unsigned long fstat_lookup_count;
+ /* number of files we've opened and read */
+ unsigned long files_read_count;
+ /* number of bytes we've had to read from files */
+ unsigned long long files_read_bytes;
+ /* number of cache lookup hits */
+ unsigned long cache_hit_count;
+};
+
+struct mail_save_private_changes {
+ /* first saved mail is 0, second is 1, etc. we'll map these to UIDs
+ using struct mail_transaction_commit_changes. */
+ unsigned int mailnum;
+ enum mail_flags flags;
+};
+
+struct mailbox_transaction_context {
+ struct mailbox *box;
+ enum mailbox_transaction_flags flags;
+ char *reason;
+
+ union mail_index_transaction_module_context module_ctx;
+ struct mail_index_transaction_vfuncs super;
+ int mail_ref_count;
+
+ struct mail_index_transaction *itrans;
+ struct dict_transaction_context *attr_pvt_trans, *attr_shared_trans;
+ /* view contains all changes done within this transaction */
+ struct mail_index_view *view;
+
+ /* for private index updates: */
+ struct mail_index_transaction *itrans_pvt;
+ struct mail_index_view *view_pvt;
+
+ struct mail_cache_view *cache_view;
+ struct mail_cache_transaction_ctx *cache_trans;
+
+ struct mail_transaction_commit_changes *changes;
+ ARRAY(union mailbox_transaction_module_context *) module_contexts;
+
+ uint32_t prev_pop3_uidl_tracking_seq;
+ uint32_t highest_pop3_uidl_uid;
+
+ struct mail_save_context *save_ctx;
+ /* number of mails saved/copied within this transaction. */
+ unsigned int save_count;
+ /* List of private flags added with save/copy. These are added to the
+ private index after committing the mails to the shared index. */
+ ARRAY(struct mail_save_private_changes) pvt_saves;
+
+ /* these statistics are never reset by mail-storage API: */
+ struct mailbox_transaction_stats stats;
+ /* Set to TRUE to update stats_* fields */
+ bool stats_track:1;
+};
+
+union mail_search_module_context {
+ struct mail_storage_module_register *reg;
+};
+
+struct mail_search_context {
+ struct mailbox_transaction_context *transaction;
+
+ struct mail_search_args *args;
+ struct mail_search_sort_program *sort_program;
+ enum mail_fetch_field wanted_fields;
+ struct mailbox_header_lookup_ctx *wanted_headers;
+ normalizer_func_t *normalizer;
+
+ /* if non-NULL, specifies that a search resulting is being updated.
+ this can be used as a search optimization: if searched message
+ already exists in search result, it's not necessary to check if
+ static data matches. */
+ struct mail_search_result *update_result;
+ /* add matches to these search results */
+ ARRAY(struct mail_search_result *) results;
+
+ uint32_t seq;
+ uint32_t progress_cur, progress_max;
+
+ ARRAY(struct mail *) mails;
+ unsigned int unused_mail_idx;
+ unsigned int max_mails;
+
+ ARRAY(union mail_search_module_context *) module_contexts;
+
+ bool seen_lost_data:1;
+ bool progress_hidden:1;
+};
+
+struct mail_save_data {
+ enum mail_flags flags;
+ enum mail_flags pvt_flags;
+ struct mail_keywords *keywords;
+ uint64_t min_modseq;
+
+ time_t received_date, save_date;
+ int received_tz_offset;
+
+ uint32_t uid;
+ char *guid, *pop3_uidl, *from_envelope;
+ uint32_t pop3_order;
+
+ struct ostream *output;
+ struct mail_save_attachment *attach;
+};
+
+struct mail_save_context {
+ struct mailbox_transaction_context *transaction;
+ struct mail *dest_mail;
+ /* Set during mailbox_copy(). This is useful when copying is
+ implemented via save, and the save_*() methods want to access the
+ source mail. */
+ struct mail *copy_src_mail;
+
+ /* data that changes for each saved mail */
+ struct mail_save_data data;
+
+ /* returns TRUE if message part is an attachment. */
+ bool (*part_is_attachment)(struct mail_save_context *ctx,
+ const struct mail_attachment_part *part);
+
+ /* mailbox_save_alloc() called, but finish/cancel not.
+ the same context is usually returned by the backends for reuse. */
+ bool unfinished:1;
+ /* mailbox_save_finish() or mailbox_copy() is being called. */
+ bool finishing:1;
+ /* mail was copied or moved using saving (requires:
+ copying_or_moving==TRUE). */
+ bool copying_via_save:1;
+ /* mail is being saved, not copied. However, this is set also with
+ mailbox_save_using_mail() and then copying_or_moving==TRUE. */
+ bool saving:1;
+ /* mail is being moved - ignore quota (requires:
+ copying_or_moving==TRUE && saving==FALSE). */
+ bool moving:1;
+ /* mail is being copied or moved. However, this is set also with
+ mailbox_save_using_mail() and then saving==TRUE. */
+ bool copying_or_moving:1;
+};
+
+struct mailbox_sync_context {
+ struct mailbox *box;
+ enum mailbox_sync_flags flags;
+ bool open_failed;
+};
+
+struct mailbox_header_lookup_ctx {
+ struct mailbox *box;
+ pool_t pool;
+ int refcount;
+
+ unsigned int count;
+ const char *const *name;
+ unsigned int *idx;
+};
+
+/* Modules should use do "my_id = mail_storage_module_id++" and
+ use objects' module_contexts[id] for their own purposes. */
+extern struct mail_storage_module_register mail_storage_module_register;
+
+/* Storage's module_id for mail_index. */
+extern struct mail_module_register mail_module_register;
+
+extern struct event_category event_category_storage;
+extern struct event_category event_category_mailbox;
+extern struct event_category event_category_mail;
+
+#define MAIL_STORAGE_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, mail_storage_mail_index_module)
+#define MAIL_STORAGE_CONTEXT_REQUIRE(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, mail_storage_mail_index_module)
+extern MODULE_CONTEXT_DEFINE(mail_storage_mail_index_module,
+ &mail_index_module_register);
+
+void mail_storage_obj_ref(struct mail_storage *storage);
+void mail_storage_obj_unref(struct mail_storage *storage);
+
+/* Set error message in storage. Critical errors are logged with i_error(),
+ but user sees only "internal error" message. */
+void mail_storage_clear_error(struct mail_storage *storage);
+void mail_storage_set_error(struct mail_storage *storage,
+ enum mail_error error, const char *string);
+void mail_storage_set_critical(struct mail_storage *storage,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+void mailbox_set_critical(struct mailbox *box,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+void mail_set_critical(struct mail *mail,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+void mail_storage_set_internal_error(struct mail_storage *storage);
+void mailbox_set_index_error(struct mailbox *box);
+void mail_storage_set_index_error(struct mail_storage *storage,
+ struct mail_index *index);
+bool mail_storage_set_error_from_errno(struct mail_storage *storage);
+void mail_storage_copy_list_error(struct mail_storage *storage,
+ struct mailbox_list *list);
+void mail_storage_copy_error(struct mail_storage *dest,
+ struct mail_storage *src);
+/* set record in mail cache corrupted */
+void mail_set_mail_cache_corrupted(struct mail *mail, const char *fmt, ...)
+ ATTR_FORMAT(2, 3);
+
+/* Indicate mail being expunged by autoexpunge */
+void mail_autoexpunge(struct mail *mail);
+
+void mail_event_create(struct mail *mail);
+/* Returns TRUE if everything should already be in memory after this call
+ or if prefetching is not supported, i.e. the caller shouldn't do more
+ prefetching before this message is handled. */
+bool mail_prefetch(struct mail *mail);
+void mail_set_aborted(struct mail *mail);
+void mail_set_expunged(struct mail *mail);
+void mail_set_seq_saving(struct mail *mail, uint32_t seq);
+/* Returns true IF and only IF the mail has EITHER one of the
+ attachment keywords set. If it has both, or none, it will return FALSE. */
+bool mail_has_attachment_keywords(struct mail *mail);
+/* Sets attachment keywords. Returns -1 on error, 0 when no attachment(s) found,
+ and 1 if attachment was found. */
+int mail_set_attachment_keywords(struct mail *mail);
+
+/* Attempt to start accessing the mail stream. Returns TRUE is ok, FALSE if
+ prevented by mail->lookup_abort. */
+bool mail_stream_access_start(struct mail *mail);
+/* Attempt to start accessing the mail metadata. Returns TRUE is ok, FALSE if
+ prevented by mail->lookup_abort. */
+bool mail_metadata_access_start(struct mail *mail);
+/* Emit mail opened events */
+void mail_opened_event(struct mail *mail);
+
+/* Emit mail expunge_requested event */
+void mail_expunge_requested_event(struct mail *mail);
+
+void mailbox_set_deleted(struct mailbox *box);
+int mailbox_mark_index_deleted(struct mailbox *box, bool del);
+/* Easy wrapper for getting mailbox's MAILBOX_LIST_PATH_TYPE_MAILBOX.
+ The mailbox must already be opened and the caller must know that the
+ storage has mailbox files (i.e. NULL/empty path is never returned). */
+const char *mailbox_get_path(struct mailbox *box) ATTR_PURE;
+/* Similar to mailbox_get_path() but for MAILBOX_LIST_PATH_TYPE_INDEX. */
+const char *mailbox_get_index_path(struct mailbox *box) ATTR_PURE;
+/* Wrapper to mailbox_list_get_path() */
+int mailbox_get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
+ const char **path_r);
+/* Get mailbox permissions. */
+const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box);
+/* Force permissions to be refreshed on next lookup */
+void mailbox_refresh_permissions(struct mailbox *box);
+
+/* Open private index files for mailbox. Returns 1 if opened, 0 if there
+ are no private indexes (or flags) in this mailbox, -1 if error. */
+int mailbox_open_index_pvt(struct mailbox *box);
+/* Create path's directory with proper permissions. The root directory is also
+ created if necessary. Returns 1 if created, 0 if it already existed,
+ -1 if error. */
+int mailbox_mkdir(struct mailbox *box, const char *path,
+ enum mailbox_list_path_type type);
+/* Create a non-mailbox type directory for mailbox if it's missing (e.g. index).
+ Optimized for case where the directory usually exists. */
+int mailbox_create_missing_dir(struct mailbox *box,
+ enum mailbox_list_path_type type);
+/* Returns TRUE if mailbox is autocreated. */
+bool mailbox_is_autocreated(struct mailbox *box);
+/* Returns TRUE if mailbox is autosubscribed. */
+bool mailbox_is_autosubscribed(struct mailbox *box);
+
+/* Returns -1 if error, 0 if failed with EEXIST, 1 if ok */
+int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
+ int *fd_r);
+/* Create a lock file with the given path and settings. If it succeeds,
+ returns 1 and lock_r, which needs to be freed once finished with the lock.
+ If lock_set->lock_timeout_secs is reached, returns 0 and error_r. Returns
+ -1 and sets error_r on other errors. */
+int mail_storage_lock_create(const char *lock_path,
+ const struct file_create_settings *lock_set,
+ const struct mail_storage_settings *mail_set,
+ struct file_lock **lock_r, const char **error_r);
+/* Create a lock file to the mailbox with the given filename. Returns the same
+ as mail_storage_lock_create(). */
+int mailbox_lock_file_create(struct mailbox *box, const char *lock_fname,
+ unsigned int lock_secs, struct file_lock **lock_r,
+ const char **error_r);
+unsigned int mail_storage_get_lock_timeout(struct mail_storage *storage,
+ unsigned int secs);
+void mail_storage_free_binary_cache(struct mail_storage *storage);
+
+enum mail_index_open_flags
+mail_storage_settings_to_index_flags(const struct mail_storage_settings *set);
+void mailbox_save_context_deinit(struct mail_save_context *ctx);
+
+/* Notify that a sync should be done. */
+void mailbox_sync_notify(struct mailbox *box, uint32_t uid,
+ enum mailbox_sync_type sync_type);
+
+/* for unit testing */
+int mailbox_verify_name(struct mailbox *box);
+
+int mail_storage_list_index_rebuild_and_set_uncorrupted(struct mail_storage *storage);
+int mail_storage_list_index_rebuild(struct mail_storage *storage,
+ enum mail_storage_list_index_rebuild_reason reason);
+
+#endif