mailbox-list.c revision e22efc90e109ade2936eea0b062a99480310fd41
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "lib.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "array.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "ioloop.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mkdir-parents.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "str.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "sha1.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "home-expand.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "close-keep-errno.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "eacces-error.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "read-full.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "write-full.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "safe-mkstemp.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "unlink-directory.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-match.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-utf7.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-log.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-tree.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mail-storage-private.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "mailbox-list-private.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <time.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <unistd.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <dirent.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include <sys/stat.h>
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen then start renaming them to larger names from end to beginning, which
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen eventually would start causing the failures when trying to use too
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen long mailbox names. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define MAILBOX_MAX_HIERARCHY_LEVELS 20
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct ns_list_iterate_context {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list_iterate_context ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list_iterate_context *backend_ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_namespace *namespaces;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen pool_t pool;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **patterns;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen};
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_lists_init(void)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_array_init(&mailbox_list_drivers, 4);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_lists_deinit(void)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_free(&mailbox_list_drivers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mailbox_list *const *drivers;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (i = 0; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *idx_r = i;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->name);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append(&mailbox_list_drivers, &list, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->name);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_delete(&mailbox_list_drivers, idx, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenconst struct mailbox_list *
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_find_class(const char *driver)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mailbox_list *const *class_p;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mailbox_list_driver_find(driver, &idx))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return *class_p;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mailbox_list_settings *set,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen enum mailbox_list_flags flags, const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct mailbox_list *const *class_p;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list *list;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(ns->list == NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(set->subscription_fname == NULL ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *set->subscription_fname != '\0');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "Unknown driver name";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen set->maildir_name != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "maildir_name not supported by this driver";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen set->alt_dir != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "alt_dir not supported by this driver";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list = (*class_p)->v.alloc();
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->ns = ns;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->mail_set = ns->mail_set;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->flags = flags;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->file_create_mode = (mode_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->dir_create_mode = (mode_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->file_create_gid = (gid_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->changelog_timestamp = (time_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* copy settings */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (set->root_dir != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.index_dir = set->index_dir == NULL ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->index_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.control_dir = set->control_dir == NULL ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->control_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.subscription_fname =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->subscription_fname);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->maildir_name);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.mailbox_dir_name =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->mailbox_dir_name);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.mailbox_dir_name = "";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.mailbox_dir_name =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->mailbox_dir_name);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.mailbox_dir_name =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ns->mail_set->mail_debug) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.control_dir == NULL ?
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "" : list->set.control_dir,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.inbox_path == NULL ?
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "" : list->set.inbox_path);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_namespace_finish_list_init(ns, list);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen hook_mailbox_list_created(list);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **path_r, const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen size_t len = strlen(path);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (len > 1 && path[len-1] == '/')
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen path = t_strndup(path, len-1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (path[0] == '~' && path[1] != '/') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* ~otheruser/dir */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (home_try_expand(&path) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strconcat(
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "No home directory for system user. "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Can't expand ", t_strcut(path, '/'),
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen " for ", NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "Home directory not set for user. "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Can't expand ~/ for ";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *path_r = path;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic const char *split_next_arg(const char *const **_args)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *args = *_args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *str = args[0];
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen args++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while (*args != NULL && **args == '\0') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen args++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (*args == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* string ends with ":", just ignore it. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen break;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str = t_strconcat(str, ":", *args, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen args++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *_args = args;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_list_settings_parse(const char *data,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list_settings *set,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_namespace *ns, const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (*data == '\0')
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* <root dir> */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen tmp = t_strsplit(data, ":");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str = split_next_arg(&tmp);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen while (*tmp != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str = split_next_arg(&tmp);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen value = strchr(str, '=');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (value == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen key = str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen value = "";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen key = t_strdup_until(str, value);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen value++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strcmp(key, "INBOX") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->inbox_path;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "INDEX") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->index_dir;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "CONTROL") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->control_dir;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "ALT") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->alt_dir;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "LAYOUT") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->layout;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "SUBSCRIPTIONS") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->subscription_fname;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "DIRNAME") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->maildir_name;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (strcmp(key, "MAILBOXDIR") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dest = &set->mailbox_dir_name;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (fix_path(ns, value, dest, &error) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen set->index_dir = "";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list *list = *_list;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *_list = NULL;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_free_and_null(list->error_string);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->changelog != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_log_free(&list->changelog);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->v.deinit(list);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return list->name;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return list->hierarchy_sep;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return list->flags;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct mail_namespace *
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return list->ns;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic mode_t get_dir_mode(mode_t mode)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* add the execute bit if either read or write bit is set */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((mode & 0600) != 0) mode |= 0100;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((mode & 0060) != 0) mode |= 0010;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((mode & 0006) != 0) mode |= 0001;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return mode;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct mail_user *
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return list->ns->user;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage **storage_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if ((*list)->v.get_storage != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *storage_r = (*list)->ns->storage;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return 0;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_storage **storage)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *storage = list->ns->storage;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mode_t *file_mode_r, mode_t *dir_mode_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen gid_t *gid_r, const char **gid_origin_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *path;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct stat st;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* use safe defaults */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *file_mode_r = 0600;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *dir_mode_r = 0700;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_r = (gid_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_origin_r = "defaults";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (path == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* no filesystem support in storage */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (stat(path, &st) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!ENOTFOUND(errno)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen path);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (list->mail_set->mail_debug) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_debug("Namespace %s: Permission lookup failed from %s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->ns->prefix, path);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (name != NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* return defaults */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_list_get_permissions_full(list, NULL,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen file_mode_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen dir_mode_r, gid_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen gid_origin_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *file_mode_r = st.st_mode & 0666;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *dir_mode_r = st.st_mode & 0777;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_origin_r = path;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!S_ISDIR(st.st_mode)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we're getting permissions from a file.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen apply +x modes as necessary. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *dir_mode_r = get_dir_mode(*dir_mode_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* directory's GID is used automatically for new
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen files */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_r = (gid_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* group has same permissions as world, so don't bother
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen changing it */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_r = (gid_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (getegid() == st.st_gid) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* using our own gid, no need to change it */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_r = (gid_t)-1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_r = st.st_gid;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (name == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->file_create_mode = *file_mode_r;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->dir_create_mode = *dir_mode_r;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->file_create_gid = *gid_r;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->file_create_gid_origin =
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, *gid_origin_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->mail_set->mail_debug && name == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_debug("Namespace %s: Using permissions from %s: "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "mode=0%o gid=%ld", list->ns->prefix,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen path != NULL ? path : "",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (int)list->dir_create_mode,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->file_create_gid == (gid_t)-1 ? -1L :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen (long)list->file_create_gid);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mode_t *mode_r, gid_t *gid_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **gid_origin_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mode_t dir_mode;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *mode_r = list->file_create_mode;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_r = list->file_create_gid;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *gid_origin_r = list->file_create_gid_origin;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen gid_origin_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mode_t *mode_r, gid_t *gid_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **gid_origin_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mode_t file_mode;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
*mode_r = list->dir_create_mode;
*gid_r = list->file_create_gid;
*gid_origin_r = list->file_create_gid_origin;
return;
}
mailbox_list_get_permissions_full(list, name, &file_mode,
mode_r, gid_r, gid_origin_r);
}
bool mailbox_list_is_valid_pattern(struct mailbox_list *list,
const char *pattern)
{
bool ret;
T_BEGIN {
ret = list->v.is_valid_pattern(list, pattern);
} T_END;
return ret;
}
bool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
const char *name)
{
bool ret;
if (*name == '\0' && *list->ns->prefix != '\0') {
/* an ugly way to get to mailbox root (e.g. Maildir/ when
it's not the INBOX) */
return TRUE;
}
T_BEGIN {
ret = list->v.is_valid_existing_name(list, name);
} T_END;
return ret;
}
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)
{
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, *inbox;
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 = "";
}
if (*fname == '\0' && *name == '\0' &&
(list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
/* if INBOX is in e.g. ~/Maildir, it shouldn't be possible to
access it also via namespace prefix. */
inbox = mailbox_list_get_path(list, "INBOX",
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if (strcmp(inbox, path) == 0) {
*flags_r |= MAILBOX_NONEXISTENT;
return 0;
}
}
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;
}