maildir-storage.c revision 20a802016205bbcafc90f164f769ea801f88d014
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2002-2003 Timo Sirainen */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "lib.h"
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen#include "hostpid.h"
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen#include "home-expand.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "mkdir-parents.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "unlink-directory.h"
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen#include "subscription-file/subscription-file.h"
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include "maildir-storage.h"
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include "maildir-uidlist.h"
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include <stdio.h>
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen#include <stdlib.h>
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include <unistd.h>
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#include <sys/stat.h>
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstruct rename_context {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen int found;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen size_t oldnamelen;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const char *newname;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen};
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenextern struct mail_storage maildir_storage;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenextern struct mailbox maildir_mailbox;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic const char *maildirs[] = { "cur", "new", "tmp", NULL };
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenstatic int verify_inbox(struct index_storage *storage);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstatic struct mail_storage *
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenmaildir_create(const char *data, const char *user)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct index_storage *storage;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const char *root_dir, *inbox_dir, *index_dir, *control_dir;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen const char *home, *path, *p;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen size_t len;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen inbox_dir = root_dir = index_dir = control_dir = NULL;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (data == NULL || *data == '\0') {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* we'll need to figure out the maildir location ourself.
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen it's either root dir if we've already chroot()ed, or
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen $HOME/Maildir otherwise */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (access("/cur", R_OK|W_OK|X_OK) == 0)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen root_dir = "/";
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen home = getenv("HOME");
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (home != NULL) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen path = t_strconcat(home, "/Maildir", NULL);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen root_dir = path;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen } else {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen p = strchr(data, ':');
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (p == NULL)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen root_dir = data;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen root_dir = t_strdup_until(data, p);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen do {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen p++;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (strncmp(p, "INBOX=", 6) == 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen inbox_dir = t_strcut(p+6, ':');
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen else if (strncmp(p, "INDEX=", 6) == 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen index_dir = t_strcut(p+6, ':');
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen else if (strncmp(p, "CONTROL=", 8) == 0)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen control_dir = t_strcut(p+8, ':');
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen p = strchr(p, ':');
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } while (p != NULL);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (root_dir == NULL)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return NULL;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* strip trailing '/' */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen len = strlen(root_dir);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (root_dir[len-1] == '/')
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen root_dir = t_strndup(root_dir, len-1);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (index_dir == NULL)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen index_dir = root_dir;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen else if (strcmp(index_dir, "MEMORY") == 0)
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen index_dir = NULL;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen storage = i_new(struct index_storage, 1);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen storage->storage = maildir_storage;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen /* the default ".temp.xxx" prefix would be treated as directory */
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen storage->temp_prefix =
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen i_strconcat("temp.", my_hostname, ".", my_pid, ".", NULL);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen storage->dir = i_strdup(home_expand(root_dir));
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen storage->inbox_path = i_strdup(home_expand(inbox_dir));
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen storage->index_dir = i_strdup(home_expand(index_dir));
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen storage->control_dir = i_strdup(home_expand(control_dir));
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen storage->user = i_strdup(user);
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen storage->callbacks = i_new(struct mail_storage_callbacks, 1);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen index_storage_init(storage);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen (void)verify_inbox(storage);
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen return &storage->storage;
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen}
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainenstatic void maildir_free(struct mail_storage *_storage)
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen{
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen struct index_storage *storage = (struct index_storage *) _storage;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen index_storage_deinit(storage);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen i_free(storage->temp_prefix);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen i_free(storage->dir);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen i_free(storage->inbox_path);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen i_free(storage->index_dir);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen i_free(storage->control_dir);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen i_free(storage->user);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen i_free(storage->callbacks);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen i_free(storage);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainenstatic int maildir_autodetect(const char *data)
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen{
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen struct stat st;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen data = t_strcut(data, ':');
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen return stat(t_strconcat(data, "/cur", NULL), &st) == 0 &&
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen S_ISDIR(st.st_mode);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen}
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainenstatic int maildir_is_valid_create_name(const char *name)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen{
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen size_t len;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen len = strlen(name);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (len == 0 || name[0] == MAILDIR_FS_SEP ||
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen name[len-1] == MAILDIR_FS_SEP ||
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen strchr(name, '*') != NULL || strchr(name, '%') != NULL)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen return FALSE;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (full_filesystem_access)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen return TRUE;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (*name == '~' || strchr(name, '/') != NULL)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen return FALSE;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen return TRUE;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen}
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainenstatic int maildir_is_valid_existing_name(const char *name)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen{
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (name[0] == '\0' || name[strlen(name)-1] == '/')
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen return FALSE;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (full_filesystem_access)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen return TRUE;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (*name == '~' || strchr(name, '/') != NULL)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return FALSE;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return TRUE;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstatic const char *maildir_get_absolute_path(const char *name, int unlink)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen{
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen const char *p;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen name = home_expand(name);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen p = strrchr(name, '/');
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen if (p == NULL)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return name;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return t_strconcat(t_strdup_until(name, p+1),
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen unlink ? MAILDIR_FS_SEP_S MAILDIR_FS_SEP_S :
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen MAILDIR_FS_SEP_S, p+1, NULL);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainenconst char *maildir_get_path(struct index_storage *storage, const char *name)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen{
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (full_filesystem_access && (*name == '/' || *name == '~'))
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return maildir_get_absolute_path(name, FALSE);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (strcmp(name, "INBOX") == 0) {
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return storage->inbox_path != NULL ?
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen storage->inbox_path : storage->dir;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return t_strconcat(storage->dir, "/"MAILDIR_FS_SEP_S, name, NULL);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic const char *
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenmaildir_get_unlink_path(struct index_storage *storage, const char *name)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (full_filesystem_access && (*name == '/' || *name == '~'))
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return maildir_get_absolute_path(name, TRUE);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return maildir_get_path(storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen t_strconcat(MAILDIR_FS_SEP_S, name, NULL));
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic const char *maildir_get_index_path(struct index_storage *storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const char *name)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (storage->index_dir == NULL)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return NULL;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (strcmp(name, "INBOX") == 0 && storage->inbox_path != NULL)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return storage->inbox_path;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (full_filesystem_access && (*name == '/' || *name == '~'))
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return maildir_get_absolute_path(name, FALSE);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S, name, NULL);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic const char *maildir_get_control_path(struct index_storage *storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const char *name)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (storage->control_dir == NULL)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return maildir_get_path(storage, name);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (full_filesystem_access && (*name == '/' || *name == '~'))
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return maildir_get_absolute_path(name, FALSE);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return t_strconcat(storage->control_dir, "/"MAILDIR_FS_SEP_S,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen name, NULL);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic int mkdir_verify(struct index_storage *storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const char *dir, int verify)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct stat st;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (verify) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (lstat(dir, &st) == 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return 0;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (errno != ENOENT) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_storage_set_critical(&storage->storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen "lstat(%s) failed: %m", dir);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return -1;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && (errno != EEXIST || !verify)) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (errno != EEXIST && (!verify || errno != ENOENT)) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_storage_set_critical(&storage->storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen "mkdir(%s) failed: %m", dir);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen}
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen/* create or fix maildir, ignore if it already exists */
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainenstatic int create_maildir(struct index_storage *storage,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen const char *dir, int verify)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen{
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen const char **tmp, *path;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (!verify && mkdir_verify(storage, dir, verify) < 0)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen for (tmp = maildirs; *tmp != NULL; tmp++) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen path = t_strconcat(dir, "/", *tmp, NULL);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (mkdir_verify(storage, path, verify) < 0) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (!verify || errno != ENOENT)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* small optimization. if we're verifying, we don't
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen check that the root dir actually exists unless we
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen fail here. */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (mkdir_verify(storage, dir, verify) < 0)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (mkdir_verify(storage, path, verify) < 0)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen}
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainenstatic int create_index_dir(struct index_storage *storage, const char *name)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen{
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen const char *dir;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (storage->index_dir == NULL)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (strcmp(storage->index_dir, storage->dir) == 0 ||
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen (strcmp(name, "INBOX") == 0 && storage->inbox_path != NULL &&
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen strcmp(storage->index_dir, storage->inbox_path) == 0))
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen dir = t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S, name, NULL);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (mkdir_parents(dir, CREATE_MODE) == -1 && errno != EEXIST) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen mail_storage_set_critical(&storage->storage,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen "mkdir(%s) failed: %m", dir);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return 0;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen}
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic int create_control_dir(struct index_storage *storage, const char *name)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen const char *dir;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (storage->control_dir == NULL)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return 0;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen dir = t_strconcat(storage->control_dir, "/"MAILDIR_FS_SEP_S,
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen name, NULL);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_storage_set_critical(&storage->storage,
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen "mkdir(%s) failed: %m", dir);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return -1;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return 0;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic int verify_inbox(struct index_storage *storage)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const char *inbox;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (storage->inbox_path == NULL) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* first make sure the cur/ new/ and tmp/ dirs exist
632018810af689442569cbb0139c55868923ccfeTimo Sirainen in root dir */
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (create_maildir(storage, storage->dir, TRUE) < 0)
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen return -1;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* create the .INBOX directory */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen inbox = t_strconcat(storage->index_dir,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen "/"MAILDIR_FS_SEP_S"INBOX", NULL);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (mkdir_verify(storage, inbox, TRUE) < 0)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return -1;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen } else {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (create_maildir(storage, storage->inbox_path, TRUE) < 0)
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen return -1;
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* make sure the index directories exist */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (create_index_dir(storage, "INBOX") < 0)
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen return -1;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (create_control_dir(storage, "INBOX") < 0)
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen return -1;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return 0;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen}
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainenstatic int maildir_is_recent(struct index_mailbox *ibox, uint32_t uid)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen{
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return maildir_uidlist_is_recent(ibox->uidlist, uid);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen}
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainenstatic struct mailbox *
632018810af689442569cbb0139c55868923ccfeTimo Sirainenmaildir_open(struct index_storage *storage, const char *name,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen enum mailbox_open_flags flags)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen{
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct index_mailbox *ibox;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct mail_index *index;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen const char *path, *index_dir, *control_dir;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct stat st;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen path = maildir_get_path(storage, name);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen index_dir = maildir_get_index_path(storage, name);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen control_dir = maildir_get_control_path(storage, name);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen index = index_storage_alloc(index_dir, path, MAILDIR_INDEX_PREFIX);
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen ibox = index_storage_mailbox_init(storage, &maildir_mailbox,
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen index, name, flags);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (ibox == NULL)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->path = i_strdup(path);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->control_dir = i_strdup(control_dir);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->mail_interface = &maildir_mail;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->uidlist = maildir_uidlist_init(ibox);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->is_recent = maildir_is_recent;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* for shared mailboxes get the create mode from the
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen permissions of dovecot-shared file */
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (stat(t_strconcat(path, "/dovecot-shared", NULL), &st) < 0)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->mail_create_mode = 0600;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen else {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->mail_create_mode = st.st_mode & 0666;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ibox->private_flags_mask = MAIL_SEEN;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen mail_index_set_permissions(ibox->index, st.st_mode & 0666,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen st.st_gid);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen }
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return &ibox->box;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic struct mailbox *
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenmaildir_mailbox_open(struct mail_storage *_storage,
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const char *name, enum mailbox_open_flags flags)
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen{
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen const char *path;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen struct stat st;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen mail_storage_clear_error(_storage);
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen if (strcmp(name, "INBOX") == 0) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (verify_inbox(storage) < 0)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return maildir_open(storage, "INBOX", flags);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (!maildir_is_valid_existing_name(name)) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen path = maildir_get_path(storage, name);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (stat(path, &st) == 0) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* exists - make sure the required directories are also there */
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (create_maildir(storage, path, TRUE) < 0 ||
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen create_index_dir(storage, name) < 0 ||
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen create_control_dir(storage, name) < 0)
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen return NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return maildir_open(storage, name, flags);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen } else if (errno == ENOENT) {
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen name);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen } else {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen path);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainenstatic int maildir_mailbox_create(struct mail_storage *_storage,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen const char *name,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen int directory __attr_unused__)
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen{
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen const char *path;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen mail_storage_clear_error(_storage);
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen if (!maildir_is_valid_create_name(name)) {
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen return -1;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen }
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen path = maildir_get_path(storage, name);
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (create_maildir(storage, path, FALSE) < 0) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (errno == EEXIST) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen mail_storage_set_error(_storage,
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen "Mailbox already exists");
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen return -1;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen return 0;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen}
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainenstatic int maildir_mailbox_delete(struct mail_storage *_storage,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen const char *name)
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen{
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen struct stat st;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen const char *src, *dest, *index_dir;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen int count;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen mail_storage_clear_error(_storage);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (strcmp(name, "INBOX") == 0) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen mail_storage_set_error(_storage, "INBOX can't be deleted.");
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return -1;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (!maildir_is_valid_existing_name(name)) {
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return -1;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* rename the .maildir into ..maildir which marks it as being
632018810af689442569cbb0139c55868923ccfeTimo Sirainen deleted. delete indexes before the actual maildir. this way we
632018810af689442569cbb0139c55868923ccfeTimo Sirainen never see partially deleted mailboxes. */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen src = maildir_get_path(storage, name);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen dest = maildir_get_unlink_path(storage, name);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (stat(src, &st) != 0 && errno == ENOENT) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
632018810af689442569cbb0139c55868923ccfeTimo Sirainen name);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return -1;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (storage->index_dir != NULL && *name != '/' && *name != '~' &&
632018810af689442569cbb0139c55868923ccfeTimo Sirainen strcmp(storage->index_dir, storage->dir) != 0) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen index_dir = t_strconcat(storage->index_dir,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen "/"MAILDIR_FS_SEP_S, name, NULL);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen index_storage_destroy_unrefed();
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen /* it can fail with some NFS implementations if indexes are
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen opened by another session.. can't really help it. */
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (unlink_directory(index_dir, TRUE) < 0 &&
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen errno != ENOTEMPTY) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen mail_storage_set_critical(_storage,
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen "unlink_directory(%s) failed: %m", index_dir);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return -1;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen }
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen }
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen count = 0;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen while (rename(src, dest) < 0 && count < 2) {
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen if (errno != EEXIST && errno != ENOTEMPTY) {
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen mail_storage_set_critical(_storage,
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen "rename(%s, %s) failed: %m", src, dest);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return -1;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* ..dir already existed? delete it and try again */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (unlink_directory(dest, TRUE) < 0) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen mail_storage_set_critical(_storage,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen "unlink_directory(%s) failed: %m", dest);
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen return -1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen count++;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (unlink_directory(dest, TRUE) < 0 && errno != ENOTEMPTY) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch mail_storage_set_critical(_storage,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen "unlink_directory(%s) failed: %m", dest);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* it's already renamed to ..dir, which means it's deleted
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen as far as client is concerned. Report success. */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return 0;
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen}
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainenstatic int rename_indexes(struct index_storage *storage,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen const char *oldname, const char *newname)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen const char *oldpath, *newpath;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (storage->index_dir == NULL ||
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen strcmp(storage->index_dir, storage->dir) == 0)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* Rename it's index. */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen oldpath = t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen oldname, NULL);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen newpath = t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen newname, NULL);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen mail_storage_set_critical(&storage->storage,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen "rename(%s, %s) failed: %m",
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen oldpath, newpath);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return -1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenstatic int rename_subfolders(struct index_storage *storage,
c89ceadf661bde22e1cd9dc2eac09c19202e65ecTimo Sirainen const char *oldname, const char *newname)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct mailbox_list_context *ctx;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct mailbox_list *list;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen const char *oldpath, *newpath, *new_listname;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen size_t oldnamelen;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen int ret;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen ret = 0;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen oldnamelen = strlen(oldname);
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen ctx = maildir_mailbox_list_init(&storage->storage, oldname, "*",
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen MAILBOX_LIST_FAST_FLAGS);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen while ((list = maildir_mailbox_list_next(ctx)) != NULL) {
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen t_push();
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen i_assert(oldnamelen <= strlen(list->name));
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen new_listname = t_strconcat(newname,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen list->name + oldnamelen, NULL);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen oldpath = maildir_get_path(storage, list->name);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen newpath = maildir_get_path(storage, new_listname);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* FIXME: it's possible to merge two folders if either one of
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen them doesn't have existing root folder. We could check this
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen but I'm not sure if it's worth it. It could be even
1e167fbb281ccf41178a0b70495193c768f9ff75Timo Sirainen considered as a feature.
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen Anyway, the bug with merging is that if both folders have
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen identically named subfolder they conflict. Just ignore those
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen and leave them under the old folder. */
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen if (rename(oldpath, newpath) == 0 ||
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen errno == EEXIST || errno == ENOTEMPTY)
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen ret = 1;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen else {
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen mail_storage_set_critical(&storage->storage,
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen "rename(%s, %s) failed: %m",
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen oldpath, newpath);
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen ret = -1;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen t_pop();
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen break;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen }
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen (void)rename_indexes(storage, list->name, new_listname);
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen t_pop();
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen }
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen if (maildir_mailbox_list_deinit(ctx) < 0)
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen return -1;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return ret;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainenstatic int maildir_mailbox_rename(struct mail_storage *_storage,
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen const char *oldname, const char *newname)
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen const char *oldpath, *newpath;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen int ret, found;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_storage_clear_error(_storage);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (!maildir_is_valid_existing_name(oldname) ||
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen !maildir_is_valid_create_name(newname)) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_storage_set_error(_storage, "Invalid mailbox name");
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return -1;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (strcmp(oldname, "INBOX") == 0) {
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen mail_storage_set_error(_storage,
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen "Renaming INBOX isn't supported.");
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen return -1;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen }
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen /* NOTE: it's possible to rename a nonexisting folder which has
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen subfolders. In that case we should ignore the rename() error. */
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen oldpath = maildir_get_path(storage, oldname);
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen newpath = maildir_get_path(storage, newname);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = rename(oldpath, newpath);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (ret == 0 || errno == ENOENT) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen (void)rename_indexes(storage, oldname, newname);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen found = ret == 0;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ret = rename_subfolders(storage, oldname, newname);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (ret < 0)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return -1;
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen if (!found && ret == 0) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_storage_set_error(_storage,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen "Mailbox doesn't exist");
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return -1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return 0;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (errno == EEXIST) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen mail_storage_set_error(_storage,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen "Target mailbox already exists");
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen return -1;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen } else {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen mail_storage_set_critical(_storage, "rename(%s, %s) failed: %m",
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen oldpath, newpath);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen return -1;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen }
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen}
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainenstatic int maildir_set_subscribed(struct mail_storage *_storage,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen const char *name, int set)
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen{
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen const char *path;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen path = t_strconcat(storage->control_dir != NULL ?
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen storage->control_dir : storage->dir,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen "/" SUBSCRIPTION_FILE_NAME, NULL);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen return subsfile_set_subscribed(_storage, path, storage->temp_prefix,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen name, set);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen}
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainenstatic int maildir_get_mailbox_name_status(struct mail_storage *_storage,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen const char *name,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen enum mailbox_name_status *status)
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen{
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen struct index_storage *storage = (struct index_storage *)_storage;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen struct stat st;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen const char *path;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen mail_storage_clear_error(_storage);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen if (!maildir_is_valid_existing_name(name)) {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen *status = MAILBOX_NAME_INVALID;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen return 0;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen path = maildir_get_path(storage, name);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (strcmp(name, "INBOX") == 0 || stat(path, &st) == 0) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen *status = MAILBOX_NAME_EXISTS;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (!maildir_is_valid_create_name(name)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen *status = MAILBOX_NAME_INVALID;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (errno == ENOENT) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen *status = MAILBOX_NAME_VALID;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen } else {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen mail_storage_set_critical(_storage, "stat(%s) failed: %m",
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen path);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return -1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenstatic int maildir_storage_close(struct mailbox *box)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct index_mailbox *ibox = (struct index_mailbox *)box;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen int ret = 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /*FIXME:if (!maildir_try_flush_dirty_flags(ibox->index, TRUE)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen mail_storage_set_index_error(ibox);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ret = -1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }*/
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_uidlist_deinit(ibox->uidlist);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen index_storage_mailbox_free(box);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return ret;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenstatic void
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenmaildir_notify_changes(struct mailbox *box, unsigned int min_interval,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen mailbox_notify_callback_t *callback, void *context)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct index_mailbox *ibox = (struct index_mailbox *)box;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ibox->min_notify_interval = min_interval;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ibox->notify_callback = callback;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ibox->notify_context = context;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (callback == NULL) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen index_mailbox_check_remove_all(ibox);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen index_mailbox_check_add(ibox,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen t_strconcat(ibox->storage->dir, "/new", NULL), TRUE);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen index_mailbox_check_add(ibox,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen t_strconcat(ibox->storage->dir, "/cur", NULL), TRUE);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenstruct mail_storage maildir_storage = {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen "maildir", /* name */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen '.', /* hierarchy separator */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_create,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_free,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_autodetect,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen index_storage_set_callbacks,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_mailbox_open,
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen maildir_mailbox_create,
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen maildir_mailbox_delete,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_mailbox_rename,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_mailbox_list_init,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen maildir_mailbox_list_next,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_mailbox_list_deinit,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_set_subscribed,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_get_mailbox_name_status,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen index_storage_get_last_error,
c89ceadf661bde22e1cd9dc2eac09c19202e65ecTimo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen NULL,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen 0
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen};
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenstruct mailbox maildir_mailbox = {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen NULL, /* name */
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen NULL, /* storage */
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen index_storage_is_readonly,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen index_storage_allow_new_keywords,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen maildir_storage_close,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen index_storage_get_status,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen maildir_storage_sync_init,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen index_mailbox_sync_next,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen index_mailbox_sync_deinit,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen maildir_notify_changes,
maildir_transaction_begin,
maildir_transaction_commit,
maildir_transaction_rollback,
index_storage_fetch,
index_storage_get_uids,
index_header_lookup_init,
index_header_lookup_deinit,
index_storage_search_get_sorting,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next,
maildir_save_init,
maildir_save_continue,
maildir_save_finish,
maildir_save_cancel,
maildir_copy,
index_storage_is_inconsistent
};