diff options
Diffstat (limited to 'src/lib-storage/mail-storage.h')
-rw-r--r-- | src/lib-storage/mail-storage.h | 1027 |
1 files changed, 1027 insertions, 0 deletions
diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h new file mode 100644 index 0000000..64e0e49 --- /dev/null +++ b/src/lib-storage/mail-storage.h @@ -0,0 +1,1027 @@ +#ifndef MAIL_STORAGE_H +#define MAIL_STORAGE_H + +struct message_size; + +#include "seq-range-array.h" +#include "file-lock.h" +#include "guid.h" +#include "mail-types.h" +#include "mail-error.h" +#include "mail-index.h" +#include "mail-namespace.h" +#include "mailbox-list.h" +#include "mailbox-attribute.h" + +/* If some operation is taking long, call notify_ok every n seconds. */ +#define MAIL_STORAGE_STAYALIVE_SECS 15 + +#define MAIL_KEYWORD_HAS_ATTACHMENT "$HasAttachment" +#define MAIL_KEYWORD_HAS_NO_ATTACHMENT "$HasNoAttachment" + +enum mail_storage_flags { + /* Remember message headers' MD5 sum */ + MAIL_STORAGE_FLAG_KEEP_HEADER_MD5 = 0x01, + /* Don't try to autodetect anything, require that the given data + contains all the necessary information. */ + MAIL_STORAGE_FLAG_NO_AUTODETECTION = 0x02, + /* Don't autocreate any directories. If they don't exist, + fail to create the storage. */ + MAIL_STORAGE_FLAG_NO_AUTOCREATE = 0x04, + /* Don't verify existence or accessibility of any directories. + Create the storage in any case. */ + MAIL_STORAGE_FLAG_NO_AUTOVERIFY = 0x08 +}; + +enum mailbox_flags { + /* Mailbox must not be modified even if asked */ + MAILBOX_FLAG_READONLY = 0x01, + /* Only saving/copying mails to mailbox works. */ + MAILBOX_FLAG_SAVEONLY = 0x02, + /* Remove MAIL_RECENT flags when syncing */ + MAILBOX_FLAG_DROP_RECENT = 0x04, + /* Don't create index files for the mailbox */ + MAILBOX_FLAG_NO_INDEX_FILES = 0x10, + /* Keep mailbox exclusively locked all the time while it's open */ + MAILBOX_FLAG_KEEP_LOCKED = 0x20, + /* Enable if mailbox is used for serving POP3. This allows making + better caching decisions. */ + MAILBOX_FLAG_POP3_SESSION = 0x40, + /* Enable if mailbox is used for saving a mail delivery using MDA. + This causes ACL plugin to use POST right rather than INSERT. */ + MAILBOX_FLAG_POST_SESSION = 0x80, + /* Force opening mailbox and ignoring any ACLs */ + MAILBOX_FLAG_IGNORE_ACLS = 0x100, + /* Open mailbox even if it's already marked as deleted */ + MAILBOX_FLAG_OPEN_DELETED = 0x200, + /* Mailbox is opened for deletion, which should be performed as + efficiently as possible, even allowing the mailbox state to become + inconsistent. For example this disables lazy_expunge plugin and + quota updates (possibly resulting in broken quota). and This is + useful for example when deleting entire user accounts. */ + MAILBOX_FLAG_DELETE_UNSAFE = 0x400, + /* Mailbox is created implicitly if it does not exist. */ + MAILBOX_FLAG_AUTO_CREATE = 0x1000, + /* Mailbox is subscribed to implicitly when it is created automatically */ + MAILBOX_FLAG_AUTO_SUBSCRIBE = 0x2000, + /* Run fsck for mailbox index before doing anything else. This may be + useful in fixing index corruption errors that aren't otherwise + detected and that are causing the full mailbox opening to fail. */ + MAILBOX_FLAG_FSCK = 0x4000, + /* Interpret name argument for mailbox_alloc_for_user() as a SPECIAL-USE + flag. */ + MAILBOX_FLAG_SPECIAL_USE = 0x8000, + /* Mailbox is opened for reading/writing attributes. This allows ACL + plugin to determine correctly whether the mailbox should be allowed + to be opened. */ + MAILBOX_FLAG_ATTRIBUTE_SESSION = 0x10000, +}; + +enum mailbox_feature { + /* Enable tracking modsequences */ + MAILBOX_FEATURE_CONDSTORE = 0x01, +}; + +enum mailbox_existence { + MAILBOX_EXISTENCE_NONE, + MAILBOX_EXISTENCE_NOSELECT, + MAILBOX_EXISTENCE_SELECT +}; + +enum mailbox_status_items { + STATUS_MESSAGES = 0x01, + STATUS_RECENT = 0x02, + STATUS_UIDNEXT = 0x04, + STATUS_UIDVALIDITY = 0x08, + STATUS_UNSEEN = 0x10, + STATUS_FIRST_UNSEEN_SEQ = 0x20, + STATUS_KEYWORDS = 0x40, + STATUS_HIGHESTMODSEQ = 0x80, + STATUS_PERMANENT_FLAGS = 0x200, + STATUS_FIRST_RECENT_UID = 0x400, + STATUS_LAST_CACHED_SEQ = 0x800, + STATUS_CHECK_OVER_QUOTA = 0x1000, /* return error if over quota */ + STATUS_HIGHESTPVTMODSEQ = 0x2000, + /* status items that must not be looked up with + mailbox_get_open_status(), because they can return failure. */ +#define MAILBOX_STATUS_FAILING_ITEMS \ + (STATUS_LAST_CACHED_SEQ | STATUS_CHECK_OVER_QUOTA) +}; + +enum mailbox_metadata_items { + MAILBOX_METADATA_GUID = 0x01, + MAILBOX_METADATA_VIRTUAL_SIZE = 0x02, + MAILBOX_METADATA_CACHE_FIELDS = 0x04, + MAILBOX_METADATA_PRECACHE_FIELDS = 0x08, + MAILBOX_METADATA_BACKEND_NAMESPACE = 0x10, + MAILBOX_METADATA_PHYSICAL_SIZE = 0x20, + MAILBOX_METADATA_FIRST_SAVE_DATE = 0x40 + /* metadata items that require mailbox to be synced at least once. */ +#define MAILBOX_METADATA_SYNC_ITEMS \ + (MAILBOX_METADATA_VIRTUAL_SIZE | MAILBOX_METADATA_PHYSICAL_SIZE | \ + MAILBOX_METADATA_FIRST_SAVE_DATE) +}; + +enum mailbox_search_result_flags { + /* Update search results whenever the mailbox view is synced. + Expunged messages are removed even without this flag. */ + MAILBOX_SEARCH_RESULT_FLAG_UPDATE = 0x01, + /* Queue changes so _sync() can be used. */ + MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC = 0x02 +}; + +enum mail_sort_type { + MAIL_SORT_ARRIVAL = 0x0001, + MAIL_SORT_CC = 0x0002, + MAIL_SORT_DATE = 0x0004, + MAIL_SORT_FROM = 0x0008, + MAIL_SORT_SIZE = 0x0010, + MAIL_SORT_SUBJECT = 0x0020, + MAIL_SORT_TO = 0x0040, + MAIL_SORT_RELEVANCY = 0x0080, + MAIL_SORT_DISPLAYFROM = 0x0100, + MAIL_SORT_DISPLAYTO = 0x0200, + MAIL_SORT_POP3_ORDER = 0x0400, +/* Maximum size for sort program (each one separately + END) */ +#define MAX_SORT_PROGRAM_SIZE (11 + 1) + + MAIL_SORT_MASK = 0x0fff, + MAIL_SORT_FLAG_REVERSE = 0x1000, /* reverse this mask type */ + + MAIL_SORT_END = 0x0000 /* ends sort program */ +}; + +enum mail_fetch_field { + MAIL_FETCH_FLAGS = 0x00000001, + MAIL_FETCH_MESSAGE_PARTS = 0x00000002, + + MAIL_FETCH_STREAM_HEADER = 0x00000004, + MAIL_FETCH_STREAM_BODY = 0x00000008, + + MAIL_FETCH_DATE = 0x00000010, + MAIL_FETCH_RECEIVED_DATE = 0x00000020, + MAIL_FETCH_SAVE_DATE = 0x00000040, + MAIL_FETCH_PHYSICAL_SIZE = 0x00000080, + MAIL_FETCH_VIRTUAL_SIZE = 0x00000100, + + /* Set has_nuls / has_no_nuls fields */ + MAIL_FETCH_NUL_STATE = 0x00000200, + + MAIL_FETCH_STREAM_BINARY = 0x00000400, + + /* specials: */ + MAIL_FETCH_IMAP_BODY = 0x00001000, + MAIL_FETCH_IMAP_BODYSTRUCTURE = 0x00002000, + MAIL_FETCH_IMAP_ENVELOPE = 0x00004000, + MAIL_FETCH_FROM_ENVELOPE = 0x00008000, + MAIL_FETCH_HEADER_MD5 = 0x00010000, + MAIL_FETCH_STORAGE_ID = 0x00020000, + MAIL_FETCH_UIDL_BACKEND = 0x00040000, + MAIL_FETCH_MAILBOX_NAME = 0x00080000, + MAIL_FETCH_SEARCH_RELEVANCY = 0x00100000, + MAIL_FETCH_GUID = 0x00200000, + MAIL_FETCH_POP3_ORDER = 0x00400000, + MAIL_FETCH_REFCOUNT = 0x00800000, + MAIL_FETCH_BODY_SNIPPET = 0x01000000, + MAIL_FETCH_REFCOUNT_ID = 0x02000000, +}; + +enum mailbox_transaction_flags { + /* Hide changes done in this transaction from next view sync */ + MAILBOX_TRANSACTION_FLAG_HIDE = 0x01, + /* External transaction. Should be used for copying and appends, + but nothing else. */ + MAILBOX_TRANSACTION_FLAG_EXTERNAL = 0x02, + /* Always assign UIDs to messages when saving/copying. Normally this + is done only if it can be done easily. */ + MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS = 0x04, + /* Refresh the index so lookups return latest flags/modseqs */ + MAILBOX_TRANSACTION_FLAG_REFRESH = 0x08, + /* Don't update caching decisions no matter what we do in this + transaction (useful for e.g. precaching) */ + MAILBOX_TRANSACTION_FLAG_NO_CACHE_DEC = 0x10, + /* Sync transaction describes changes to mailbox that already happened + to another mailbox with whom we're syncing with (dsync) */ + MAILBOX_TRANSACTION_FLAG_SYNC = 0x20, + /* Don't trigger any notifications for this transaction. This + especially means the notify plugin. This would normally be used only + with _FLAG_SYNC. */ + MAILBOX_TRANSACTION_FLAG_NO_NOTIFY = 0x40, +}; + +enum mailbox_sync_flags { + /* Make sure we sync all external changes done to mailbox */ + MAILBOX_SYNC_FLAG_FULL_READ = 0x01, + /* Make sure we write all our internal changes into the mailbox */ + MAILBOX_SYNC_FLAG_FULL_WRITE = 0x02, + /* If it's not too much trouble, check if there are some changes */ + MAILBOX_SYNC_FLAG_FAST = 0x04, + + /* Don't sync expunges from our view */ + MAILBOX_SYNC_FLAG_NO_EXPUNGES = 0x08, + /* If mailbox is currently inconsistent, fix it instead of failing. */ + MAILBOX_SYNC_FLAG_FIX_INCONSISTENT = 0x40, + /* Syncing after an EXPUNGE command. This is just an informational + flag for plugins. */ + MAILBOX_SYNC_FLAG_EXPUNGE = 0x80, + /* Force doing a full resync of indexes. */ + MAILBOX_SYNC_FLAG_FORCE_RESYNC = 0x100, + /* FIXME: kludge until something better comes along: + Request full text search index optimization */ + MAILBOX_SYNC_FLAG_OPTIMIZE = 0x400 +}; + +enum mailbox_sync_type { + MAILBOX_SYNC_TYPE_EXPUNGE = 0x01, + MAILBOX_SYNC_TYPE_FLAGS = 0x02, + MAILBOX_SYNC_TYPE_MODSEQ = 0x04 +}; + +struct message_part; +struct mail_namespace; +struct mail_storage; +struct mail_search_args; +struct mail_search_result; +struct mail_keywords; +struct mail_save_context; +struct mailbox; +struct mailbox_transaction_context; + +struct mailbox_status { + uint32_t messages; /* STATUS_MESSAGES */ + uint32_t recent; /* STATUS_RECENT */ + uint32_t unseen; /* STATUS_UNSEEN */ + + uint32_t uidvalidity; /* STATUS_UIDVALIDITY */ + uint32_t uidnext; /* STATUS_UIDNEXT */ + + uint32_t first_unseen_seq; /* STATUS_FIRST_UNSEEN_SEQ */ + uint32_t first_recent_uid; /* STATUS_FIRST_RECENT_UID */ + uint32_t last_cached_seq; /* STATUS_LAST_CACHED_SEQ */ + uint64_t highest_modseq; /* STATUS_HIGHESTMODSEQ */ + /* 0 if no private index (STATUS_HIGHESTPVTMODSEQ) */ + uint64_t highest_pvt_modseq; + + /* NULL-terminated array of keywords (STATUS_KEYWORDS) */ + const ARRAY_TYPE(keywords) *keywords; + + /* These flags can be permanently modified (STATUS_PERMANENT_FLAGS) */ + enum mail_flags permanent_flags; + /* These flags can be modified (STATUS_PERMANENT_FLAGS) */ + enum mail_flags flags; + + /* All keywords can be permanently modified (STATUS_PERMANENT_FLAGS) */ + bool permanent_keywords:1; + /* More keywords can be created (STATUS_PERMANENT_FLAGS) */ + bool allow_new_keywords:1; + /* Modseqs aren't permanent (index is in memory) (STATUS_HIGHESTMODSEQ) */ + bool nonpermanent_modseqs:1; + /* Modseq tracking has never been enabled for this mailbox + yet. (STATUS_HIGHESTMODSEQ) */ + bool no_modseq_tracking:1; + + /* Messages have GUIDs (always set) */ + bool have_guids:1; + /* mailbox_save_set_guid() works (always set) */ + bool have_save_guids:1; + /* GUIDs are always 128bit (always set) */ + bool have_only_guid128:1; +}; + +struct mailbox_cache_field { + const char *name; + int decision; /* enum mail_cache_decision_type */ + /* last_used is unchanged, if it's (time_t)-1 */ + time_t last_used; +}; +ARRAY_DEFINE_TYPE(mailbox_cache_field, struct mailbox_cache_field); + +struct mailbox_metadata { + guid_128_t guid; + /* sum of virtual size of all messages in mailbox */ + uint64_t virtual_size; + /* sum of physical size of all messages in mailbox */ + uint64_t physical_size; + /* timestamp of when the first message was saved. + (time_t)-1 if there are no mails in the mailbox. */ + time_t first_save_date; + + /* Fields that have "temp" or "yes" caching decision. */ + const ARRAY_TYPE(mailbox_cache_field) *cache_fields; + /* Fields that should be precached */ + enum mail_fetch_field precache_fields; + + /* imapc backend returns this based on the remote NAMESPACE reply, + while currently other backends return "" and type the same as the + mailbox's real namespace type */ + const char *backend_ns_prefix; + enum mail_namespace_type backend_ns_type; +}; + +struct mailbox_update { + /* All non-zero fields are changed. */ + guid_128_t mailbox_guid; + uint32_t uid_validity; + uint32_t min_next_uid; + uint32_t min_first_recent_uid; + uint64_t min_highest_modseq; + uint64_t min_highest_pvt_modseq; + /* Modify caching decisions, terminated by name=NULL */ + const struct mailbox_cache_field *cache_updates; +}; + +struct mail_transaction_commit_changes { + /* Unreference the pool to free memory used by these changes. */ + pool_t pool; + + /* UIDVALIDITY for assigned UIDs. */ + uint32_t uid_validity; + /* UIDs assigned to saved messages. Not necessarily ascending. + If UID assignment wasn't required (e.g. LDA), this array may also be + empty. Otherwise all of the saved mails got an UID. */ + ARRAY_TYPE(seq_range) saved_uids; + + /* number of modseq changes that couldn't be changed as requested */ + unsigned int ignored_modseq_changes; + + /* Changes that occurred within this transaction */ + enum mail_index_transaction_change changes_mask; + /* User doesn't have read ACL for the mailbox, so don't show the + uid_validity / saved_uids. */ + bool no_read_perm; +}; + +struct mailbox_sync_rec { + uint32_t seq1, seq2; + enum mailbox_sync_type type; +}; +struct mailbox_sync_status { + /* There are expunges that haven't been synced yet */ + bool sync_delayed_expunges:1; +}; + +struct mailbox_expunge_rec { + /* IMAP UID */ + uint32_t uid; + /* 128 bit GUID. If the actual GUID has a different size, this + contains last bits of its SHA1 sum. */ + guid_128_t guid_128; +}; +ARRAY_DEFINE_TYPE(mailbox_expunge_rec, struct mailbox_expunge_rec); + +enum mail_lookup_abort { + /* Perform everything no matter what it takes */ + MAIL_LOOKUP_ABORT_NEVER = 0, + /* Abort if the operation would require reading message header/body or + otherwise opening the mail file (e.g. with dbox metadata is read by + opening and reading the file). This still allows somewhat fast + operations to be performed, such as stat()ing a file. */ + MAIL_LOOKUP_ABORT_READ_MAIL, + /* Abort if the operation can't be done fully using cache file */ + MAIL_LOOKUP_ABORT_NOT_IN_CACHE, + /* Abort if the operation can't be done fully using cache file. + * During this lookup all cache lookups that have "no" decision + * will be changed to "tmp". This way the field will start to be + * cached in the future. */ + MAIL_LOOKUP_ABORT_NOT_IN_CACHE_START_CACHING, +}; + +enum mail_access_type { + MAIL_ACCESS_TYPE_DEFAULT = 0, + /* Mail is being used for searching */ + MAIL_ACCESS_TYPE_SEARCH, + /* Mail is being used for sorting results */ + MAIL_ACCESS_TYPE_SORT, +}; + +struct mail { + /* always set */ + struct mailbox *box; + struct mailbox_transaction_context *transaction; + uint32_t seq, uid; + + bool expunged:1; + bool saving:1; /* This mail is still being saved */ + bool has_nuls:1; /* message data is known to contain NULs */ + bool has_no_nuls:1; /* -''- known to not contain NULs */ + + /* Mail's header/body stream was opened (or attempted to be opened) + within this request. If lookup_abort!=MAIL_LOOKUP_ABORT_NEVER, this + can't become TRUE. */ + bool mail_stream_accessed:1; + /* Mail's fast metadata was accessed within this request, e.g. the mail + file was stat()ed. If mail_stream_opened==TRUE, this value isn't + accurate anymore, because some backends may always set this when + stream is opened and some don't. If lookup_abort is + MAIL_LOOKUP_ABORT_NOT_IN_CACHE, this can't become TRUE. */ + bool mail_metadata_accessed:1; + + enum mail_access_type access_type; + + /* If the lookup is aborted, error is set to MAIL_ERROR_NOTPOSSIBLE */ + enum mail_lookup_abort lookup_abort; +}; + +struct mail_storage_callbacks { + /* "* OK <text>" */ + void (*notify_ok)(struct mailbox *mailbox, const char *text, + void *context); + /* "* NO <text>" */ + void (*notify_no)(struct mailbox *mailbox, const char *text, + void *context); + +}; + +struct mailbox_virtual_pattern { + struct mail_namespace *ns; + const char *pattern; +}; +ARRAY_DEFINE_TYPE(mailbox_virtual_patterns, struct mailbox_virtual_pattern); +ARRAY_DEFINE_TYPE(mail_storage, struct mail_storage *); +ARRAY_DEFINE_TYPE(mailboxes, struct mailbox *); + +extern ARRAY_TYPE(mail_storage) mail_storage_classes; + +typedef void mailbox_notify_callback_t(struct mailbox *box, void *context); + +void mail_storage_init(void); +void mail_storage_deinit(void); + +/* register all mail storages */ +void mail_storage_register_all(void); + +/* Register mail storage class with given name - all methods that are NULL + are set to default methods */ +void mail_storage_class_register(struct mail_storage *storage_class); +void mail_storage_class_unregister(struct mail_storage *storage_class); +/* Find mail storage class by name */ +struct mail_storage *mail_storage_find_class(const char *name); + +/* Create a new instance of registered mail storage class with given + storage-specific data. If driver is NULL, it's tried to be autodetected + from ns location. If ns location is NULL, it uses the first storage that + exists. The storage is put into ns->storage. */ +int mail_storage_create(struct mail_namespace *ns, const char *driver, + enum mail_storage_flags flags, const char **error_r) + ATTR_NULL(2); +int mail_storage_create_full(struct mail_namespace *ns, const char *driver, + const char *data, enum mail_storage_flags flags, + struct mail_storage **storage_r, + const char **error_r) ATTR_NULL(2); +void mail_storage_unref(struct mail_storage **storage); + +/* Returns the mail storage settings. */ +const struct mail_storage_settings * +mail_storage_get_settings(struct mail_storage *storage) ATTR_PURE; +struct mail_user *mail_storage_get_user(struct mail_storage *storage) ATTR_PURE; + +/* Set storage callback functions to use. */ +void mail_storage_set_callbacks(struct mail_storage *storage, + struct mail_storage_callbacks *callbacks, + void *context) ATTR_NULL(3); + +/* Purge storage's mailboxes (freeing disk space from expunged mails), + if supported by the storage. Otherwise just a no-op. */ +int mail_storage_purge(struct mail_storage *storage); + +/* Returns the error message of last occurred error. */ +const char * ATTR_NOWARN_UNUSED_RESULT +mail_storage_get_last_error(struct mail_storage *storage, + enum mail_error *error_r) ATTR_NULL(2); +/* Wrapper for mail_storage_get_last_error(); */ +const char * ATTR_NOWARN_UNUSED_RESULT +mailbox_get_last_error(struct mailbox *box, enum mail_error *error_r) + ATTR_NULL(2); +/* Wrapper for mail_storage_get_last_error(); */ +enum mail_error mailbox_get_last_mail_error(struct mailbox *box); + +const char * ATTR_NOWARN_UNUSED_RESULT +mail_storage_get_last_internal_error(struct mail_storage *storage, + enum mail_error *error_r) ATTR_NULL(2); +/* Wrapper for mail_storage_get_last_internal_error(); */ +const char * ATTR_NOWARN_UNUSED_RESULT +mailbox_get_last_internal_error(struct mailbox *box, + enum mail_error *error_r) ATTR_NULL(2); + +/* Save the last error until it's popped. This is useful for cases where the + storage has already failed, but the cleanup code path changes the error to + something else unwanted. */ +void mail_storage_last_error_push(struct mail_storage *storage); +void mail_storage_last_error_pop(struct mail_storage *storage); + +/* Returns TRUE if mailboxes are files. */ +bool mail_storage_is_mailbox_file(struct mail_storage *storage) ATTR_PURE; + +/* Initialize mailbox without actually opening any files or verifying that + it exists. Note that append and copy may open the selected mailbox again + with possibly different readonly-state. */ +struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname, + enum mailbox_flags flags); +/* Like mailbox_alloc(), but use mailbox GUID. */ +struct mailbox *mailbox_alloc_guid(struct mailbox_list *list, + const guid_128_t guid, + enum mailbox_flags flags); +/* Initialize mailbox for a particular user without actually opening any files + or verifying that it exists. The mname parameter is normally equal to the + mailbox vname, except when the MAILBOX_FLAG_SPECIAL_USE flag is set, in which + case it is the special-use flag. */ +struct mailbox * +mailbox_alloc_for_user(struct mail_user *user, const char *mname, + enum mailbox_flags flags); + +/* Get mailbox existence state. If auto_boxes=FALSE, return + MAILBOX_EXISTENCE_NONE for autocreated mailboxes that haven't been + physically created yet */ +int mailbox_exists(struct mailbox *box, bool auto_boxes, + enum mailbox_existence *existence_r); +/* Open the mailbox. If this function isn't called explicitly, it's also called + internally by lib-storage when necessary. */ +int mailbox_open(struct mailbox *box); +/* Open mailbox as read-only using the given stream as input. */ +int mailbox_open_stream(struct mailbox *box, struct istream *input); +/* Close mailbox. Same as if mailbox was freed and re-allocated. */ +void mailbox_close(struct mailbox *box); +/* Close and free the mailbox. */ +void mailbox_free(struct mailbox **box); + +/* Returns TRUE if box1 points to the same mailbox as ns2/vname2. */ +bool mailbox_equals(const struct mailbox *box1, + const struct mail_namespace *ns2, + const char *vname2) ATTR_PURE; +/* Returns TRUE if the mailbox is user's INBOX or another user's shared INBOX */ +bool mailbox_is_any_inbox(struct mailbox *box); + +/* Returns TRUE if the mailbox has the specified special use flag assigned. */ +bool mailbox_has_special_use(struct mailbox *box, const char *special_use); + +/* Change mailbox_verify_create_name() to not verify new mailbox name + restrictions (but still check that it's a valid existing name). This is + mainly used by dsync to make sure the sync works even though the original + name isn't valid anymore. */ +void mailbox_skip_create_name_restrictions(struct mailbox *box, bool set); +/* Returns -1 if mailbox_create() is guaranteed to fail because the mailbox + name is invalid, 0 not. The error message contains a reason. */ +int mailbox_verify_create_name(struct mailbox *box); +/* Create a mailbox. Returns failure if it already exists. Mailbox name is + allowed to contain multiple new nonexistent hierarchy levels. If directory + is TRUE, the mailbox should be created so that it can contain children. The + mailbox itself doesn't have to be created as long as it shows up in LIST. + If update is non-NULL, its contents are used to set initial mailbox + metadata. */ +int mailbox_create(struct mailbox *box, const struct mailbox_update *update, + bool directory) ATTR_NULL(2); +/* Update existing mailbox's metadata. */ +int mailbox_update(struct mailbox *box, const struct mailbox_update *update); +/* Delete mailbox (and its parent directory, if it has no siblings) */ +int mailbox_delete(struct mailbox *box); +/* Delete mailbox, but only if it's empty. If it's not, fails with + MAIL_ERROR_EXISTS. */ +int mailbox_delete_empty(struct mailbox *box); +/* Rename mailbox (and its children). Renaming across different mailbox lists + is possible only between private namespaces and storages of the same type. + If the rename fails, the error is set to src's storage. */ +int mailbox_rename(struct mailbox *src, struct mailbox *dest); +/* Subscribe/unsubscribe mailbox. Subscribing to + nonexistent mailboxes is optional. */ +int mailbox_set_subscribed(struct mailbox *box, bool set); +/* Returns TRUE if mailbox is subscribed, FALSE if not. This function + doesn't refresh the subscriptions list, but assumes that it's been done by + e.g. mailbox_list_iter*(). */ +bool mailbox_is_subscribed(struct mailbox *box); + +/* Enable the given feature for the mailbox. */ +int mailbox_enable(struct mailbox *box, enum mailbox_feature features); +/* Returns all enabled features. */ +enum mailbox_feature +mailbox_get_enabled_features(struct mailbox *box) ATTR_PURE; + +/* Returns storage of given mailbox */ +struct mail_storage *mailbox_get_storage(const struct mailbox *box) ATTR_PURE; +/* Return namespace of given mailbox. */ +struct mail_namespace * +mailbox_get_namespace(const struct mailbox *box) ATTR_PURE; +/* Returns the storage's settings. */ +const struct mail_storage_settings * +mailbox_get_settings(struct mailbox *box) ATTR_PURE; +/* Returns the mailbox's settings, or NULL if there are none. */ +const struct mailbox_settings * +mailbox_settings_find(struct mail_namespace *ns, const char *vname); + +/* Returns the (virtual) name of the given mailbox. */ +const char *mailbox_get_vname(const struct mailbox *box) ATTR_PURE; +/* Returns the backend name of given mailbox. */ +const char *mailbox_get_name(const struct mailbox *box) ATTR_PURE; + +/* Returns TRUE if mailbox is read-only. */ +bool mailbox_is_readonly(struct mailbox *box); +/* Returns TRUE if two mailboxes point to the same physical mailbox. */ +bool mailbox_backends_equal(const struct mailbox *box1, + const struct mailbox *box2); +/* Returns TRUE if mailbox is now in inconsistent state, meaning that + the message IDs etc. may have changed - only way to recover this + would be to fully close the mailbox and reopen it. With IMAP + connection this would mean a forced disconnection since we can't + do forced CLOSE. */ +bool mailbox_is_inconsistent(struct mailbox *box); + +/* Gets the mailbox status information. If mailbox isn't opened yet, try to + return the results from mailbox list indexes. Otherwise the mailbox is + opened and synced. If the mailbox is already opened, no syncing is done + automatically. */ +int mailbox_get_status(struct mailbox *box, enum mailbox_status_items items, + struct mailbox_status *status_r); +/* Gets the mailbox status, requires that mailbox is already opened. */ +void mailbox_get_open_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r); +/* Gets mailbox metadata */ +int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); +/* Returns a mask of flags that are private to user in this mailbox + (as opposed to flags shared between users). */ +enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box); + +/* Synchronize the mailbox. */ +struct mailbox_sync_context * +mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags); +bool mailbox_sync_next(struct mailbox_sync_context *ctx, + struct mailbox_sync_rec *sync_rec_r); +int mailbox_sync_deinit(struct mailbox_sync_context **ctx, + struct mailbox_sync_status *status_r); +/* One-step mailbox synchronization. Use this if you don't care about + changes. */ +int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags); + +/* Call given callback function when something changes in the mailbox. */ +void mailbox_notify_changes(struct mailbox *box, + mailbox_notify_callback_t *callback, void *context) + ATTR_NULL(3); +#define mailbox_notify_changes(box, callback, context) \ + mailbox_notify_changes(box, (mailbox_notify_callback_t *)callback, \ + (void *)((char *)context - CALLBACK_TYPECHECK(callback, \ + void (*)(struct mailbox *, typeof(context))))) +void mailbox_notify_changes_stop(struct mailbox *box); + +struct mailbox_transaction_context * +mailbox_transaction_begin(struct mailbox *box, + enum mailbox_transaction_flags flags, + const char *reason); +int mailbox_transaction_commit(struct mailbox_transaction_context **t); +int mailbox_transaction_commit_get_changes( + struct mailbox_transaction_context **t, + struct mail_transaction_commit_changes *changes_r); +void mailbox_transaction_rollback(struct mailbox_transaction_context **t); +/* Return the number of active transactions for the mailbox. */ +unsigned int mailbox_transaction_get_count(const struct mailbox *box) ATTR_PURE; +/* When committing transaction, drop flag/keyword updates for messages whose + modseq is larger than max_modseq. Save those messages' sequences to the + given array. */ +void mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t, + uint64_t max_modseq, + ARRAY_TYPE(seq_range) *seqs); + +struct mailbox * +mailbox_transaction_get_mailbox(const struct mailbox_transaction_context *t) + ATTR_PURE; + +/* Convert uid range to sequence range. */ +void mailbox_get_seq_range(struct mailbox *box, uint32_t uid1, uint32_t uid2, + uint32_t *seq1_r, uint32_t *seq2_r); +/* Convert sequence range to uid range. If sequences contain + (uint32_t)-1 to specify "*", they're preserved. */ +void mailbox_get_uid_range(struct mailbox *box, + const ARRAY_TYPE(seq_range) *seqs, + ARRAY_TYPE(seq_range) *uids); +/* Get list of messages' that have been expunged after prev_modseq and that + exist in uids_filter range. UIDs that have been expunged after the last + mailbox sync aren't returned. Returns TRUE if ok, FALSE if modseq is lower + than we can check for (but expunged_uids is still set as best as it can). */ +bool mailbox_get_expunges(struct mailbox *box, uint64_t prev_modseq, + const ARRAY_TYPE(seq_range) *uids_filter, + ARRAY_TYPE(mailbox_expunge_rec) *expunges); +/* Same as mailbox_get_expunges(), but return only list of UIDs. Not caring + about GUIDs is slightly faster. */ +bool mailbox_get_expunged_uids(struct mailbox *box, uint64_t prev_modseq, + const ARRAY_TYPE(seq_range) *uids_filter, + ARRAY_TYPE(seq_range) *expunged_uids); + +/* Initialize header lookup for given headers. */ +struct mailbox_header_lookup_ctx * +mailbox_header_lookup_init(struct mailbox *box, const char *const headers[]); +void mailbox_header_lookup_ref(struct mailbox_header_lookup_ctx *ctx); +void mailbox_header_lookup_unref(struct mailbox_header_lookup_ctx **ctx); +/* Merge two header lookups. */ +struct mailbox_header_lookup_ctx * +mailbox_header_lookup_merge(const struct mailbox_header_lookup_ctx *hdr1, + const struct mailbox_header_lookup_ctx *hdr2); + +/* Initialize new search request. If sort_program is non-NULL, the messages are + returned in the requested order, otherwise from first to last. */ +struct mail_search_context * ATTR_NULL(3, 5) +mailbox_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); +/* Deinitialize search request. */ +int mailbox_search_deinit(struct mail_search_context **ctx); +/* Search the next message. Returns TRUE if found, FALSE if not. */ +bool mailbox_search_next(struct mail_search_context *ctx, struct mail **mail_r); +/* Like mailbox_search_next(), but don't spend too much time searching. + Returns FALSE with tryagain_r=FALSE if finished, and tryagain_r=TRUE if + more results will be returned by calling the function again. */ +bool mailbox_search_next_nonblock(struct mail_search_context *ctx, + struct mail **mail_r, bool *tryagain_r); +/* Returns TRUE if some messages were already expunged and we couldn't + determine correctly if those messages should have been returned in this + search. */ +bool mailbox_search_seen_lost_data(struct mail_search_context *ctx); +/* Detach the given mail from the search context. This allows the mail to live + even after mail_search_context has been freed. */ +void mailbox_search_mail_detach(struct mail_search_context *ctx, + struct mail *mail); + +/* Remember the search result for future use. This must be called before the + first mailbox_search_next*() call. */ +struct mail_search_result * +mailbox_search_result_save(struct mail_search_context *ctx, + enum mailbox_search_result_flags flags); +/* Free memory used by search result. */ +void mailbox_search_result_free(struct mail_search_result **result); +/* A simplified API for searching and saving the result. */ +int mailbox_search_result_build(struct mailbox_transaction_context *t, + struct mail_search_args *args, + enum mailbox_search_result_flags flags, + struct mail_search_result **result_r); +/* Return all messages' UIDs in the search result. */ +const ARRAY_TYPE(seq_range) * +mailbox_search_result_get(struct mail_search_result *result); +/* Return messages that have been removed and added since the last sync call. + This function must not be called if search result wasn't saved with + _QUEUE_SYNC flag. */ +void mailbox_search_result_sync(struct mail_search_result *result, + ARRAY_TYPE(seq_range) *removed_uids, + ARRAY_TYPE(seq_range) *added_uids); + +/* Build mail_keywords from NULL-terminated keywords list. Any duplicate + keywords are removed. Returns 0 if successful, -1 if there are invalid + keywords (error is set). */ +int mailbox_keywords_create(struct mailbox *box, const char *const keywords[], + struct mail_keywords **keywords_r); +/* Like mailbox_keywords_create(), except ignore invalid keywords. */ +struct mail_keywords * +mailbox_keywords_create_valid(struct mailbox *box, + const char *const keywords[]); +struct mail_keywords * +mailbox_keywords_create_from_indexes(struct mailbox *box, + const ARRAY_TYPE(keyword_indexes) *idx); +/* Return union of two mail_keywords. They must be created in the same + mailbox. */ +struct mail_keywords *mailbox_keywords_merge(struct mail_keywords *keywords1, + struct mail_keywords *keywords2); +void mailbox_keywords_ref(struct mail_keywords *keywords); +void mailbox_keywords_unref(struct mail_keywords **keywords); +/* Returns TRUE if keyword is valid, FALSE and error if not. */ +bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword, + const char **error_r); + +/* Initialize saving a new mail. You must not try to save more than one mail + at a time. */ +struct mail_save_context * +mailbox_save_alloc(struct mailbox_transaction_context *t); +/* Set the flags and keywords. Nothing is set by default. */ +void mailbox_save_set_flags(struct mail_save_context *ctx, + enum mail_flags flags, + struct mail_keywords *keywords); +/* Copy flags and keywords from given mail. */ +void mailbox_save_copy_flags(struct mail_save_context *ctx, struct mail *mail); +/* Set message's modseq to be at least min_modseq. */ +void mailbox_save_set_min_modseq(struct mail_save_context *ctx, + uint64_t min_modseq); +/* If received date isn't specified the current time is used. timezone_offset + specifies the preferred timezone in minutes, but it may be ignored if + backend doesn't support storing it. */ +void mailbox_save_set_received_date(struct mail_save_context *ctx, + time_t received_date, int timezone_offset); +/* Set the "message saved" date. This should be set only when you're + replicating/restoring an existing mailbox. */ +void mailbox_save_set_save_date(struct mail_save_context *ctx, + time_t save_date); +/* Set the envelope sender. This is currently used only with mbox files to + specify the address in From_-line. */ +void mailbox_save_set_from_envelope(struct mail_save_context *ctx, + const char *envelope); +/* Set message's UID. If UID is smaller than the current next_uid, it's given + a new UID anyway. */ +void mailbox_save_set_uid(struct mail_save_context *ctx, uint32_t uid); +/* Set globally unique ID for the saved mail. A new GUID is generated by + default. This function should usually be called only when copying an + existing mail (or restoring a mail from backup). */ +void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid); +/* Set message's POP3 UIDL, if the backend supports it. */ +void mailbox_save_set_pop3_uidl(struct mail_save_context *ctx, + const char *uidl); +/* Specify ordering for POP3 messages. The default is to add them to the end + of the mailbox. Not all backends support this. */ +void mailbox_save_set_pop3_order(struct mail_save_context *ctx, + unsigned int order); +/* Returns the destination mail */ +struct mail *mailbox_save_get_dest_mail(struct mail_save_context *ctx); +/* Begin saving the message. All mail_save_set_*() calls must have been called + before this function. If the save initialization fails, the context is freed + and -1 is returned. After beginning the save you should keep calling + i_stream_read() and calling mailbox_save_continue() as long as there's + more input. */ +int mailbox_save_begin(struct mail_save_context **ctx, struct istream *input); +int mailbox_save_continue(struct mail_save_context *ctx); +int mailbox_save_finish(struct mail_save_context **ctx); +void mailbox_save_cancel(struct mail_save_context **ctx); + +struct mailbox_transaction_context * +mailbox_save_get_transaction(struct mail_save_context *ctx); + +/* Copy the given message. You'll need to specify the flags etc. using the + mailbox_save_*() functions. */ +int mailbox_copy(struct mail_save_context **ctx, struct mail *mail); +/* Move the given message. This is usually equivalent to copy+expunge, + but without enforcing quota. */ +int mailbox_move(struct mail_save_context **ctx, struct mail *mail); +/* Same as mailbox_copy(), but treat the message as if it's being saved, + not copied. (For example: New mail delivered to multiple maildirs, with + each mails being hard link copies.) */ +int mailbox_save_using_mail(struct mail_save_context **ctx, struct mail *mail); + +struct mail *mail_alloc(struct mailbox_transaction_context *t, + enum mail_fetch_field wanted_fields, + struct mailbox_header_lookup_ctx *wanted_headers) + ATTR_NULL(3); +void mail_free(struct mail **mail); +void mail_set_seq(struct mail *mail, uint32_t seq); +/* Returns TRUE if successful, FALSE if message doesn't exist. + mail_*() functions shouldn't be called if FALSE is returned. */ +bool mail_set_uid(struct mail *mail, uint32_t uid); + +/* Add wanted fields/headers on top of existing ones. These will be forgotten + after the next mail_set_seq/uid() that closes the existing mail. Note that + it's valid to call this function while there is no mail assigned + (mail->seq==0), i.e. this is called before any mail_set_seq/uid() or after + mail.close(). */ +void mail_add_temp_wanted_fields(struct mail *mail, + enum mail_fetch_field fields, + struct mailbox_header_lookup_ctx *headers) + ATTR_NULL(3); + +/* Returns mail's event. This lazily creates the event when called for the + first time for the mail. */ +struct event *mail_event(struct mail *mail); +/* Returns message's flags */ +enum mail_flags mail_get_flags(struct mail *mail); +/* Returns message's keywords */ +const char *const *mail_get_keywords(struct mail *mail); +/* Returns message's keywords */ +const ARRAY_TYPE(keyword_indexes) *mail_get_keyword_indexes(struct mail *mail); +/* Returns message's modseq */ +uint64_t mail_get_modseq(struct mail *mail); +/* Returns message's private modseq, or 0 if message hasn't had any + private flag changes. This is useful only for shared mailboxes that have + a private index defined. */ +uint64_t mail_get_pvt_modseq(struct mail *mail); + +/* Returns message's MIME parts */ +int mail_get_parts(struct mail *mail, struct message_part **parts_r); + +/* Get the Date-header of the mail. Timezone is in minutes. date=0 if it + wasn't found or it was invalid. */ +int mail_get_date(struct mail *mail, time_t *date_r, int *timezone_r); +/* Get the time when the mail was received (IMAP INTERNALDATE). */ +int mail_get_received_date(struct mail *mail, time_t *date_r); +/* Get the time when the mail was saved into this mailbox. This returns -1 on + error, 0 if a real save date is not supported and a fall-back date is used, + and 1 when a save date was successfully retrieved. */ +int mail_get_save_date(struct mail *mail, time_t *date_r); + +/* Get the space used by the mail as seen by the reader. Linefeeds are always + counted as being CR+LF. */ +int mail_get_virtual_size(struct mail *mail, uoff_t *size_r); +/* Get the size of the stream returned by mail_get_stream(). */ +int mail_get_physical_size(struct mail *mail, uoff_t *size_r); + +/* Get value for single header field, or NULL if header wasn't found. + Returns 1 if header was found, 0 if not, -1 if error. */ +int mail_get_first_header(struct mail *mail, const char *field, + const char **value_r); +/* Like mail_get_first_header(), but decode MIME encoded words to UTF-8. + Also multiline headers are returned unfolded. + + Do not use this function for getting structured fields (e.g. address fields), + because decoding may break the structuring. Instead parse them first and + only afterwards decode the encoded words. */ +int mail_get_first_header_utf8(struct mail *mail, const char *field, + const char **value_r); +/* Return a NULL-terminated list of values for each found field. + Returns 1 if headers were found, 0 if not (value_r[0]==NULL) or + -1 if error. */ +int mail_get_headers(struct mail *mail, const char *field, + const char *const **value_r); +/* Like mail_get_headers(), but decode MIME encoded words to UTF-8. + Also multiline headers are returned unfolded. + Do not use for structured fields (see mail_get_first_header_utf8()). */ +int mail_get_headers_utf8(struct mail *mail, const char *field, + const char *const **value_r); +/* Returns stream containing specified headers. The returned stream will be + automatically freed when the mail is closed, or when another + mail_get_header_stream() call is made (so you can't have multiple header + streams open at the same time). */ +int mail_get_header_stream(struct mail *mail, + struct mailbox_header_lookup_ctx *headers, + struct istream **stream_r); +/* Returns input stream pointing to beginning of message header. + hdr_size and body_size are updated unless they're NULL. The returned stream + is destroyed automatically, don't unreference it. */ +int mail_get_stream(struct mail *mail, struct message_size *hdr_size, + struct message_size *body_size, struct istream **stream_r) + ATTR_NULL(2, 3); +/* Same as mail_get_stream(), but specify a reason why the mail is being read. + This can be useful for debugging purposes. */ +int mail_get_stream_because(struct mail *mail, struct message_size *hdr_size, + struct message_size *body_size, + const char *reason, struct istream **stream_r) + ATTR_NULL(2, 3); +/* Similar to mail_get_stream(), but the stream may or may not contain the + message body. */ +int mail_get_hdr_stream(struct mail *mail, struct message_size *hdr_size, + struct istream **stream_r) ATTR_NULL(2); +/* Same as mail_get_hdr_stream(), but specify a reason why the header is being + read. This can be useful for debugging purposes. */ +int mail_get_hdr_stream_because(struct mail *mail, + struct message_size *hdr_size, + const char *reason, struct istream **stream_r); +/* Returns the message part's body decoded to 8bit binary. If the + Content-Transfer-Encoding isn't supported, returns -1 and sets error to + MAIL_ERROR_CONVERSION. If the part refers to a multipart, all of its + children are returned decoded. Note that the returned stream must be + unreferenced, unlike mail_get_*stream*() which automatically free it. */ +int mail_get_binary_stream(struct mail *mail, const struct message_part *part, + bool include_hdr, uoff_t *size_r, + bool *binary_r, struct istream **stream_r); +/* Like mail_get_binary_stream(), but only return the size. */ +int mail_get_binary_size(struct mail *mail, const struct message_part *part, + bool include_hdr, uoff_t *size_r, + unsigned int *lines_r); + +/* Get any of the "special" fields. Unhandled specials are returned as "". */ +int mail_get_special(struct mail *mail, enum mail_fetch_field field, + const char **value_r); +/* Returns the mail for the physical message. Normally this is the mail itself, + but in virtual mailboxes it points to the backend mailbox. */ +int mail_get_backend_mail(struct mail *mail, struct mail **real_mail_r); + +/* Retrieve and parse the value of the Message-ID header field. Returns 1 if the + header was found and it contains a valid message ID, 0 if the header was not + found or no valid message ID was contained in it, and -1 if an error occurred + while retrieving the header. Returns the message ID value including '<' and + '>' in the *value_r return parameter or NULL if the header wasn't found or + its value was invalid. */ +int mail_get_message_id(struct mail *mail, const char **value_r); + +/* Update message flags. */ +void mail_update_flags(struct mail *mail, enum modify_type modify_type, + enum mail_flags flags); +/* Update message keywords. */ +void mail_update_keywords(struct mail *mail, enum modify_type modify_type, + struct mail_keywords *keywords); +/* Update message's modseq to be at least min_modseq. */ +void mail_update_modseq(struct mail *mail, uint64_t min_modseq); +/* Update message's private modseq to be at least min_pvt_modseq. */ +void mail_update_pvt_modseq(struct mail *mail, uint64_t min_pvt_modseq); + +/* Update message's POP3 UIDL (if possible). */ +void mail_update_pop3_uidl(struct mail *mail, const char *uidl); +/* Expunge this message. Sequence numbers don't change until commit. */ +void mail_expunge(struct mail *mail); + +/* Add missing fields to cache. */ +int mail_precache(struct mail *mail); +/* Mark a cached field corrupted and have it recalculated. */ +void mail_set_cache_corrupted(struct mail *mail, + enum mail_fetch_field field, + const char *reason); + +/* Return 128 bit GUID using input string. If guid is already 128 bit hex + encoded, it's returned as-is. Otherwise SHA1 sum is taken and its last + 128 bits are returned. */ +void mail_generate_guid_128_hash(const char *guid, guid_128_t guid_128_r); + +/* Parse a human-writable string into a timestamp. utc_r controls whether + the returned timestamp should be treated as an exact UTC time (TRUE), or + whether this is a human-given date where the timestamp could be adjusted + by the matched mails' timezones (see MAIL_SEARCH_ARG_FLAG_USE_TZ). + + Returns 0 and timestamp on success, -1 if the string couldn't be parsed. + Currently supported string formats: yyyy-mm-dd (utc=FALSE), + imap date (utc=FALSE), unix timestamp (utc=TRUE), interval (e.g. n days, + utc=TRUE). */ +int mail_parse_human_timestamp(const char *str, time_t *timestamp_r, + bool *utc_r); + +#endif |