mail-storage-private.h revision 74943466e541d8bfe3916bb0eb9fb9cb0599dfe7
#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;
/* Default prefix for indexes */
#define MAIL_INDEX_PREFIX "dovecot.index"
/* Block size when read()ing message header. */
/* Block size when read()ing message (header and) body. */
#define MAIL_SHARED_STORAGE_NAME "shared"
/* Mailbox list index was found to be 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. */
/* 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. */
};
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);
const char **error_r);
struct mailbox_list *list);
struct mailbox_list_settings *set);
struct mailbox_list_settings *set);
struct mailbox_list *list,
const char *vname,
enum mailbox_flags flags);
/* 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. */
};
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 */
/* root_dir points to a unique directory */
/* mailbox_open_stream() is supported */
/* 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 */
/* Messages have GUIDs (always set mailbox_status.have_guids=TRUE) */
/* mailbox_save_set_guid() works (always set
mailbox_status.have_save_guids=TRUE) */
/* 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) */
/* Storage deletes all files internally - mailbox list's
delete_mailbox() shouldn't delete anything itself. */
/* Storage supports stubs (used for caching purposes). */
MAIL_STORAGE_CLASS_FLAG_STUBS = 0x800,
};
struct mail_binary_cache {
bool include_hdr;
};
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;
/* Fields that the storage backend can get by other means than parsing
MAIL_FETCH_IMAP_BODYSTRUCTURE from the remote server. Adding fields
here avoids adding them to index_mail_data.access_part. */
struct mail_storage_vfuncs v, *vlast;
/* private: */
/* 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 */
/* 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;
/* Last error set in mail_storage_set_critical(). */
char *last_internal_error;
char *error_string;
enum mail_error error;
const struct mail_storage *storage_class;
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;
/* Module-specific contexts. See mail_storage_module_id. */
/* Failed to create shared attribute dict, don't try again */
bool shared_attr_dict_failed:1;
bool last_error_is_internal: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 */
struct mailbox *backend_mailbox,
/* like get_virtual_uids(), but if a backend UID doesn't exist,
convert it to 0. */
struct mailbox *backend_mailbox,
bool only_with_msgs);
};
struct mailbox_vfuncs {
enum mailbox_existence *existence_r);
const struct mailbox_update *update);
struct mailbox_status *status_r);
enum mailbox_metadata_items items,
struct mailbox_metadata *metadata_r);
int (*attribute_set)(struct mailbox_transaction_context *t,
const struct mail_attribute_value *value);
struct mail_attribute_value *value_r);
struct mailbox_attribute_iter *
enum mail_attribute_type type,
const char *prefix);
/* 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. */
struct mail_index_view *list_view,
/* Update the sync extension record. */
struct mail_index_transaction *trans,
struct mailbox_sync_context *
enum mailbox_sync_flags flags);
struct mailbox_sync_rec *sync_rec_r);
struct mailbox_sync_status *status_r);
/* Called once for each expunge. Called one or more times for
uid=0 and sync_type=0. */
enum mailbox_sync_type sync_type);
struct mailbox_transaction_context *
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);
struct mail *
(*mail_alloc)(struct mailbox_transaction_context *t,
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,
struct mailbox_header_lookup_ctx *wanted_headers);
/* Internal search function which updates ctx->seq */
struct mail_save_context *
(*save_alloc)(struct mailbox_transaction_context *t);
void (*transaction_save_commit_post)
(struct mail_save_context *save_ctx,
struct mail_index_transaction_commit_result *result_r);
};
union mailbox_module_context {
struct mailbox_vfuncs super;
struct mail_storage_module_register *reg;
};
struct mail_msgpart_partial_cache {
};
struct mailbox_index_vsize {
};
struct mailbox_index_pop3_uidl {
};
struct mailbox_index_first_saved {
};
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 mailbox_vfuncs v, *vlast;
/* virtual mailboxes: */
const struct virtual_mailbox_vfuncs *virtual_vfuncs;
/* private: */
/* Linked list of all mailboxes in this storage */
/* these won't be set until mailbox is opened: */
struct mail_index *index;
struct mail_index_view *view;
struct mail_cache *cache;
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;
/* Reason for why mailbox is being accessed or NULL if unknown. */
const char *reason;
/* 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;
const char *index_prefix;
enum mailbox_flags flags;
unsigned int transaction_count;
unsigned int attribute_iter_count;
/* MAIL_RECENT flags handling */
struct mail_index_view *tmp_sync_view;
/* Mailbox notification settings: */
void *notify_context;
struct mailbox_notify_file *notify_files;
/* Increased by one for each new struct mailbox. */
unsigned int generation_sequence;
/* Saved search results */
/* Module-specific contexts. See mail_storage_module_id. */
/* 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;
};
struct mail_vfuncs {
enum mail_fetch_field fields,
struct mailbox_header_lookup_ctx *headers);
const ARRAY_TYPE(keyword_indexes) *
struct message_part **parts_r);
bool decode_to_utf8, const char **value_r);
bool decode_to_utf8, const char *const **value_r);
struct mailbox_header_lookup_ctx *headers,
struct message_size *hdr_size,
struct message_size *body_size,
const struct message_part *part,
const char **value_r);
enum mail_flags flags);
struct mail_keywords *keywords);
enum mail_fetch_field field,
const char *reason);
};
union mail_module_context {
struct mail_vfuncs super;
struct mail_module_register *reg;
};
struct mail_private {
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 mailbox_header_lookup_ctx *wanted_headers;
const char *get_stream_reason;
bool autoexpunged:1;
};
struct mailbox_list_context {
struct mail_storage *storage;
enum mailbox_list_flags flags;
bool failed;
};
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 {
char *reason;
struct mail_index_transaction_vfuncs super;
int mail_ref_count;
struct mail_index_transaction *itrans;
/* 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;
struct mail_save_context *save_ctx;
unsigned int save_count;
private index after committing the mails to the shared index. */
/* 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;
/* We've done some non-transactional (e.g. dovecot-uidlist updates) */
bool nontransactional_changes: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;
struct mailbox_header_lookup_ctx *wanted_headers;
/* 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 */
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;
int received_tz_offset;
unsigned int pop3_order;
struct mail_save_attachment *attach;
};
struct mail_save_context {
struct mailbox_transaction_context *transaction;
/* 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. */
const struct mail_attachment_part *part);
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 {
enum mailbox_sync_flags flags;
bool open_failed;
};
struct mailbox_header_lookup_ctx {
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) \
#define MAIL_STORAGE_CONTEXT_REQUIRE(obj) \
/* Set error message in storage. Critical errors are logged with i_error(),
but user sees only "internal error" message. */
struct mail_index *index);
struct mailbox_list *list);
struct mail_storage *src);
/* set record in mail cache corrupted */
/* Indicate mail being expunged by autoexpunge */
/* 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. */
/* 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. */
/* Sets attachment keywords. */
/* Easy wrapper for getting mailbox's MAILBOX_LIST_PATH_TYPE_MAILBOX.
The mailbox must already be opened and the caller must know that the
/* Similar to mailbox_get_path() but for MAILBOX_LIST_PATH_TYPE_INDEX. */
/* Wrapper to mailbox_list_get_path() */
const char **path_r);
/* Get mailbox permissions. */
/* Force permissions to be refreshed on next lookup */
/* 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. */
/* 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. */
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. */
enum mailbox_list_path_type type);
/* Returns TRUE if mailbox is autocreated. */
/* Returns TRUE if mailbox is autosubscribed. */
/* Returns -1 if error, 0 if failed with EEXIST, 1 if ok */
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,
/* Create a lock file to the mailbox with the given filename. Returns the same
as mail_storage_lock_create(). */
const char **error_r);
unsigned int secs);
#endif