mailbox-list.c revision 2a6dcd984104fed84bed8795ccdfabb20e41ce52
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen#include "array.h"
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen#include "ioloop.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mkdir-parents.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "str.h"
7a7d2aa11e46195e2d92d6c337d7e78052a5ce67Timo Sirainen#include "sha1.h"
a956137aa86d16e5a90b9d4a9e69d3854d824380Timo Sirainen#include "home-expand.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "close-keep-errno.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "eacces-error.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "read-full.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "write-full.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "safe-mkstemp.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "unlink-directory.h"
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen#include "imap-match.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-utf7.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-log.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-tree.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-storage-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-list-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <time.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <unistd.h>
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen#include <dirent.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <sys/stat.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
afa201e7e1d2447e8dfa1aff43de0fdad564105fTimo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen then start renaming them to larger names from end to beginning, which
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen eventually would start causing the failures when trying to use too
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen long mailbox names. */
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen#define MAILBOX_MAX_HIERARCHY_LEVELS 20
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenstruct ns_list_iterate_context {
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct mailbox_list_iterate_context ctx;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen struct mailbox_list_iterate_context *backend_ctx;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen struct mail_namespace *namespaces;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen pool_t pool;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen const char **patterns;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen};
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenvoid mailbox_lists_init(void)
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen{
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen i_array_init(&mailbox_list_drivers, 4);
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen}
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenvoid mailbox_lists_deinit(void)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen{
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen array_free(&mailbox_list_drivers);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen}
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen{
860e6dd603921f61b0cd53c1cc16e1d66d312699Timo Sirainen const struct mailbox_list *const *drivers;
860e6dd603921f61b0cd53c1cc16e1d66d312699Timo Sirainen unsigned int i, count;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen for (i = 0; i < count; i++) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen *idx_r = i;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen return TRUE;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen }
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen }
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen return FALSE;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen}
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen{
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen unsigned int idx;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen list->name);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen }
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen array_append(&mailbox_list_drivers, &list, 1);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen}
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen{
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen unsigned int idx;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen list->name);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen }
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen array_delete(&mailbox_list_drivers, idx, 1);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen}
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenconst struct mailbox_list *
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenmailbox_list_find_class(const char *driver)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen{
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen const struct mailbox_list *const *class_p;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen unsigned int idx;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (!mailbox_list_driver_find(driver, &idx))
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen return NULL;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen return *class_p;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen}
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen const struct mailbox_list_settings *set,
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen enum mailbox_list_flags flags, const char **error_r)
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mailbox_list *const *class_p;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mailbox_list *list;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_assert(ns->list == NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(set->subscription_fname == NULL ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *set->subscription_fname != '\0');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen *error_r = "Unknown driver name";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
d22301419109ed4a38351715e6760011421dadecTimo Sirainen set->maildir_name != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "maildir_name not supported by this driver";
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
d22301419109ed4a38351715e6760011421dadecTimo Sirainen set->alt_dir != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "alt_dir not supported by this driver";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen list = (*class_p)->v.alloc();
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen list->ns = ns;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->mail_set = ns->mail_set;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->flags = flags;
6b8043a4d96d696a6b65ebe9ae4f56fbec638348Timo Sirainen list->file_create_mode = (mode_t)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->dir_create_mode = (mode_t)-1;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen list->file_create_gid = (gid_t)-1;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen list->changelog_timestamp = (time_t)-1;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen /* copy settings */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (set->root_dir != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi p_strdup(list->pool, set->index_dir);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi list->set.control_dir = set->control_dir == NULL ||
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen p_strdup(list->pool, set->control_dir);
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen }
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->set.subscription_fname =
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen p_strdup(list->pool, set->subscription_fname);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen p_strdup(list->pool, set->maildir_name);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->set.mailbox_dir_name =
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen p_strdup(list->pool, set->mailbox_dir_name);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.mailbox_dir_name = "";
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen list->set.mailbox_dir_name =
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen p_strdup(list->pool, set->mailbox_dir_name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.mailbox_dir_name =
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen }
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ns->mail_set->mail_debug) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen list->name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
1127f3e1ad7135b6ee5d5e13f8fd1e72f85a76f8Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch list->set.control_dir == NULL ?
1127f3e1ad7135b6ee5d5e13f8fd1e72f85a76f8Timo Sirainen "" : list->set.control_dir,
1127f3e1ad7135b6ee5d5e13f8fd1e72f85a76f8Timo Sirainen list->set.inbox_path == NULL ?
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "" : list->set.inbox_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_namespace_finish_list_init(ns, list);
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hook_mailbox_list_created(list);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen}
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **path_r, const char **error_r)
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen{
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen size_t len = strlen(path);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen if (len > 1 && path[len-1] == '/')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen path = t_strndup(path, len-1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (path[0] == '~' && path[1] != '/') {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* ~otheruser/dir */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (home_try_expand(&path) < 0) {
7e1b549a1d841e59faad16430cbd1d56317db8afTimo Sirainen *error_r = t_strconcat(
7e1b549a1d841e59faad16430cbd1d56317db8afTimo Sirainen "No home directory for system user. "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Can't expand ", t_strcut(path, '/'),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen " for ", NULL);
f605df8a4c15cc7a11e16fdde994d51473700890Timo Sirainen return -1;
f605df8a4c15cc7a11e16fdde994d51473700890Timo Sirainen }
f605df8a4c15cc7a11e16fdde994d51473700890Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek *error_r = "Home directory not set for user. "
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen "Can't expand ~/ for ";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen *path_r = path;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return 0;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen}
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *args = *_args;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *str = args[0];
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen args++;
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen while (*args != NULL && **args == '\0') {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen args++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*args == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* string ends with ":", just ignore it. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = t_strconcat(str, ":", *args, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen args++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *_args = args;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mailbox_list_settings_parse(const char *data,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_list_settings *set,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_namespace *ns, const char **error_r)
ee9254cc7875519a9c71cc58a40610e6f320e907Timo Sirainen{
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen *error_r = NULL;
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen if (*data == '\0')
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen return 0;
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <root dir> */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen tmp = t_strsplit(data, ":");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = split_next_arg(&tmp);
fa7c76955c6bc62689fbdf39318194f85905e6e2Timo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
5bcac2212ca86e72289faa7db2c509841fbdbd59Timo Sirainen while (*tmp != NULL) {
5bcac2212ca86e72289faa7db2c509841fbdbd59Timo Sirainen str = split_next_arg(&tmp);
5bcac2212ca86e72289faa7db2c509841fbdbd59Timo Sirainen value = strchr(str, '=');
a956137aa86d16e5a90b9d4a9e69d3854d824380Timo Sirainen if (value == NULL) {
5bcac2212ca86e72289faa7db2c509841fbdbd59Timo Sirainen key = str;
a956137aa86d16e5a90b9d4a9e69d3854d824380Timo Sirainen value = "";
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen } else {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen key = t_strdup_until(str, value);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen value++;
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen if (strcmp(key, "INBOX") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dest = &set->inbox_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strcmp(key, "INDEX") == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dest = &set->index_dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (strcmp(key, "CONTROL") == 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dest = &set->control_dir;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else if (strcmp(key, "ALT") == 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dest = &set->alt_dir;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else if (strcmp(key, "LAYOUT") == 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dest = &set->layout;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else if (strcmp(key, "SUBSCRIPTIONS") == 0)
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen dest = &set->subscription_fname;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else if (strcmp(key, "DIRNAME") == 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dest = &set->maildir_name;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else if (strcmp(key, "MAILBOXDIR") == 0)
0a7b04ec6441fdcf083392888b2e30844fc3e86dTimo Sirainen dest = &set->mailbox_dir_name;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen else {
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek *error_r = t_strdup_printf("Unknown setting: %s", key);
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen return -1;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen }
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen if (fix_path(ns, value, dest, &error) < 0) {
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen return -1;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen }
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen }
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen set->index_dir = "";
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen return 0;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen}
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen{
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen struct mailbox_list *list = *_list;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen *_list = NULL;
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen i_free_and_null(list->error_string);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen if (list->changelog != NULL)
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen mailbox_log_free(&list->changelog);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->v.deinit(list);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen}
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen{
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen return list->name;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch}
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen{
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen return list->hierarchy_sep;
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen}
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek return list->flags;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainenstruct mail_namespace *
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen{
50bf6cfe2aa6111fb38af37970f9551b2286638cTimo Sirainen return list->ns;
50bf6cfe2aa6111fb38af37970f9551b2286638cTimo Sirainen}
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainenstatic mode_t get_dir_mode(mode_t mode)
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen{
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen /* add the execute bit if either read or write bit is set */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((mode & 0600) != 0) mode |= 0100;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((mode & 0060) != 0) mode |= 0010;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen if ((mode & 0006) != 0) mode |= 0001;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen return mode;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen}
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainenstruct mail_user *
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen{
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen return list->ns->user;
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen}
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Boschint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
e22ac7474fb36e3e3dcfeb70ea5f54ea812aa2d0Timo Sirainen struct mail_storage **storage_r)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen if ((*list)->v.get_storage != NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen else {
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen *storage_r = (*list)->ns->storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_storage **storage)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen *storage = list->ns->storage;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen}
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainenstatic void
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen mode_t *file_mode_r, mode_t *dir_mode_r,
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen gid_t *gid_r, const char **gid_origin_r)
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen{
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen const char *path;
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen struct stat st;
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen /* use safe defaults */
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen *file_mode_r = 0600;
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek *dir_mode_r = 0700;
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen *gid_r = (gid_t)-1;
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen *gid_origin_r = "defaults";
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen if (path == NULL) {
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen /* no filesystem support in storage */
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen } else if (stat(path, &st) < 0) {
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen if (!ENOTFOUND(errno)) {
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen path);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi } else if (list->mail_set->mail_debug) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi i_debug("Namespace %s: Permission lookup failed from %s",
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen list->ns->prefix, path);
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen }
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen if (name != NULL) {
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen /* return defaults */
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen mailbox_list_get_permissions_full(list, NULL,
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen file_mode_r,
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen dir_mode_r, gid_r,
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen gid_origin_r);
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen return;
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen }
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen } else {
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen *file_mode_r = st.st_mode & 0666;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *dir_mode_r = st.st_mode & 0777;
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek *gid_origin_r = path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen if (!S_ISDIR(st.st_mode)) {
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen /* we're getting permissions from a file.
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen apply +x modes as necessary. */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen *dir_mode_r = get_dir_mode(*dir_mode_r);
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen }
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* directory's GID is used automatically for new
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *gid_r = (gid_t)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* group has same permissions as world, so don't bother
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen changing it */
84e49ad7d7a840d600a961daeca60802e3d69cd0Timo Sirainen *gid_r = (gid_t)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (getegid() == st.st_gid) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* using our own gid, no need to change it */
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen *gid_r = (gid_t)-1;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen } else {
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen *gid_r = st.st_gid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (name == NULL) {
8b31f966d9688e07672ef1958dcbdb7686523c04Timo Sirainen list->file_create_mode = *file_mode_r;
9847ec56efa15fa063eea9988eee2d4ed9ec7d58Timo Sirainen list->dir_create_mode = *dir_mode_r;
d46a1e3f999dda802dc5137e883adcd7a6629cd3Timo Sirainen list->file_create_gid = *gid_r;
08e9fd42eb8007e1f9db62c088eef74f906114a5Josef 'Jeff' Sipek list->file_create_gid_origin =
08e9fd42eb8007e1f9db62c088eef74f906114a5Josef 'Jeff' Sipek p_strdup(list->pool, *gid_origin_r);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("Namespace %s: Using permissions from %s: "
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen "mode=0%o gid=%ld", list->ns->prefix,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path != NULL ? path : "",
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen (int)list->dir_create_mode,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->file_create_gid == (gid_t)-1 ? -1L :
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen (long)list->file_create_gid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen}
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mode_t *mode_r, gid_t *gid_r,
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen const char **gid_origin_r)
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mode_t dir_mode;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen *mode_r = list->file_create_mode;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen *gid_r = list->file_create_gid;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen *gid_origin_r = list->file_create_gid_origin;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return;
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen }
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen gid_origin_r);
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen}
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen const char *name,
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen mode_t *mode_r, gid_t *gid_r,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **gid_origin_r)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mode_t file_mode;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
306cfd77100131c08b243de10f6d40500f4c27c6Timo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen *mode_r = list->dir_create_mode;
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen *gid_r = list->file_create_gid;
438f12d7a776da695019114884b48188d94613efTimo Sirainen *gid_origin_r = list->file_create_gid_origin;
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
af9edddbb704a640055898846add4e386e83fe43Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen mailbox_list_get_permissions_full(list, name, &file_mode,
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen mode_r, gid_r, gid_origin_r);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen}
6469cf211a57433335641725dc236ebb2b9fdd3bTimo Sirainen
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainenbool mailbox_list_is_valid_pattern(struct mailbox_list *list,
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen const char *pattern)
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen{
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen bool ret;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen T_BEGIN {
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen ret = list->v.is_valid_pattern(list, pattern);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenbool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *name)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*name == '\0' && *list->ns->prefix != '\0') {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* an ugly way to get to mailbox root (e.g. Maildir/ when
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen it's not the INBOX) */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen T_BEGIN {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = list->v.is_valid_existing_name(list, name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainenbool mailbox_list_is_valid_create_name(struct mailbox_list *list,
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen const char *name)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *p;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* safer to just disallow all control characters */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen for (p = name; *p != '\0'; p++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*p < ' ')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen T_BEGIN {
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen string_t *str = t_str_new(256);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen 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)
{
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)
{
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);
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", 1024);
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)
{
const char *path, *fname, *rootdir;
struct stat st;
unsigned int len;
rootdir = mailbox_list_get_path(list, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
if (path == NULL) {
/* shouldn't happen with anything except shared mailboxes */
return 0;
}
len = strlen(rootdir);
if (strncmp(path, rootdir, len) == 0 && path[len] == '/') {
fname = strrchr(path, '/');
if (fname == NULL) {
fname = path;
path = "/";
} else {
path = t_strdup_until(path, fname);
fname++;
}
} else {
/* a) looking up INBOX that's elsewhere
b) looking up the root dir itself (as INBOX or "") */
fname = "";
}
return list->v.get_mailbox_flags(list, path, fname,
MAILBOX_LIST_FILE_TYPE_UNKNOWN,
&st, flags_r);
}
static bool mailbox_list_init_changelog(struct mailbox_list *list)
{
const char *path;
mode_t mode;
gid_t gid;
const char *gid_origin;
if (list->changelog != NULL)
return TRUE;
/* don't do this in mailbox_list_create(), because _get_path() might be
overridden by storage (mbox). */
path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
if (path == NULL)
return FALSE;
path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
list->changelog = mailbox_log_alloc(path);
mailbox_list_get_permissions(list, NULL, &mode, &gid, &gid_origin);
mailbox_log_set_permissions(list->changelog, mode, gid, gid_origin);
return TRUE;
}
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;
time_t stamp;
if (!mailbox_list_init_changelog(list) ||
mail_guid_128_is_empty(mailbox_guid))
return;
stamp = list->changelog_timestamp != (time_t)-1 ?
list->changelog_timestamp : ioloop_time;
memset(&rec, 0, sizeof(rec));
rec.type = type;
memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
mailbox_log_record_set_timestamp(&rec, stamp);
(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];
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. */
mailbox_name_get_sha128(name, guid);
mailbox_list_add_change(list, set ? MAILBOX_LOG_RECORD_SUBSCRIBE :
MAILBOX_LOG_RECORD_UNSUBSCRIBE, guid);
return 0;
}
int mailbox_list_delete_dir(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;
}
return list->v.delete_dir(list, name);
}
void mailbox_name_get_sha128(const char *name, uint8_t guid[MAIL_GUID_128_SIZE])
{
unsigned char sha[SHA1_RESULTLEN];
sha1_get_digest(name, strlen(name), sha);
memcpy(guid, sha, I_MIN(MAIL_GUID_128_SIZE, sizeof(sha)));
}
struct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list)
{
return !mailbox_list_init_changelog(list) ? NULL : list->changelog;
}
void mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
time_t stamp)
{
list->changelog_timestamp = stamp;
}
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;
}
static bool
mailbox_list_try_get_home_path(struct mailbox_list *list, const char **name)
{
if ((*name)[1] == '/') {
/* ~/dir - use the configured home directory */
if (mail_user_try_home_expand(list->ns->user, name) < 0)
return FALSE;
} else {
/* ~otheruser/dir - assume we're using system users */
if (home_try_expand(name) < 0)
return FALSE;
}
return TRUE;
}
bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
const char **name)
{
const char *root_dir, *path, *mailbox_name;
unsigned int len;
if (!list->mail_set->mail_full_filesystem_access)
return FALSE;
if (**name == '~') {
/* try to expand home directory */
if (!mailbox_list_try_get_home_path(list, name)) {
/* fallback to using actual "~name" mailbox */
return FALSE;
}
} else {
if (**name != '/')
return FALSE;
}
/* okay, we have an absolute path now. but check first if it points to
same directory as one of our regular mailboxes. */
root_dir = mailbox_list_get_path(list, NULL,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
len = strlen(root_dir);
if (strncmp(root_dir, *name, len) == 0 && (*name)[len] == '/') {
mailbox_name = *name + len + 1;
path = mailbox_list_get_path(list, mailbox_name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(path, *name) == 0) {
/* yeah, we can replace the full path with mailbox
name. this way we can use indexes. */
*name = mailbox_name;
return FALSE;
}
}
return TRUE;
}
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;
}