dbox-storage.c revision 32ee977e189266744ef69ac4e832fd3111d6f949
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "lib.h"
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "array.h"
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "ioloop.h"
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "str.h"
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "mkdir-parents.h"
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "unlink-directory.h"
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen#include "index-mail.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include "mail-copy.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include "dbox-sync.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include "dbox-index.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include "dbox-file.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include "dbox-storage.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <stdio.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <stdlib.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <unistd.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <dirent.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/stat.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#define DBOX_LIST_CONTEXT(obj) \
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen MODULE_CONTEXT(obj, dbox_mailbox_list_module)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenextern struct mail_storage dbox_storage;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenextern struct mailbox dbox_mailbox;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(dbox_mailbox_list_module,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen &mailbox_list_module_register);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainenstatic int
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainendbox_list_delete_mailbox(struct mailbox_list *list, const char *name);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainenstatic int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen const char *dir, const char *fname,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen enum mailbox_list_file_type type,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen enum mailbox_info_flags *flags);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainenstatic int
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainendbox_get_list_settings(struct mailbox_list_settings *list_set,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen const char *data, enum mail_storage_flags flags,
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen const char **layout_r, const char **alt_dir_r,
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen const char **error_r)
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen{
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen *layout_r = "fs";
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen
0f97c2b6ec76e7f600e983cb952cf265a6189114Timo Sirainen memset(list_set, 0, sizeof(*list_set));
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen list_set->subscription_fname = DBOX_SUBSCRIPTION_FILE_NAME;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen list_set->maildir_name = "";
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (data == NULL || *data == '\0' || *data == ':') {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen /* we won't do any guessing for this format. */
34b724d1d7e50b1ab24267a3b6fc089b1147c1abAki Tuomi if (debug)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen i_info("dbox: mailbox location not given");
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen *error_r = "Root mail directory not given";
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return -1;
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen }
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
1da5113b93f5dd0543a155040daa7ae3f3718b8bTimo Sirainen if (debug)
1da5113b93f5dd0543a155040daa7ae3f3718b8bTimo Sirainen i_info("dbox: data=%s", data);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return mailbox_list_settings_parse(data, list_set, layout_r, alt_dir_r,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen error_r);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen}
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainenstatic struct mail_storage *dbox_alloc(void)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen{
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen struct dbox_storage *storage;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen pool_t pool;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen pool = pool_alloconly_create("dbox storage", 512+256);
0f97c2b6ec76e7f600e983cb952cf265a6189114Timo Sirainen storage = p_new(pool, struct dbox_storage, 1);
0f97c2b6ec76e7f600e983cb952cf265a6189114Timo Sirainen storage->storage = dbox_storage;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen storage->storage.pool = pool;
2848ed04730e9f2ed91829d41312ebc3132b5613Timo Sirainen
2848ed04730e9f2ed91829d41312ebc3132b5613Timo Sirainen return &storage->storage;
2848ed04730e9f2ed91829d41312ebc3132b5613Timo Sirainen}
2848ed04730e9f2ed91829d41312ebc3132b5613Timo Sirainen
cf05592015b99607095f970bf914f5d069bf0666Timo Sirainenstatic int dbox_create(struct mail_storage *_storage, const char *data,
cf05592015b99607095f970bf914f5d069bf0666Timo Sirainen const char **error_r)
cf05592015b99607095f970bf914f5d069bf0666Timo Sirainen{
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen struct mailbox_list_settings list_set;
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen struct stat st;
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen const char *layout, *alt_dir;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (dbox_get_list_settings(&list_set, data, _storage->flags,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen &layout, &alt_dir, error_r) < 0)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return -1;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen list_set.mail_storage_flags = &_storage->flags;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen list_set.lock_method = &_storage->lock_method;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if ((_storage->flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (stat(list_set.root_dir, &st) < 0) {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (errno != ENOENT) {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen *error_r = t_strdup_printf(
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen "stat(%s) failed: %m",
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen list_set.root_dir);
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen } else {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen *error_r = t_strdup_printf(
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen "Root mail directory doesn't exist: %s",
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen list_set.root_dir);
85c9cf2c39903ecb102d701e8b19a7cf364dce83Timo Sirainen }
85c9cf2c39903ecb102d701e8b19a7cf364dce83Timo Sirainen return -1;
85c9cf2c39903ecb102d701e8b19a7cf364dce83Timo Sirainen }
85c9cf2c39903ecb102d701e8b19a7cf364dce83Timo Sirainen } else {
85c9cf2c39903ecb102d701e8b19a7cf364dce83Timo Sirainen if (mkdir_parents(list_set.root_dir, CREATE_MODE) < 0 &&
85c9cf2c39903ecb102d701e8b19a7cf364dce83Timo Sirainen errno != EEXIST) {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen *error_r = t_strdup_printf("mkdir(%s) failed: %m",
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen list_set.root_dir);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return -1;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen }
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen }
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return -1;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen storage->list_module_ctx.super = _storage->list->v;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen storage->alt_dir = p_strdup(_storage->pool, alt_dir);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen _storage->list->v.iter_is_mailbox = dbox_list_iter_is_mailbox;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen _storage->list->v.delete_mailbox = dbox_list_delete_mailbox;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen MODULE_CONTEXT_SET_FULL(_storage->list, dbox_mailbox_list_module,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen storage, &storage->list_module_ctx);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen /* finish list init after we've overridden vfuncs */
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mailbox_list_init(_storage->list, _storage->ns, &list_set,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mail_storage_get_list_flags(_storage->flags));
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return 0;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen}
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainenstatic int create_dbox(struct mail_storage *storage, const char *path)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen{
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mail_storage_set_critical(storage,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen "mkdir(%s) failed: %m", path);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen }
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return -1;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen }
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return 0;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen}
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainenstatic const char *
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainendbox_get_alt_path(struct dbox_storage *storage, const char *path)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen{
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen unsigned int len;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (storage->alt_dir == NULL)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return NULL;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen len = strlen(storage->alt_dir);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (strncmp(path, storage->alt_dir, len) != 0)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return t_strconcat(storage->alt_dir, path + len, NULL);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen else
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen return NULL;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen}
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainenstatic struct mailbox *
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainendbox_open(struct dbox_storage *storage, const char *name,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen enum mailbox_open_flags flags)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen{
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen struct mail_storage *_storage = &storage->storage;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen struct dbox_mailbox *mbox;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen struct mail_index *index;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen const char *path, *value;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen pool_t pool;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen path = mailbox_list_get_path(_storage->list, name,
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen index = index_storage_alloc(_storage, name, flags, DBOX_INDEX_PREFIX);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mail_index_set_fsync_types(index, MAIL_INDEX_SYNC_TYPE_APPEND |
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen MAIL_INDEX_SYNC_TYPE_EXPUNGE);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen pool = pool_alloconly_create("dbox mailbox", 1024+512);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox = p_new(pool, struct dbox_mailbox, 1);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->ibox.box = dbox_mailbox;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->ibox.box.pool = pool;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->ibox.storage = &storage->storage;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->ibox.mail_vfuncs = &dbox_mail_vfuncs;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->ibox.index = index;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->path = p_strdup(pool, path);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->alt_path = p_strdup(pool, dbox_get_alt_path(storage, path));
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->storage = storage;
34b724d1d7e50b1ab24267a3b6fc089b1147c1abAki Tuomi mbox->last_interactive_change = ioloop_time;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen value = getenv("DBOX_ROTATE_SIZE");
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (value != NULL)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->rotate_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen else
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->rotate_size = DBOX_DEFAULT_ROTATE_SIZE;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->rotate_size = 0; /* FIXME: currently anything else doesn't work */
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen value = getenv("DBOX_ROTATE_MIN_SIZE");
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen if (value != NULL)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->rotate_min_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen else
1da5113b93f5dd0543a155040daa7ae3f3718b8bTimo Sirainen mbox->rotate_min_size = DBOX_DEFAULT_ROTATE_MIN_SIZE;
1da5113b93f5dd0543a155040daa7ae3f3718b8bTimo Sirainen if (mbox->rotate_min_size > mbox->rotate_size)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->rotate_min_size = mbox->rotate_size;
0f97c2b6ec76e7f600e983cb952cf265a6189114Timo Sirainen value = getenv("DBOX_ROTATE_DAYS");
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen if (value != NULL)
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen mbox->rotate_days = (unsigned int)strtoul(value, NULL, 10);
66e1cf5014bec1cf1a8339be6fccc9be5ad3c793Timo Sirainen else
mbox->rotate_days = DBOX_DEFAULT_ROTATE_DAYS;
value = getenv("DBOX_MAX_OPEN_FILES");
if (value != NULL)
mbox->max_open_files = (unsigned int)strtoul(value, NULL, 10);
else
mbox->max_open_files = DBOX_DEFAULT_MAX_OPEN_FILES;
i_array_init(&mbox->open_files, I_MIN(mbox->max_open_files, 128));
mbox->dbox_ext_id =
mail_index_ext_register(index, "dbox", 0,
sizeof(struct dbox_mail_index_record),
sizeof(uint32_t));
mbox->dbox_hdr_ext_id =
mail_index_ext_register(index, "dbox-hdr",
sizeof(struct dbox_index_header), 0, 0);
mbox->dbox_index = dbox_index_init(mbox);
index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE);
return &mbox->ibox.box;
}
static struct mailbox *
dbox_mailbox_open(struct mail_storage *_storage, const char *name,
struct istream *input, enum mailbox_open_flags flags)
{
struct dbox_storage *storage = (struct dbox_storage *)_storage;
const char *path;
struct stat st;
if (input != NULL) {
mail_storage_set_critical(_storage,
"dbox doesn't support streamed mailboxes");
return NULL;
}
path = mailbox_list_get_path(_storage->list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(path, &st) == 0)
return dbox_open(storage, name, flags);
else if (errno == ENOENT) {
if (strcmp(name, "INBOX") == 0) {
/* INBOX always exists, create it */
if (create_dbox(_storage, path) < 0)
return NULL;
return dbox_open(storage, name, flags);
}
mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
return NULL;
} else {
mail_storage_set_critical(_storage, "stat(%s) failed: %m",
path);
return NULL;
}
}
static int dbox_storage_mailbox_close(struct mailbox *box)
{
struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
int ret;
ret = dbox_sync(mbox, TRUE);
dbox_index_deinit(&mbox->dbox_index);
dbox_files_free(mbox);
array_free(&mbox->open_files);
return index_storage_mailbox_close(box) < 0 ? -1 : ret;
}
static int dbox_mailbox_create(struct mail_storage *_storage,
const char *name, bool directory ATTR_UNUSED)
{
const char *path;
struct stat st;
path = mailbox_list_get_path(_storage->list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(path, &st) == 0) {
mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox already exists");
return -1;
}
return create_dbox(_storage, path);
}
static int
dbox_delete_nonrecursive(struct mailbox_list *list, const char *path,
const char *name)
{
DIR *dir;
struct dirent *d;
string_t *full_path;
unsigned int dir_len;
bool unlinked_something = FALSE;
dir = opendir(path);
if (dir == NULL) {
if (!mailbox_list_set_error_from_errno(list)) {
mailbox_list_set_critical(list,
"opendir(%s) failed: %m", path);
}
return -1;
}
full_path = t_str_new(256);
str_append(full_path, path);
str_append_c(full_path, '/');
dir_len = str_len(full_path);
errno = 0;
while ((d = readdir(dir)) != NULL) {
if (d->d_name[0] == '.') {
/* skip . and .. */
if (d->d_name[1] == '\0')
continue;
if (d->d_name[1] == '.' && d->d_name[2] == '\0')
continue;
}
str_truncate(full_path, dir_len);
str_append(full_path, d->d_name);
/* trying to unlink() a directory gives either EPERM or EISDIR
(non-POSIX). it doesn't really work anywhere in practise,
so don't bother stat()ing the file first */
if (unlink(str_c(full_path)) == 0)
unlinked_something = TRUE;
else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
mailbox_list_set_critical(list,
"unlink_directory(%s) failed: %m",
str_c(full_path));
}
}
if (closedir(dir) < 0) {
mailbox_list_set_critical(list, "closedir(%s) failed: %m",
path);
}
if (rmdir(path) == 0)
unlinked_something = TRUE;
else if (errno != ENOENT && errno != ENOTEMPTY) {
mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
return -1;
}
if (!unlinked_something) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
t_strdup_printf("Directory %s isn't empty, "
"can't delete it.", name));
return -1;
}
return 0;
}
static int
dbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
struct dbox_storage *storage = DBOX_LIST_CONTEXT(list);
struct stat st;
const char *path, *alt_path;
/* Make sure the indexes are closed before trying to delete the
directory that contains them. It can still fail with some NFS
implementations if indexes are opened by another session, but
that can't really be helped. */
index_storage_destroy_unrefed();
/* delete the index and control directories */
if (storage->list_module_ctx.super.delete_mailbox(list, name) < 0)
return -1;
/* check if the mailbox actually exists */
path = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (stat(path, &st) != 0 && errno == ENOENT) {
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
return -1;
}
if (dbox_delete_nonrecursive(list, path, name) < 0)
return -1;
alt_path = dbox_get_alt_path(storage, path);
if (alt_path != NULL) {
if (dbox_delete_nonrecursive(list, alt_path, name) < 0)
return -1;
}
return 0;
}
static void dbox_notify_changes(struct mailbox *box)
{
struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
if (box->notify_callback == NULL)
index_mailbox_check_remove_all(&mbox->ibox);
else
index_mailbox_check_add(&mbox->ibox, mbox->path);
}
static int dbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
ATTR_UNUSED,
const char *dir, const char *fname,
enum mailbox_list_file_type type,
enum mailbox_info_flags *flags)
{
const char *mail_path;
struct stat st;
int ret = 1;
/* try to avoid stat() with these checks */
if (type != MAILBOX_LIST_FILE_TYPE_DIR &&
type != MAILBOX_LIST_FILE_TYPE_SYMLINK &&
type != MAILBOX_LIST_FILE_TYPE_UNKNOWN) {
/* it's a file */
*flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
return 0;
}
/* need to stat() then */
t_push();
mail_path = t_strconcat(dir, "/", fname, NULL);
if (stat(mail_path, &st) == 0) {
if (!S_ISDIR(st.st_mode)) {
/* non-directory */
*flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
ret = 0;
}
} else {
/* non-selectable. probably either access denied, or symlink
destination not found. don't bother logging errors. */
*flags |= MAILBOX_NOSELECT;
}
t_pop();
return ret;
}
static void dbox_class_init(void)
{
dbox_transaction_class_init();
}
static void dbox_class_deinit(void)
{
dbox_transaction_class_deinit();
}
struct mail_storage dbox_storage = {
MEMBER(name) DBOX_STORAGE_NAME,
MEMBER(mailbox_is_file) FALSE,
{
dbox_class_init,
dbox_class_deinit,
dbox_alloc,
dbox_create,
NULL,
NULL,
dbox_mailbox_open,
dbox_mailbox_create
}
};
struct mailbox dbox_mailbox = {
MEMBER(name) NULL,
MEMBER(storage) NULL,
{
index_storage_is_readonly,
index_storage_allow_new_keywords,
dbox_storage_mailbox_close,
index_storage_get_status,
NULL,
NULL,
dbox_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
NULL,
dbox_notify_changes,
index_transaction_begin,
index_transaction_commit,
index_transaction_rollback,
index_keywords_create,
index_keywords_free,
index_storage_get_uids,
dbox_mail_alloc,
index_header_lookup_init,
index_header_lookup_deinit,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next_nonblock,
index_storage_search_next_update_seq,
dbox_save_init,
dbox_save_continue,
dbox_save_finish,
dbox_save_cancel,
mail_storage_copy,
index_storage_is_inconsistent
}
};