cydir-storage.c revision 1108376e39a19912e8394e64e19b1bc6f6691cf6
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2007 Timo Sirainen */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "lib.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "array.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ioloop.h"
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen#include "str.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "mkdir-parents.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "unlink-directory.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "index-mail.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "mail-copy.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "cydir-sync.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "cydir-storage.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include <stdio.h>
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include <stdlib.h>
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include <unistd.h>
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include <dirent.h>
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include <sys/stat.h>
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
373492be949e159fda651807b3acda2c5c077027Timo Sirainen
72f5f2c5c6905b5d3f389b424313e2c450dfad96Timo Sirainen#define CYDIR_LIST_CONTEXT(obj) \
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen MODULE_CONTEXT(obj, cydir_mailbox_list_module)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenextern struct mail_storage cydir_storage;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenextern struct mailbox cydir_mailbox;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
373492be949e159fda651807b3acda2c5c077027Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(cydir_mailbox_list_module,
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen &mailbox_list_module_register);
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic int
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainencydir_list_delete_mailbox(struct mailbox_list *list, const char *name);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const char *dir, const char *fname,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen enum mailbox_list_file_type type,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen enum mailbox_info_flags *flags);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic int
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainencydir_get_list_settings(struct mailbox_list_settings *list_set,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *data, enum mail_storage_flags flags)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *p;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen size_t len;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen memset(list_set, 0, sizeof(*list_set));
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen list_set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen list_set->maildir_name = "";
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (data == NULL || *data == '\0') {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* we won't do any guessing for this format. */
51fb710488efa419a2964335c30451c62b9633b1Timo Sirainen if (debug)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_info("cydir: mailbox location not given");
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen return -1;
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* <root dir> [:INDEX=<dir>] */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (debug)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_info("cydir: data=%s", data);
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen p = strchr(data, ':');
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen if (p == NULL)
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen list_set->root_dir = data;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen else {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen list_set->root_dir = t_strdup_until(data, p);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen do {
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen p++;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (strncmp(p, "INDEX=", 6) == 0)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen list_set->index_dir = t_strcut(p+6, ':');
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen p = strchr(p, ':');
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen } while (p != NULL);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* strip trailing '/' */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen len = strlen(list_set->root_dir);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (list_set->root_dir[len-1] == '/')
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen list_set->root_dir = t_strndup(list_set->root_dir, len-1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (list_set->index_dir != NULL &&
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen strcmp(list_set->index_dir, "MEMORY") == 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen list_set->index_dir = "";
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return 0;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic struct mail_storage *cydir_alloc(void)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct cydir_storage *storage;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen pool_t pool;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen pool = pool_alloconly_create("cydir storage", 512+256);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen storage = p_new(pool, struct cydir_storage, 1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen storage->storage = cydir_storage;
ba8498efbf886ca8b69fdb20c0ba2f5dba9416e3Timo Sirainen storage->storage.pool = pool;
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen return &storage->storage;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic int cydir_create(struct mail_storage *_storage, const char *data)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct cydir_storage *storage = (struct cydir_storage *)_storage;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct mailbox_list_settings list_set;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const char *error;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct stat st;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (cydir_get_list_settings(&list_set, data, _storage->flags) < 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen list_set.mail_storage_flags = &_storage->flags;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen list_set.lock_method = &_storage->lock_method;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if ((_storage->flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (stat(list_set.root_dir, &st) < 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (errno != ENOENT) {
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen i_error("stat(%s) failed: %m",
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen list_set.root_dir);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (mkdir_parents(list_set.root_dir, CREATE_MODE) < 0 &&
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen errno != EEXIST) {
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen i_error("mkdir_parents(%s) failed: %m", list_set.root_dir);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen return -1;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen }
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (mailbox_list_init("fs", &list_set,
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen mail_storage_get_list_flags(_storage->flags),
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen &_storage->list, &error) < 0) {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen i_error("cydir fs: %s", error);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return -1;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen storage->list_module_ctx.super = _storage->list->v;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen _storage->list->v.iter_is_mailbox = cydir_list_iter_is_mailbox;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen _storage->list->v.delete_mailbox = cydir_list_delete_mailbox;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen MODULE_CONTEXT_SET_FULL(_storage->list, cydir_mailbox_list_module,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen storage, &storage->list_module_ctx);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return 0;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic int create_cydir(struct mail_storage *storage, const char *path)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *error;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen if (mail_storage_errno2str(&error)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mail_storage_set_error(storage, "%s", error);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen }
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen path);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen return 0;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen}
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainenstatic int create_index_dir(struct mail_storage *storage, const char *name)
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen{
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen const char *root_dir, *index_dir;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen root_dir = mailbox_list_get_path(storage->list, name,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen index_dir = mailbox_list_get_path(storage->list, name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (strcmp(index_dir, root_dir) == 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return 0;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (mkdir_parents(index_dir, CREATE_MODE) < 0 && errno != EEXIST) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen index_dir);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen return 0;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic bool cydir_is_recent(struct index_mailbox *ibox __attr_unused__,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen uint32_t uid __attr_unused__)
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen{
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen return FALSE;
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic struct mailbox *
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainencydir_open(struct cydir_storage *storage, const char *name,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen enum mailbox_open_flags flags)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct mail_storage *_storage = &storage->storage;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct cydir_mailbox *mbox;
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen struct mail_index *index;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen const char *path, *index_dir;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen pool_t pool;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen path = mailbox_list_get_path(_storage->list, name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen index_dir = mailbox_list_get_path(_storage->list, name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen MAILBOX_LIST_PATH_TYPE_INDEX);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (create_cydir(_storage, path) < 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return NULL;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (create_index_dir(_storage, name) < 0)
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen return NULL;
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen index = index_storage_alloc(index_dir, path, CYDIR_INDEX_PREFIX);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen pool = pool_alloconly_create("cydir mailbox", 1024+512);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox = p_new(pool, struct cydir_mailbox, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->ibox.box = cydir_mailbox;
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen mbox->ibox.box.pool = pool;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->ibox.storage = &storage->storage;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->ibox.mail_vfuncs = &cydir_mail_vfuncs;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->ibox.is_recent = cydir_is_recent;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->ibox.index = index;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->storage = storage;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->path = p_strdup(pool, path);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE);
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen return &mbox->ibox.box;
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen}
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic struct mailbox *
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainencydir_mailbox_open(struct mail_storage *_storage, const char *name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct istream *input, enum mailbox_open_flags flags)
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct cydir_storage *storage = (struct cydir_storage *)_storage;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *path;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct stat st;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_storage_clear_error(_storage);
f2df3069766c747cbf020fea5d3a4261949064b0Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (input != NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_storage_set_critical(_storage,
062ea54b7775d0c92ed67b9b1f4d93fa8ec80c84Timo Sirainen "cydir doesn't support streamed mailboxes");
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (strcmp(name, "INBOX") == 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return cydir_open(storage, "INBOX", flags);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (!mailbox_list_is_valid_existing_name(_storage->list, name)) {
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen return NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen if (stat(path, &st) == 0) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return cydir_open(storage, name, flags);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen } else if (errno == ENOENT) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_storage_set_error(_storage,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen } else {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen path);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen return NULL;
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen }
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic int cydir_mailbox_create(struct mail_storage *_storage,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen const char *name,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen bool directory __attr_unused__)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *path;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct stat st;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_storage_clear_error(_storage);
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (!mailbox_list_is_valid_create_name(_storage->list, name)) {
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen path = mailbox_list_get_path(_storage->list, name,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (stat(path, &st) == 0) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen mail_storage_set_error(_storage, "Mailbox already exists");
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return -1;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return create_cydir(_storage, path);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen}
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainenstatic int
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainencydir_delete_nonrecursive(struct mailbox_list *list, const char *path,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen const char *name)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen{
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen DIR *dir;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen struct dirent *d;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen string_t *full_path;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen unsigned int dir_len;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen bool unlinked_something = FALSE;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen dir = opendir(path);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (dir == NULL) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (errno == ENOENT) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen mailbox_list_set_error(list, t_strdup_printf(
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen } else {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen mailbox_list_set_critical(list,
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen "opendir(%s) failed: %m", path);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return -1;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen full_path = t_str_new(256);
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen str_append(full_path, path);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen str_append_c(full_path, '/');
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen dir_len = str_len(full_path);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen errno = 0;
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen while ((d = readdir(dir)) != NULL) {
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen if (d->d_name[0] == '.') {
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen /* skip . and .. */
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen if (d->d_name[1] == '\0')
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen continue;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (d->d_name[1] == '.' && d->d_name[2] == '\0')
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen continue;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen }
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen str_truncate(full_path, dir_len);
6bd263caf006edc75205f446fa0283c6f364941bTimo Sirainen str_append(full_path, d->d_name);
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen /* trying to unlink() a directory gives either EPERM or EISDIR
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen (non-POSIX). it doesn't really work anywhere in practise,
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen so don't bother stat()ing the file first */
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen if (unlink(str_c(full_path)) == 0)
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen unlinked_something = TRUE;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen mailbox_list_set_critical(list,
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen "unlink_directory(%s) failed: %m",
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen str_c(full_path));
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen if (closedir(dir) < 0) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mailbox_list_set_critical(list, "closedir(%s) failed: %m",
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen path);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (rmdir(path) == 0)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen unlinked_something = TRUE;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen else if (errno != ENOENT && errno != ENOTEMPTY) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return -1;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (!unlinked_something) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen mailbox_list_set_error(list, t_strdup_printf(
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen "Directory %s isn't empty, can't delete it.", name));
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return -1;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return 0;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic int
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainencydir_list_delete_mailbox(struct mailbox_list *list, const char *name)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct cydir_storage *storage = CYDIR_LIST_CONTEXT(list);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct stat st;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen const char *src;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* Make sure the indexes are closed before trying to delete the
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen directory that contains them. It can still fail with some NFS
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen implementations if indexes are opened by another session, but
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen that can't really be helped. */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen index_storage_destroy_unrefed();
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* delete the index and control directories */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (storage->list_module_ctx.super.delete_mailbox(list, name) < 0)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return -1;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
272aca0a772140d3a45a425a3fd67854ae2ccec2Timo Sirainen /* check if the mailbox actually exists */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (stat(src, &st) != 0 && errno == ENOENT) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen mailbox_list_set_error(list, t_strdup_printf(
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return -1;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen }
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen return cydir_delete_nonrecursive(list, src, name);
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen}
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainenstatic int cydir_storage_close(struct mailbox *box)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_storage_mailbox_free(box);
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenstatic void
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainencydir_notify_changes(struct mailbox *box, unsigned int min_interval,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen mailbox_notify_callback_t *callback, void *context)
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct cydir_mailbox *mbox = (struct cydir_mailbox *)box;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen mbox->ibox.min_notify_interval = min_interval;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen mbox->ibox.notify_callback = callback;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen mbox->ibox.notify_context = context;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen if (callback == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_mailbox_check_remove_all(&mbox->ibox);
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen return;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen index_mailbox_check_add(&mbox->ibox, mbox->path);
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen}
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic int cydir_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen const char *dir, const char *fname,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen enum mailbox_list_file_type type,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enum mailbox_info_flags *flags)
{
const char *mail_path;
struct stat st;
int ret = 1;
if (strchr(fname, '.') != NULL) {
*flags = MAILBOX_NOSELECT;
return 0;
}
/* 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 &&
(ctx->flags & MAILBOX_LIST_ITER_FAST_FLAGS) != 0) {
/* 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, but may contain subdirs */
*flags |= MAILBOX_NOSELECT;
}
t_pop();
return ret;
}
static void cydir_class_init(void)
{
cydir_transaction_class_init();
}
static void cydir_class_deinit(void)
{
cydir_transaction_class_deinit();
}
struct mail_storage cydir_storage = {
MEMBER(name) CYDIR_STORAGE_NAME,
MEMBER(mailbox_is_file) FALSE,
{
cydir_class_init,
cydir_class_deinit,
cydir_alloc,
cydir_create,
NULL,
NULL,
cydir_mailbox_open,
cydir_mailbox_create,
index_storage_get_last_error
}
};
struct mailbox cydir_mailbox = {
MEMBER(name) NULL,
MEMBER(storage) NULL,
{
index_storage_is_readonly,
index_storage_allow_new_keywords,
cydir_storage_close,
index_storage_get_status,
cydir_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
cydir_notify_changes,
index_transaction_begin,
index_transaction_commit,
index_transaction_rollback,
index_keywords_create,
index_keywords_free,
index_storage_get_uids,
index_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,
cydir_save_init,
cydir_save_continue,
cydir_save_finish,
cydir_save_cancel,
mail_storage_copy,
index_storage_is_inconsistent
}
};