mail-storage.c revision f86e4521d7864d385e3397a58eaa4b9c8ed178d8
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen/* Message to show to users when critical error occurs */
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen "Internal error occurred. Refer to server log for more information."
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenstruct mail_storage_module_register mail_storage_module_register = { 0 };
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenstruct mail_module_register mail_module_register = { 0 };
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenstruct mail_storage_mail_index_module mail_storage_mail_index_module =
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen MODULE_CONTEXT_INIT(&mail_index_module_register);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenvoid (*hook_mail_storage_created)(struct mail_storage *storage);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenvoid (*hook_mailbox_opened)(struct mailbox *box) = NULL;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenstatic ARRAY_DEFINE(storages, struct mail_storage *);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenvoid mail_storage_class_register(struct mail_storage *storage_class)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen /* append it after the list, so the autodetection order is correct */
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenvoid mail_storage_class_unregister(struct mail_storage *storage_class)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen unsigned int i, count;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen for (i = 0; i < count; i++) {
008a83e9f680f04f69789fb702232416eab2a86cTimo Sirainenvoid mail_storage_parse_env(enum mail_storage_flags *flags_r,
008a83e9f680f04f69789fb702232416eab2a86cTimo Sirainen const char *str;
008a83e9f680f04f69789fb702232416eab2a86cTimo Sirainen *flags_r |= MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL;
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen *flags_r |= MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *flags_r |= MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX;
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen if ((*flags_r & MAIL_STORAGE_FLAG_MMAP_DISABLE) == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_fatal("mail_nfs_index=yes requires mmap_disable=yes");
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen if ((*flags_r & MAIL_STORAGE_FLAG_FSYNC_DISABLE) != 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_fatal("mail_nfs_index=yes requires fsync_disable=no");
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (str != NULL && (str = strchr(str, '%')) != NULL &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *flags_r |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainenstatic struct mail_storage *mail_storage_find(const char *name)
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen unsigned int i, count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenmail_storage_autodetect(const char *data, enum mail_storage_flags flags)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i, count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < count; i++) {
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenmail_storage_set_autodetection(const char **data, const char **driver,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen const char *p;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* check if data is in driver:data format (eg. mbox:~/mail) */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen while (i_isalnum(*p)) p++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* no autodetection if the storage format is given. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenint mail_storage_create(struct mail_namespace *ns, const char *driver,
e2e105f6182f550efa82f77d2a46b3e8a2d4da10Timo Sirainen const char **error_r)
e2e105f6182f550efa82f77d2a46b3e8a2d4da10Timo Sirainen unsigned int i, count;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen mail_storage_set_autodetection(&data, &driver, &flags);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen /* use the first driver that works */
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen storage_class = mail_storage_autodetect(data, flags);
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen "Ambiguous mail location setting, "
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen "don't know what to do with it: %s "
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen "(try prefixing it with mbox: or maildir:)",
e4423c16a4f798ecf75ca2b0c3ef834000faed4bTimo Sirainen for (i = 0; i < count; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen storage->user = p_strdup(storage->pool, user);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen p_new(storage->pool, struct mail_storage_callbacks, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen p_array_init(&storage->module_contexts, storage->pool, 5);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (classes[i]->v.create(storage, data, error_r) == 0)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0 && count > 1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_info("%s: Couldn't create mail storage %s: %s",
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen /* try the next one */
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen *error_r = t_strdup_printf("%s: %s", classes[0]->name,
73b251f13abfbd8e06c8c78784eb570d28fe7e40Timo Sirainen if (home == NULL || *home == '\0') home = "(not set)";
73b251f13abfbd8e06c8c78784eb570d28fe7e40Timo Sirainen "Mail storage autodetection failed with home=%s", home);
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainenvoid mail_storage_destroy(struct mail_storage **_storage)
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainenvoid mail_storage_clear_error(struct mail_storage *storage)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenvoid mail_storage_set_error(struct mail_storage *storage,
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenvoid mail_storage_set_internal_error(struct mail_storage *storage)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mail_storage_set_critical(struct mail_storage *storage,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen const char *fmt, ...)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* critical errors may contain sensitive data, so let user
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen see only "Internal error" with a timestamp to make it
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen easier to look from log files the actual error message. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenchar mail_storage_get_hierarchy_sep(struct mail_storage *storage)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return mailbox_list_get_hierarchy_sep(storage->list);
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainenstruct mailbox_list *mail_storage_get_list(struct mail_storage *storage)
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainenstruct mail_namespace *mail_storage_get_namespace(struct mail_storage *storage)
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainenvoid mail_storage_set_callbacks(struct mail_storage *storage,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint mail_storage_mailbox_create(struct mail_storage *storage, const char *name,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!mailbox_list_is_valid_create_name(storage->list, name)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "Invalid mailbox name");
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return storage->v.mailbox_create(storage, name, directory);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst char *mail_storage_get_last_error(struct mail_storage *storage,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* We get here only in error situations, so we have to return some
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen error. If storage->error is NONE, it means we forgot to set it at
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen some point.. */
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return storage->error_string != NULL ? storage->error_string :
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen "BUG: Unknown internal error";
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen /* This shouldn't happen.. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenconst char *mail_storage_get_mailbox_path(struct mail_storage *storage,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return mailbox_list_get_path(storage->list, name,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenconst char *mail_storage_get_mailbox_control_dir(struct mail_storage *storage,
a04b6515c20b431294626400e173d81f3d25889bTimo Sirainen return mailbox_list_get_path(storage->list, name,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst char *mail_storage_get_mailbox_index_dir(struct mail_storage *storage,
008a83e9f680f04f69789fb702232416eab2a86cTimo Sirainen return mailbox_list_get_path(storage->list, name,
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainenmail_storage_get_list_flags(enum mail_storage_flags storage_flags)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if ((storage_flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((storage_flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_FULL_FS_ACCESS;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((storage_flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen list_flags |= MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if ((storage_flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenbool mail_storage_set_error_from_errno(struct mail_storage *storage)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen mail_storage_set_error(storage, error, error_string);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstruct mailbox *mailbox_open(struct mail_storage *storage, const char *name,
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen if (!mailbox_list_is_valid_existing_name(storage->list, name)) {
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen "Invalid mailbox name");
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen box = storage->v.mailbox_open(storage, name, input, flags);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen if (hook_mailbox_opened != NULL && box != NULL)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen i_panic("Trying to close mailbox %s with open transactions",
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenstruct mail_storage *mailbox_get_storage(struct mailbox *box)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenconst char *mailbox_get_name(struct mailbox *box)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenbool mailbox_allow_new_keywords(struct mailbox *box)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenmailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenbool mailbox_sync_next(struct mailbox_sync_context *ctx,
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen return ctx->box->v.sync_next(ctx, sync_rec_r);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenint mailbox_sync_deinit(struct mailbox_sync_context **_ctx,
39e8567467cfe8eb63c00708a8653e92758908b9Timo Sirainen return ctx->box->v.sync_deinit(ctx, status_items, status_r);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenint mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* we don't care about mailbox's current state, so we might as well
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen fix inconsistency state */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return mailbox_sync_deinit(&ctx, status_items, status_r);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenvoid mailbox_notify_changes(struct mailbox *box, unsigned int min_interval,
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen mailbox_notify_callback_t *callback, void *context)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenvoid mailbox_notify_changes_stop(struct mailbox *box)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint mailbox_keywords_create(struct mailbox *box, const char *const keywords[],
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return box->v.keywords_create(box, keywords, keywords_r, FALSE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenmailbox_keywords_create_valid(struct mailbox *box,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen const char *const keywords[])
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (box->v.keywords_create(box, keywords, &kw, TRUE) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mailbox_keywords_free(struct mailbox *box,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid mailbox_get_uids(struct mailbox *box, uint32_t uid1, uint32_t uid2,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen box->v.get_uids(box, uid1, uid2, seq1_r, seq2_r);
struct mail_search_context *
bool tryagain;
int ret;
&tryagain)) == 0) {
if (!tryagain)
return ret;
struct mailbox_transaction_context *
return trans;
struct mailbox *
return t->box;
if (ret == 0) {