mbox-storage.c revision ca1319463a8e8dbfeff8b78b0c687980b6428ddc
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (C) 2002 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "unlink-directory.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "subscription-file/subscription-file.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "mail-custom-flags.h"
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen#include "mbox-index.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "mbox-storage.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen#include <stdio.h>
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen#include <stdlib.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <unistd.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <fcntl.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <sys/stat.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define CREATE_MODE 0770 /* umask() should limit it more */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenextern MailStorage mbox_storage;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenextern Mailbox mbox_mailbox;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic int mbox_autodetect(const char *data)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen const char *path;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen struct stat st;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen path = t_strconcat(data, "/.imap", NULL);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen if (stat(path, &st) == 0 && S_ISDIR(st.st_mode) &&
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen access(path, R_OK|W_OK|X_OK) == 0)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return TRUE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen path = t_strconcat(data, "/inbox", NULL);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode) &&
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen access(path, R_OK|W_OK) == 0)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return TRUE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen path = t_strconcat(data, "/mbox", NULL);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode) &&
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen access(path, R_OK|W_OK) == 0)
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek return TRUE;
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek return FALSE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic MailStorage *mbox_create(const char *data, const char *user)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen MailStorage *storage;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *home, *path;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (data == NULL || *data == '\0') {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we'll need to figure out the mail location ourself.
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen it's root dir if we've already chroot()ed, otherwise
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen either $HOME/mail or $HOME/Mail */
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek if (mbox_autodetect(""))
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek data = "/";
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek else {
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek home = getenv("HOME");
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek if (home != NULL) {
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek path = t_strconcat(home, "/mail", NULL);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0)
30517c760897cc4f249da1830ae1996f4d7b5aeaTimo Sirainen data = path;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen else {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen path = t_strconcat(home, "/Mail", NULL);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (access(path, R_OK|W_OK|X_OK) == 0)
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek data = path;
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen }
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (data == NULL)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return NULL;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen storage = i_new(MailStorage, 1);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen memcpy(storage, &mbox_storage, sizeof(MailStorage));
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen storage->dir = i_strdup(data);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen storage->user = i_strdup(user);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return storage;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen}
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenstatic void mbox_free(MailStorage *storage)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen{
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen i_free(storage->dir);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen i_free(storage->user);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_free(storage);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int mbox_is_valid_name(MailStorage *storage, const char *name)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *p;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int newdir;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (name[0] == '\0' || name[0] == storage->hierarchy_sep)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return FALSE;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen /* make sure there's no "../" or "..\" stuff */
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen newdir = TRUE;
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen for (p = name; *p != '\0'; p++) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (newdir && p[0] == '.' && p[1] == '.' &&
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen (p[2] == '/' || p[2] == '\\'))
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return FALSE;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen newdir = p[0] == '/' || p[0] == '\\';
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return TRUE;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic const char *mbox_get_index_dir(const char *mbox_path)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen const char *p, *rootpath;
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen p = strrchr(mbox_path, '/');
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen if (p == NULL)
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen return t_strconcat(".imap/", mbox_path);
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen else {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen rootpath = t_strdup_until(mbox_path, p);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return t_strconcat(rootpath, "/.imap/", p+1, NULL);
660ecbaf80e6b3cf3a70ed1e0cdf7f8af6d895d0Josef 'Jeff' Sipek }
660ecbaf80e6b3cf3a70ed1e0cdf7f8af6d895d0Josef 'Jeff' Sipek}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int create_mbox_index_dirs(const char *mbox_path, int verify)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen{
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen const char *index_dir, *imap_dir;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen index_dir = mbox_get_index_dir(mbox_path);
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen imap_dir = t_strdup_until(index_dir, strstr(index_dir, ".imap/") + 5);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mkdir(imap_dir, CREATE_MODE) == -1 && errno != EEXIST)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mkdir(index_dir, CREATE_MODE) == -1 && (errno != EEXIST || !verify))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen return TRUE;
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen}
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainenstatic void verify_inbox(MailStorage *storage)
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen{
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen char path[1024];
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen int fd;
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen i_snprintf(path, sizeof(path), "%s/inbox", storage->dir);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen /* make sure inbox file itself exists */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (fd != -1)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen (void)close(fd);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* make sure the index directories exist */
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen (void)create_mbox_index_dirs(path, TRUE);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen}
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainenstatic Mailbox *mbox_open(MailStorage *storage, const char *name,
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen int readonly, int fast)
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen{
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen IndexMailbox *ibox;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen const char *path, *index_dir;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen /* name = "foo/bar"
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen mbox_path = "/mail/foo/bar"
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen index_dir = "/mail/foo/.imap/bar" */
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen path = t_strconcat(storage->dir, "/", name, NULL);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen index_dir = mbox_get_index_dir(path);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen ibox = index_storage_init(storage, &mbox_mailbox,
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen mbox_index_alloc(index_dir, path),
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen name, readonly, fast);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen if (ibox != NULL)
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen ibox->expunge_locked = mbox_expunge_locked;
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainen return (Mailbox *) ibox;
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen}
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic Mailbox *mbox_open_mailbox(MailStorage *storage, const char *name,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen int readonly, int fast)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct stat st;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen char path[1024];
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_storage_clear_error(storage);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* INBOX is always case-insensitive */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (strcasecmp(name, "INBOX") == 0) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* make sure inbox exists */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen verify_inbox(storage);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return mbox_open(storage, "inbox", readonly, fast);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (!mbox_is_valid_name(storage, name)) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen mail_storage_set_error(storage, "Invalid mailbox name");
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return FALSE;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_snprintf(path, sizeof(path), "%s/%s", storage->dir, name);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (stat(path, &st) == 0) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen /* exists - make sure the required directories are also there */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen (void)create_mbox_index_dirs(path, TRUE);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return mbox_open(storage, name, readonly, fast);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen } else if (errno == ENOENT) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen mail_storage_set_error(storage, "Mailbox doesn't exist: %s",
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen name);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return NULL;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen } else {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen mail_storage_set_critical(storage, "Can't open mailbox %s: %m",
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen name);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return NULL;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen}
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainenstatic int mbox_create_mailbox(MailStorage *storage, const char *name)
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen{
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen struct stat st;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen char path[1024];
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen int fd;
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen mail_storage_clear_error(storage);
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen if (strcasecmp(name, "INBOX") == 0)
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen name = "inbox";
ba55ec8fdf79301bfce9838d773250cef9486178Timo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (!mbox_is_valid_name(storage, name)) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen mail_storage_set_error(storage, "Invalid mailbox name");
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return FALSE;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen /* make sure it doesn't exist already */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen i_snprintf(path, sizeof(path), "%s/%s", storage->dir, name);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (stat(path, &st) == 0) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen mail_storage_set_error(storage, "Mailbox already exists");
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return FALSE;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (errno != ENOENT) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen mail_storage_set_critical(storage, "stat() failed for mbox "
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen "file %s: %m", path);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen return FALSE;
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen }
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen /* create the mailbox file */
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen if (fd != -1) {
82ea464c113f43aaa2b2e23de334cf3081c332beTimo Sirainen (void)close(fd);
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen return TRUE;
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen } else if (errno == EEXIST) {
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen /* mailbox was just created between stat() and open() call.. */
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen mail_storage_set_error(storage, "Mailbox already exists");
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen return FALSE;
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen } else {
89a89730a1dd98edb5c16a5b65f693389eb81124Timo Sirainen mail_storage_set_critical(storage, "Can't create mailbox "
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen "%s: %m", name);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return FALSE;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen }
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen}
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainenstatic int mbox_delete_mailbox(MailStorage *storage, const char *name)
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen{
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen const char *index_dir;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen char path[1024];
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen mail_storage_clear_error(storage);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen if (strcasecmp(name, "INBOX") == 0) {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen mail_storage_set_error(storage, "INBOX can't be deleted.");
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen return FALSE;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen }
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen if (!mbox_is_valid_name(storage, name)) {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen mail_storage_set_error(storage, "Invalid mailbox name");
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen return FALSE;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen }
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen /* first unlink the mbox file */
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen i_snprintf(path, sizeof(path), "%s/%s", storage->dir, name);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen if (unlink(path) == -1) {
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen if (errno == ENOENT) {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen mail_storage_set_error(storage,
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen "Mailbox doesn't exist: %s",
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen name);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen } else {
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen mail_storage_set_critical(storage, "Can't delete mbox "
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen "file %s: %m", path);
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen }
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen return FALSE;
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen }
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen
66967e15d8ed35f30493dd9694a0aabe1a266f9dTimo Sirainen /* next delete the index directory */
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen index_dir = mbox_get_index_dir(path);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen if (!unlink_directory(index_dir) && errno != ENOENT) {
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen mail_storage_set_critical(storage, "unlink_directory(%s) "
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen "failed: %m", index_dir);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return FALSE;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen return TRUE;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainenstatic int mbox_rename_mailbox(MailStorage *storage, const char *oldname,
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen const char *newname)
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *old_indexdir, *new_indexdir;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen char oldpath[1024], newpath[1024];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen mail_storage_clear_error(storage);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (!mbox_is_valid_name(storage, oldname) ||
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen !mbox_is_valid_name(storage, newname)) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_storage_set_error(storage, "Invalid mailbox name");
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen return FALSE;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen if (strcasecmp(oldname, "INBOX") == 0)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen oldname = "inbox";
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen /* NOTE: renaming INBOX works just fine with us, it's simply created
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen the next time it's needed. */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_snprintf(oldpath, sizeof(oldpath), "%s/%s", storage->dir, oldname);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_snprintf(newpath, sizeof(newpath), "%s/%s", storage->dir, newname);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (link(oldpath, newpath) == 0) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen (void)unlink(oldpath);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* ... */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen } else if (errno == EEXIST) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen mail_storage_set_error(storage,
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen "Target mailbox already exists");
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return FALSE;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen } else {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen mail_storage_set_critical(storage, "link(%s, %s) failed: %m",
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen oldpath, newpath);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen return FALSE;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen }
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen /* we need to rename the index directory as well */
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen old_indexdir = mbox_get_index_dir(oldpath);
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen new_indexdir = mbox_get_index_dir(newpath);
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen (void)rename(old_indexdir, new_indexdir);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return TRUE;
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen}
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainenstatic int mbox_get_mailbox_name_status(MailStorage *storage, const char *name,
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen MailboxNameStatus *status)
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen{
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen struct stat st;
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen char path[1024];
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_storage_clear_error(storage);
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen if (strcasecmp(name, "INBOX") == 0)
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen name = "inbox";
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!mbox_is_valid_name(storage, name)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *status = MAILBOX_NAME_INVALID;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return TRUE;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen }
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen i_snprintf(path, sizeof(path), "%s/%s", storage->dir, name);
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen if (stat(path, &st) == 0) {
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen *status = MAILBOX_NAME_EXISTS;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return TRUE;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen } else if (errno == ENOENT) {
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen *status = MAILBOX_NAME_VALID;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen return TRUE;
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen } else {
e0fab14602b73ff590b2a9c5d9e67e2dfb5d1f9eTimo Sirainen mail_storage_set_critical(storage, "mailbox name status: "
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen "stat(%s) failed: %m", path);
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen return FALSE;
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen }
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen}
a215abacb2d2d1e1bcd475756aab809038ae4277Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenstatic void mbox_storage_close(Mailbox *box)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen IndexMailbox *ibox = (IndexMailbox *) box;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_EXCLUSIVE))
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mail_storage_set_index_error(ibox);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen else {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* update flags by rewrite mbox file */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_index_rewrite(ibox->index);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen (void)ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen index_storage_close(box);
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo SirainenMailStorage mbox_storage = {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen "mbox", /* name */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen '/', /* hierarchy_sep - can't be changed */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_create,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_free,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_autodetect,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_open_mailbox,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_create_mailbox,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_delete_mailbox,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_rename_mailbox,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_find_mailboxes,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen subsfile_set_subscribed,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mbox_find_subscribed,
c6b6ac7819931dfa92c0182ffaa7db07ac6ab0daTimo Sirainen mbox_get_mailbox_name_status,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mail_storage_get_last_error,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen NULL,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen NULL,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen NULL
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen};
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen
5ca745ae8e9903ef5265360e4c882e9314595020Timo SirainenMailbox mbox_mailbox = {
5ca745ae8e9903ef5265360e4c882e9314595020Timo Sirainen NULL, /* name */
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen NULL, /* storage */
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen mbox_storage_close,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen index_storage_get_status,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen index_storage_sync,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen index_storage_expunge,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen index_storage_update_flags,
785ee8becdb11e41abaaf64c28eb3923215d1f27Timo Sirainen index_storage_copy,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen index_storage_fetch,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen index_storage_search,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen mbox_storage_save,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_storage_is_inconsistency_error,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen FALSE,
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen FALSE
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen