mailbox-list.c revision 93107c0447855ce051cb4a2215ac1089536110ca
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mkdir-parents.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "sha1.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "home-expand.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "close-keep-errno.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "eacces-error.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "safe-mkstemp.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "unlink-directory.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-match.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-utf7.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mailbox-log.h"
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#include "mailbox-tree.h"
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#include "mail-storage-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mailbox-list-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <time.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <dirent.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen then start renaming them to larger names from end to beginning, which
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen eventually would start causing the failures when trying to use too
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen long mailbox names. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MAILBOX_MAX_HIERARCHY_LEVELS 20
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct ns_list_iterate_context {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct mailbox_list_iterate_context ctx;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct mail_namespace *namespaces;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_t pool;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char **patterns;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid (*hook_mailbox_list_created)(struct mailbox_list *list);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenvoid mailbox_lists_init(void)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen i_array_init(&mailbox_list_drivers, 4);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen}
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenvoid mailbox_lists_deinit(void)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen array_free(&mailbox_list_drivers);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen}
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mailbox_list *const *drivers;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i, count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen for (i = 0; i < count; i++) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen *idx_r = i;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return TRUE;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen unsigned int idx;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen list->name);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen array_delete(&mailbox_list_drivers, idx, 1);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen}
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen const struct mailbox_list_settings *set,
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen enum mailbox_list_flags flags, const char **error_r)
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen{
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen const struct mailbox_list *const *class_p;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen struct mailbox_list *list;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen const char *path;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen unsigned int idx;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen i_assert(ns->list == NULL);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0');
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen i_assert(set->subscription_fname == NULL ||
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen *set->subscription_fname != '\0');
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen *error_r = t_strdup_printf("Unknown mailbox list driver: %s",
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen driver);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen return -1;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen }
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen list = (*class_p)->v.alloc();
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
f75188af11dce30be322cc2eefa3e3884871abf7Timo Sirainen
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen list->ns = ns;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen list->mail_set = ns->mail_set;
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen list->flags = flags;
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen list->file_create_mode = (mode_t)-1;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->dir_create_mode = (mode_t)-1;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->file_create_gid = (gid_t)-1;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* copy settings */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen p_strdup(list->pool, set->index_dir);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen p_strdup(list->pool, set->control_dir);
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.subscription_fname =
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen p_strdup(list->pool, set->subscription_fname);
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen list->set.dir_guid_fname =
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen p_strdup(list->pool, set->dir_guid_fname);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_strdup(list->pool, set->maildir_name);
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen list->set.mailbox_dir_name =
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen p_strdup(list->pool, set->mailbox_dir_name);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen list->set.mailbox_dir_name = "";
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
f75188af11dce30be322cc2eefa3e3884871abf7Timo Sirainen list->set.mailbox_dir_name =
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen p_strdup(list->pool, set->mailbox_dir_name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen list->set.mailbox_dir_name =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ns->mail_set->mail_debug) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->name,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->set.control_dir == NULL ?
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen "" : list->set.control_dir,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->set.inbox_path == NULL ?
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen "" : list->set.inbox_path);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen mail_namespace_finish_list_init(ns, list);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (path != NULL) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen list->changelog = mailbox_log_alloc(path);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (hook_mailbox_list_created != NULL)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen hook_mailbox_list_created(list);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen return 0;
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen}
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen
8830fab191cab8440281eb641dfdd93974b2933bTimo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
f75188af11dce30be322cc2eefa3e3884871abf7Timo Sirainen const char **path_r, const char **error_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen size_t len = strlen(path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (len > 1 && path[len-1] == '/')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen path = t_strndup(path, len-1);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (path[0] == '~' && path[1] != '/') {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* ~otheruser/dir */
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (home_try_expand(&path) < 0) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen *error_r = t_strconcat(
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen "No home directory for system user. "
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen "Can't expand ", t_strcut(path, '/'),
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen " for ", NULL);
f75188af11dce30be322cc2eefa3e3884871abf7Timo Sirainen return -1;
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = "Home directory not set for user. "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Can't expand ~/ for ";
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen return -1;
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen *path_r = path;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen return 0;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen}
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen{
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen const char *const *args = *_args;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen const char *str = args[0];
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen args++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*args != NULL && **args == '\0') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args++;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (*args == NULL) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen str = t_strconcat(str, ":", NULL);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen break;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen }
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen str = t_strconcat(str, ":", *args, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_args = args;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen return str;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mailbox_list_settings_parse(const char *data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mailbox_list_settings *set,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_namespace *ns, const char **error_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen *error_r = NULL;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (*data == '\0')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* <root dir> */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tmp = t_strsplit(data, ":");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = split_next_arg(&tmp);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*tmp != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = split_next_arg(&tmp);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value = strchr(str, '=');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (value == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen key = str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value = "";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen key = t_strdup_until(str, value);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(key, "INBOX") == 0)
c1d45cada20777e1973579d40d0ebe43f89bb053Timo Sirainen dest = &set->inbox_path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(key, "INDEX") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest = &set->index_dir;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(key, "CONTROL") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest = &set->control_dir;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(key, "ALT") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest = &set->alt_dir;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(key, "LAYOUT") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest = &set->layout;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(key, "SUBSCRIPTIONS") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dest = &set->subscription_fname;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(key, "DIRNAME") == 0)
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen dest = &set->maildir_name;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen else if (strcmp(key, "MAILBOXDIR") == 0)
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen dest = &set->mailbox_dir_name;
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fix_path(ns, value, dest, &error) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen }
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen set->index_dir = "";
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen return 0;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen}
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen{
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen struct mailbox_list *list = *_list;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen *_list = NULL;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen i_free_and_null(list->error_string);
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen if (list->changelog != NULL)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen mailbox_log_free(&list->changelog);
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen list->v.deinit(list);
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen}
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen{
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen return list->name;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen}
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen{
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen return list->hierarchy_sep;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen{
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen return list->flags;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen}
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mail_namespace *
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen{
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen return list->ns;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic mode_t get_dir_mode(mode_t mode)
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen{
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen /* add the execute bit if either read or write bit is set */
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if ((mode & 0600) != 0) mode |= 0100;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((mode & 0060) != 0) mode |= 0010;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if ((mode & 0006) != 0) mode |= 0001;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen return mode;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenstruct mail_user *
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return list->ns->user;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct mail_storage **storage_r)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((*list)->v.get_storage != NULL)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen else {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *storage_r = (*list)->ns->storage;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen return 0;
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen }
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen}
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_storage **storage)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *storage = list->ns->storage;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainenstatic void
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mode_t *file_mode_r, mode_t *dir_mode_r,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen gid_t *gid_r, const char **gid_origin_r)
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen if (stat(path, &st) < 0) {
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen if (!ENOTFOUND(errno)) {
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen path);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen } else if (list->mail_set->mail_debug) {
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_info("Namespace %s: Permission lookup failed from %s",
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen list->ns->prefix, path);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (name != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* return defaults */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mailbox_list_get_permissions_full(list, NULL,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen file_mode_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dir_mode_r, gid_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen gid_origin_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* return safe defaults */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *file_mode_r = 0600;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *dir_mode_r = 0700;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *gid_r = (gid_t)-1;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen *gid_origin_r = "defaults";
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen } else {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen *file_mode_r = st.st_mode & 0666;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen *dir_mode_r = st.st_mode & 0777;
a9bbb619908c206d9cb319398d4aaad37a22cd67Timo Sirainen *gid_origin_r = path;
a9bbb619908c206d9cb319398d4aaad37a22cd67Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (!S_ISDIR(st.st_mode)) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* we're getting permissions from a file.
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen apply +x modes as necessary. */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen *dir_mode_r = get_dir_mode(*dir_mode_r);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* directory's GID is used automatically for new
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen files */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen *gid_r = (gid_t)-1;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* group has same permissions as world, so don't bother
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen changing it */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *gid_r = (gid_t)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (getegid() == st.st_gid) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* using our own gid, no need to change it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *gid_r = (gid_t)-1;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen } else {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen *gid_r = st.st_gid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (name == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->file_create_mode = *file_mode_r;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->dir_create_mode = *dir_mode_r;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->file_create_gid = *gid_r;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->file_create_gid_origin =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_strdup(list->pool, *gid_origin_r);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_info("Namespace %s: Using permissions from %s: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "mode=0%o gid=%ld", list->ns->prefix, path,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (int)list->dir_create_mode,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->file_create_gid == (gid_t)-1 ? -1L :
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen (long)list->file_create_gid);
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen }
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen}
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen
6e354c4070b611471727692919d29440d73a73f7Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen const char *name,
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen mode_t *mode_r, gid_t *gid_r,
6e354c4070b611471727692919d29440d73a73f7Timo Sirainen const char **gid_origin_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mode_t dir_mode;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *mode_r = list->file_create_mode;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *gid_r = list->file_create_gid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *gid_origin_r = list->file_create_gid_origin;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen gid_origin_r);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *name,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen mode_t *mode_r, gid_t *gid_r,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen const char **gid_origin_r)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen{
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen mode_t file_mode;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *mode_r = list->dir_create_mode;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *gid_r = list->file_create_gid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *gid_origin_r = list->file_create_gid_origin;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen }
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mailbox_list_get_permissions_full(list, name, &file_mode,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mode_r, gid_r, gid_origin_r);
}
bool mailbox_list_is_valid_pattern(struct mailbox_list *list,
const char *pattern)
{
return list->v.is_valid_pattern(list, pattern);
}
bool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
const char *name)
{
if (*name == '\0' && *list->ns->prefix != '\0' &&
(list->ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0) {
/* an ugly way to get to mailbox root (e.g. Maildir/ when
it's not the INBOX) */
return TRUE;
}
return list->v.is_valid_existing_name(list, name);
}
bool mailbox_list_is_valid_create_name(struct mailbox_list *list,
const char *name)
{
const char *p;
int ret;
/* safer to just disallow all control characters */
for (p = name; *p != '\0'; p++) {
if (*p < ' ')
return FALSE;
}
T_BEGIN {
string_t *str = t_str_new(256);
ret = imap_utf7_to_utf8(name, str);
} T_END;
return ret < 0 ? FALSE :
list->v.is_valid_create_name(list, name);
}
const char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
enum mailbox_list_path_type type)
{
mailbox_list_clear_error(list);
return list->v.get_path(list, name, type);
}
const char *mailbox_list_get_temp_prefix(struct mailbox_list *list)
{
return list->v.get_temp_prefix(list, FALSE);
}
const char *mailbox_list_get_global_temp_prefix(struct mailbox_list *list)
{
return list->v.get_temp_prefix(list, TRUE);
}
const char *mailbox_list_join_refpattern(struct mailbox_list *list,
const char *ref, const char *pattern)
{
if (list->v.join_refpattern != NULL)
return list->v.join_refpattern(list, ref, pattern);
/* the default implementation: */
if (*ref != '\0') {
/* merge reference and pattern */
pattern = t_strconcat(ref, pattern, NULL);
}
return pattern;
}
int mailbox_list_get_mailbox_name_status(struct mailbox_list *list,
const char *name,
enum mailbox_name_status *status)
{
mailbox_list_clear_error(list);
if (!mailbox_list_is_valid_existing_name(list, name)) {
*status = MAILBOX_NAME_INVALID;
return 0;
}
return list->v.get_mailbox_name_status(list, name, status);
}
struct mailbox_list_iterate_context *
mailbox_list_iter_init(struct mailbox_list *list, const char *pattern,
enum mailbox_list_iter_flags flags)
{
const char *patterns[2];
patterns[0] = pattern;
patterns[1] = NULL;
return mailbox_list_iter_init_multiple(list, patterns, flags);
}
struct mailbox_list_iterate_context *
mailbox_list_iter_init_multiple(struct mailbox_list *list,
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
i_assert(*patterns != NULL);
mailbox_list_clear_error(list);
return list->v.iter_init(list, patterns, flags);
}
static struct mail_namespace *
ns_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns)
{
if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SKIP_ALIASES) != 0) {
while (ns != NULL && ns->alias_for != NULL)
ns = ns->next;
}
return ns;
}
static const struct mailbox_info *
mailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx)
{
struct ns_list_iterate_context *ctx =
(struct ns_list_iterate_context *)_ctx;
const struct mailbox_info *info;
info = mailbox_list_iter_next(ctx->backend_ctx);
if (info == NULL && ctx->namespaces != NULL) {
/* go to the next namespace */
if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
_ctx->failed = TRUE;
ctx->ctx.list->ns = ctx->namespaces;
ctx->backend_ctx =
mailbox_list_iter_init_multiple(ctx->namespaces->list,
ctx->patterns,
_ctx->flags);
ctx->namespaces = ns_next(ctx, ctx->namespaces->next);
return mailbox_list_ns_iter_next(_ctx);
}
return info;
}
static int
mailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx)
{
struct ns_list_iterate_context *ctx =
(struct ns_list_iterate_context *)_ctx;
int ret;
if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
_ctx->failed = TRUE;
ret = _ctx->failed ? -1 : 0;
pool_unref(&ctx->pool);
return ret;
}
struct mailbox_list_iterate_context *
mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces,
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
struct ns_list_iterate_context *ctx;
unsigned int i, count;
pool_t pool;
i_assert(namespaces != NULL);
pool = pool_alloconly_create("mailbox list namespaces", 512);
ctx = p_new(pool, struct ns_list_iterate_context, 1);
ctx->pool = pool;
ctx->ctx.flags = flags;
ctx->ctx.list = p_new(pool, struct mailbox_list, 1);
ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next;
ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit;
count = str_array_length(patterns);
ctx->patterns = p_new(pool, const char *, count + 1);
for (i = 0; i < count; i++)
ctx->patterns[i] = p_strdup(pool, patterns[i]);
namespaces = ns_next(ctx, namespaces);
ctx->ctx.list->ns = namespaces;
ctx->backend_ctx = mailbox_list_iter_init_multiple(namespaces->list,
patterns, flags);
ctx->namespaces = ns_next(ctx, namespaces->next);
return &ctx->ctx;
}
const struct mailbox_info *
mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
{
const struct mailbox_info *info;
info = ctx->list->v.iter_next(ctx);
if (info != NULL)
ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE;
return info;
}
int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx)
{
struct mailbox_list_iterate_context *ctx = *_ctx;
*_ctx = NULL;
return ctx->list->v.iter_deinit(ctx);
}
int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
enum mailbox_info_flags *flags_r)
{
struct mailbox_list_iterate_context ctx;
const char *path;
memset(&ctx, 0, sizeof(ctx));
ctx.list = list;
*flags_r = 0;
path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
return list->v.iter_is_mailbox == NULL ? 0 :
list->v.iter_is_mailbox(&ctx, path, "", "",
MAILBOX_LIST_FILE_TYPE_UNKNOWN,
flags_r);
}
void mailbox_list_add_change(struct mailbox_list *list,
enum mailbox_log_record_type type,
const uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
{
struct mailbox_log_record rec;
if (list->changelog == NULL || mail_guid_128_is_empty(mailbox_guid))
return;
memset(&rec, 0, sizeof(rec));
rec.type = type;
memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
mailbox_log_record_set_timestamp(&rec, ioloop_time);
(void)mailbox_log_append(list->changelog, &rec);
}
int mailbox_list_set_subscribed(struct mailbox_list *list,
const char *name, bool set)
{
uint8_t guid[MAIL_GUID_128_SIZE];
unsigned char sha[SHA1_RESULTLEN];
mailbox_list_clear_error(list);
if (list->v.set_subscribed(list, name, set) < 0)
return -1;
/* subscriptions are about names, not about mailboxes. it's possible
to have a subscription to non-existing mailbox. renames also don't
change subscriptions. so instead of using actual GUIDs, we'll use
hash of the name. */
sha1_get_digest(name, strlen(name), sha);
memcpy(guid, sha, I_MIN(sizeof(guid), sizeof(sha)));
mailbox_list_add_change(list, set ? MAILBOX_LOG_RECORD_SUBSCRIBE :
MAILBOX_LOG_RECORD_UNSUBSCRIBE, guid);
return 0;
}
int mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
if (!mailbox_list_is_valid_existing_name(list, name) || *name == '\0') {
mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
if (strcmp(name, "INBOX") == 0 &&
(list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
}
return list->v.delete_mailbox(list, name);
}
static bool nullequals(const void *p1, const void *p2)
{
return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
}
int mailbox_list_rename_mailbox(struct mailbox_list *oldlist,
const char *oldname,
struct mailbox_list *newlist,
const char *newname, bool rename_children)
{
struct mail_storage *oldstorage;
struct mail_storage *newstorage;
uint8_t guid[MAIL_GUID_128_SIZE];
if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
return -1;
newstorage = oldstorage;
mailbox_list_get_closest_storage(newlist, &newstorage);
if (!mailbox_list_is_valid_existing_name(oldlist, oldname) ||
*oldname == '\0' ||
!mailbox_list_is_valid_create_name(newlist, newname)) {
mailbox_list_set_error(oldlist, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
if (strcmp(oldstorage->name, newstorage->name) != 0) {
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
"Can't rename mailbox to another storage type.");
return -1;
}
if (!nullequals(oldlist->set.index_dir, newlist->set.index_dir) ||
!nullequals(oldlist->set.control_dir, newlist->set.control_dir)) {
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
"Can't rename mailboxes across specified storages.");
return -1;
}
if (oldlist->ns->type != NAMESPACE_PRIVATE ||
newlist->ns->type != NAMESPACE_PRIVATE) {
mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
"Renaming not supported across non-private namespaces.");
return -1;
}
(void)mailbox_list_get_guid(oldlist, oldname, guid);
if (oldlist->v.rename_mailbox(oldlist, oldname, newlist, newname,
rename_children) < 0)
return -1;
mailbox_list_add_change(oldlist, MAILBOX_LOG_RECORD_RENAME, guid);
return 0;
}
static int mailbox_list_read_guid(struct mailbox_list *list, const char *path,
uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
{
int fd, ret;
fd = open(path, O_RDONLY);
if (fd != -1) {
ret = read_full(fd, mailbox_guid, MAIL_GUID_128_SIZE);
close_keep_errno(fd);
if (ret > 0)
return 1;
if (ret < 0) {
mailbox_list_set_critical(list, "read(%s) failed: %m",
path);
return -1;
}
/* recreate it */
mailbox_list_set_critical(list, "Corrupted mailbox GUID in %s",
path);
(void)unlink(path);
return 0;
} else if (errno == ENOENT) {
return 0;
} else if (errno == EACCES) {
mailbox_list_set_critical(list, "%s",
eacces_error_get("open", path));
return -1;
} else {
mailbox_list_set_critical(list, "open(%s) failed: %m", path);
return -1;
}
}
static int
mailbox_list_get_guid_real(struct mailbox_list *list, const char *name,
uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
{
string_t *temp_path;
const char *dir, *path;
int fd, ret;
memset(mailbox_guid, 0, MAIL_GUID_128_SIZE);
if (list->set.dir_guid_fname == NULL) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
"Storage doesn't support mailbox GUIDs");
return -1;
}
dir = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
path = t_strconcat(dir, "/", list->set.dir_guid_fname, NULL);
/* try reading the GUID from the file */
if ((ret = mailbox_list_read_guid(list, path, mailbox_guid)) < 0)
return -1;
/* create temp file containing a new GUID. the file must never be
modified and it doesn't contain anything sensitive, so just make
it world-readable. */
temp_path = t_str_new(256);
str_append(temp_path, path);
fd = safe_mkstemp_hostpid_group(temp_path, 0644, (gid_t)-1, NULL);
if (fd == -1) {
mailbox_list_set_critical(list,
"safe_mkstemp(%s) failed: %m", str_c(temp_path));
return -1;
}
mail_generate_guid_128(mailbox_guid);
ret = write_full(fd, mailbox_guid, MAIL_GUID_128_SIZE);
close_keep_errno(fd);
if (ret < 0) {
mailbox_list_set_critical(list,
"write(%s) failed: %m", str_c(temp_path));
} else if (link(str_c(temp_path), path) == 0) {
/* success */
} else if (errno == EEXIST) {
/* someone else just created the GUID, read it. */
ret = mailbox_list_read_guid(list, path, mailbox_guid);
if (ret == 0) {
/* broken? shouldn't really happen. we anyway deleted
it already, so try again. */
return mailbox_list_get_guid(list, name, mailbox_guid);
}
} else {
mailbox_list_set_critical(list, "link(%s, %s) failed: %m",
str_c(temp_path), path);
ret = -1;
}
(void)unlink(str_c(temp_path));
return ret < 0 ? -1 : 0;
}
int mailbox_list_get_guid(struct mailbox_list *list, const char *name,
uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
{
int ret;
T_BEGIN {
ret = mailbox_list_get_guid_real(list, name, mailbox_guid);
} T_END;
return ret;
}
struct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list)
{
return list->changelog;
}
static int mailbox_list_try_delete(struct mailbox_list *list, const char *dir)
{
if (unlink_directory(dir, TRUE) == 0 || errno == ENOENT)
return 0;
if (errno == ENOTEMPTY) {
/* We're most likely using NFS and we can't delete
.nfs* files. */
mailbox_list_set_error(list, MAIL_ERROR_INUSE,
"Mailbox is still open in another session, "
"can't delete it.");
} else {
mailbox_list_set_critical(list,
"unlink_directory(%s) failed: %m", dir);
}
return -1;
}
int mailbox_list_delete_index_control(struct mailbox_list *list,
const char *name)
{
const char *path, *index_dir, *dir;
path = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
/* delete the index directory first, so that if we crash we don't
leave indexes for deleted mailboxes lying around */
index_dir = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_INDEX);
if (*index_dir != '\0' && strcmp(index_dir, path) != 0) {
if (mailbox_list_try_delete(list, index_dir) < 0)
return -1;
}
/* control directory next */
dir = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_CONTROL);
if (*dir != '\0' && strcmp(dir, path) != 0 &&
strcmp(dir, index_dir) != 0) {
if (mailbox_list_try_delete(list, dir) < 0)
return -1;
}
return 0;
}
static void node_fix_parents(struct mailbox_node *node)
{
/* If we happened to create any of the parents, we need to mark them
nonexistent. */
node = node->parent;
for (; node != NULL; node = node->parent) {
if ((node->flags & MAILBOX_MATCHED) == 0)
node->flags |= MAILBOX_NONEXISTENT;
}
}
static void
mailbox_list_iter_update_real(struct mailbox_list_iter_update_context *ctx,
const char *name)
{
struct mail_namespace *ns = ctx->iter_ctx->list->ns;
struct mailbox_node *node;
enum mailbox_info_flags create_flags = 0, always_flags;
enum imap_match_result match;
const char *p;
bool created, add_matched;
if (ctx->update_only ||
(ctx->iter_ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0)
create_flags = MAILBOX_NONEXISTENT | MAILBOX_NOCHILDREN;
always_flags = ctx->leaf_flags;
add_matched = TRUE;
for (;;) {
created = FALSE;
match = imap_match(ctx->glob, name);
if (match == IMAP_MATCH_YES) {
node = ctx->update_only ?
mailbox_tree_lookup(ctx->tree_ctx, name) :
mailbox_tree_get(ctx->tree_ctx, name, &created);
if (created) {
node->flags = create_flags;
if (create_flags != 0)
node_fix_parents(node);
}
if (node != NULL) {
if (!ctx->update_only && add_matched)
node->flags |= MAILBOX_MATCHED;
node->flags |= always_flags;
}
/* We don't want to show the parent mailboxes unless
something else matches them, but if they are matched
we want to show them having child subscriptions */
add_matched = FALSE;
} else {
if ((match & IMAP_MATCH_PARENT) == 0)
break;
/* We've a (possibly) non-subscribed parent mailbox
which has a subscribed child mailbox. Make sure we
return the parent mailbox. */
}
if (!ctx->match_parents)
break;
/* see if parent matches */
p = strrchr(name, ns->sep);
if (p == NULL)
break;
name = t_strdup_until(name, p);
create_flags &= ~MAILBOX_NOCHILDREN;
always_flags = MAILBOX_CHILDREN | ctx->parent_flags;
}
}
void mailbox_list_iter_update(struct mailbox_list_iter_update_context *ctx,
const char *name)
{
T_BEGIN {
mailbox_list_iter_update_real(ctx, name);
} T_END;
}
bool mailbox_list_name_is_too_large(const char *name, char sep)
{
unsigned int levels = 1, level_len = 0;
for (; *name != '\0'; name++) {
if (*name == sep) {
if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
return TRUE;
levels++;
level_len = 0;
} else {
level_len++;
}
}
if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
return TRUE;
if (levels > MAILBOX_MAX_HIERARCHY_LEVELS)
return TRUE;
return FALSE;
}
enum mailbox_list_file_type
mailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
{
enum mailbox_list_file_type type;
#ifdef HAVE_DIRENT_D_TYPE
switch (d->d_type) {
case DT_UNKNOWN:
type = MAILBOX_LIST_FILE_TYPE_UNKNOWN;
break;
case DT_REG:
type = MAILBOX_LIST_FILE_TYPE_FILE;
break;
case DT_DIR:
type = MAILBOX_LIST_FILE_TYPE_DIR;
break;
case DT_LNK:
type = MAILBOX_LIST_FILE_TYPE_SYMLINK;
break;
default:
type = MAILBOX_LIST_FILE_TYPE_OTHER;
break;
}
#else
type = MAILBOX_LIST_FILE_TYPE_UNKNOWN;
#endif
return type;
}
bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
const char **name)
{
if (!list->mail_set->mail_full_filesystem_access)
return FALSE;
if (**name == '/')
return TRUE;
if (**name != '~')
return FALSE;
/* try to expand home directory */
if ((*name)[1] == '/') {
/* ~/dir - use the configured home directory */
if (mail_user_try_home_expand(list->ns->user, name) == 0)
return TRUE;
} else {
/* ~otheruser/dir - assume we're using system users */
if (home_try_expand(name) == 0)
return TRUE;
}
/* fallback to using ~dir */
return FALSE;
}
int mailbox_list_create_parent_dir(struct mailbox_list *list,
const char *mailbox, const char *path)
{
const char *p, *dir, *origin;
gid_t gid;
mode_t mode;
p = strrchr(path, '/');
if (p == NULL)
return 0;
dir = t_strdup_until(path, p);
mailbox_list_get_dir_permissions(list, mailbox, &mode, &gid, &origin);
if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 &&
errno != EEXIST) {
mailbox_list_set_critical(list, "mkdir_parents(%s) failed: %m",
dir);
return -1;
}
return 0;
}
const char *mailbox_list_get_last_error(struct mailbox_list *list,
enum mail_error *error_r)
{
if (error_r != NULL)
*error_r = list->error;
return list->error_string != NULL ? list->error_string :
"Unknown internal list error";
}
void mailbox_list_clear_error(struct mailbox_list *list)
{
i_free_and_null(list->error_string);
list->error = MAIL_ERROR_NONE;
}
void mailbox_list_set_error(struct mailbox_list *list,
enum mail_error error, const char *string)
{
i_free(list->error_string);
list->error_string = i_strdup(string);
list->error = error;
}
void mailbox_list_set_internal_error(struct mailbox_list *list)
{
struct tm *tm;
char str[256];
tm = localtime(&ioloop_time);
i_free(list->error_string);
list->error_string =
strftime(str, sizeof(str),
MAIL_ERRSTR_CRITICAL_MSG_STAMP, tm) > 0 ?
i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
list->error = MAIL_ERROR_TEMP;
}
void mailbox_list_set_critical(struct mailbox_list *list, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
i_error("%s", t_strdup_vprintf(fmt, va));
va_end(va);
/* critical errors may contain sensitive data, so let user
see only "Internal error" with a timestamp to make it
easier to look from log files the actual error message. */
mailbox_list_set_internal_error(list);
}
bool mailbox_list_set_error_from_errno(struct mailbox_list *list)
{
const char *error_string;
enum mail_error error;
if (!mail_error_from_errno(&error, &error_string))
return FALSE;
mailbox_list_set_error(list, error, error_string);
return TRUE;
}