maildir-storage.c revision 181aa01111e2de2dae413b4c1ccfcfc4e801ac40
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi/* Copyright (C) 2002-2003 Timo Sirainen */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#define CREATE_MODE 0770 /* umask() should limit it more */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *newname;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *maildirs[] = { "cur", "new", "tmp", NULL };
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct mail_storage *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *root_dir, *inbox_dir, *index_dir, *control_dir;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi inbox_dir = root_dir = index_dir = control_dir = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* we'll need to figure out the maildir location ourself.
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi it's either root dir if we've already chroot()ed, or
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi $HOME/Maildir otherwise */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } while (p != NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* strip trailing '/' */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi memcpy(storage, &maildir_storage, sizeof(struct mail_storage));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi storage->inbox_file = i_strdup(home_expand(inbox_dir));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi storage->index_dir = i_strdup(home_expand(index_dir));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi storage->control_dir = i_strdup(home_expand(control_dir));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi storage->callbacks = i_new(struct mail_storage_callbacks, 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void maildir_free(struct mail_storage *storage)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return stat(t_strconcat(data, "/cur", NULL), &st) == 0 &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int maildir_is_valid_create_name(const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strchr(name, '*') != NULL || strchr(name, '%') != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int maildir_is_valid_existing_name(const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *maildir_get_absolute_path(const char *name, int unlink)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *p;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiconst char *maildir_fix_mailbox_name(struct mail_storage *storage,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (name[5] == '\0' || name[5] == storage->hierarchy_sep)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* use same case with all INBOX folders or we'll get
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi into trouble */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* don't check namespace with INBOX */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (storage->namespace != NULL && remove_namespace) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncmp(storage->namespace, name, len) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_panic("maildir: expecting namespace '%s' in name "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (full_filesystem_access && (*name == '/' || *name == '~'))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiconst char *maildir_get_path(struct mail_storage *storage, const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (full_filesystem_access && (*name == '/' || *name == '~'))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return t_strconcat(storage->dir, "/"MAILDIR_FS_SEP_S, name, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimaildir_get_unlink_path(struct mail_storage *storage, const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (full_filesystem_access && (*name == '/' || *name == '~'))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *maildir_get_index_path(struct mail_storage *storage,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(name, "INBOX") == 0 && storage->inbox_file != NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (full_filesystem_access && (*name == '/' || *name == '~'))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S, name, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic const char *maildir_get_control_path(struct mail_storage *storage,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (full_filesystem_access && (*name == '/' || *name == '~'))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return t_strconcat(storage->control_dir, "/"MAILDIR_FS_SEP_S,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int mkdir_verify(struct mail_storage *storage,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mkdir(dir, CREATE_MODE) < 0 && (errno != EEXIST || !verify)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (errno != EEXIST && (!verify || errno != ENOENT)) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi/* create or fix maildir, ignore if it already exists */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int create_maildir(struct mail_storage *storage,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!verify && !mkdir_verify(storage, dir, verify))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* small optimization. if we're verifying, we don't
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi check that the root dir actually exists unless we
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi fail here. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int create_index_dir(struct mail_storage *storage, const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *dir;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strcmp(storage->index_dir, storage->dir) == 0 ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strcmp(storage->index_dir, storage->inbox_file) == 0))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dir = t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S, name, NULL);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mkdir_parents(dir, CREATE_MODE) == -1 && errno != EEXIST) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_set_critical(storage, "mkdir(%s) failed: %m", dir);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int create_control_dir(struct mail_storage *storage, const char *name)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *dir;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi dir = t_strconcat(storage->control_dir, "/"MAILDIR_FS_SEP_S,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (mkdir_parents(dir, CREATE_MODE) < 0 && errno != EEXIST) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_set_critical(storage, "mkdir(%s) failed: %m", dir);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int verify_inbox(struct mail_storage *storage)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *inbox;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* first make sure the cur/ new/ and tmp/ dirs exist
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi in root dir */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* create the .INBOX directory */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!create_maildir(storage, storage->inbox_file, TRUE))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* make sure the index directories exist */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void maildir_mail_init(struct index_mail *mail)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct mailbox *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomimaildir_open(struct mail_storage *storage, const char *name,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi index_dir = maildir_get_index_path(storage, name);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi control_dir = maildir_get_control_path(storage, name);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi index = index_storage_lookup_ref(index_dir, path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi index = maildir_index_alloc(path, index_dir, control_dir);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ibox = index_storage_mailbox_init(storage, &maildir_mailbox,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* for shared mailboxes get the create mode from the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi permissions of dovecot-shared file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (stat(t_strconcat(path, "/dovecot-shared", NULL), &st) < 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic struct mailbox *
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *path;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi name = maildir_fix_mailbox_name(storage, name, TRUE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_set_error(storage, "Invalid mailbox name");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* exists - make sure the required directories are also there */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_set_error(storage, "Mailbox doesn't exist: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int maildir_create_mailbox(struct mail_storage *storage,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *name,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *path;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi name = maildir_fix_mailbox_name(storage, name, TRUE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi mail_storage_set_error(storage, "Invalid mailbox name");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "Mailbox already exists");
return FALSE;
return TRUE;
const char *name)
int count;
return FALSE;
return FALSE;
name);
return FALSE;
return FALSE;
count = 0;
return FALSE;
return FALSE;
count++;
return TRUE;
return TRUE;
return FALSE;
return TRUE;
int ret;
ret = 0;
const char *list_name;
t_push();
t_pop();
t_pop();
return ret;
return FALSE;
return FALSE;
if (ret < 0)
return FALSE;
return FALSE;
return TRUE;
return FALSE;
return FALSE;
const char *name,
const char *path;
return TRUE;
return TRUE;
return TRUE;
return TRUE;
return FALSE;
unsigned int min_newmail_notify_interval)
if (flags == 0) {
return FALSE;
return TRUE;
return FALSE;
return FALSE;
return TRUE;
NULL,
NULL,
NULL,
NULL,
NULL,