mailbox-list.c revision aaa340328f0c43b3ebdedd7bded70521d3f7a167
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "lib.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "array.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "ioloop.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "home-expand.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "unlink-directory.h"
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#include "imap-match.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "mailbox-tree.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "mailbox-list-private.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include <time.h>
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include <unistd.h>
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen#include <dirent.h>
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include <sys/stat.h>
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen then start renaming them to larger names from end to beginning, which
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen eventually would start causing the failures when trying to use too
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen long mailbox names. */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#define MAILBOX_MAX_HIERARCHY_LEVELS 20
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen/* Message to show to users when critical error occurs */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#define CRITICAL_MSG \
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen "Internal error occurred. Refer to server log for more information."
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid (*hook_mailbox_list_created)(struct mailbox_list *list);
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid mailbox_lists_init(void)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_array_init(&mailbox_list_drivers, 4);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid mailbox_lists_deinit(void)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen array_free(&mailbox_list_drivers);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const struct mailbox_list *const *drivers;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen unsigned int i, count;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen for (i = 0; i < count; i++) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *idx_r = i;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return TRUE;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return FALSE;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen unsigned int idx;
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list->name);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen{
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen unsigned int idx;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list->name);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen array_delete(&mailbox_list_drivers, idx, 1);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenint mailbox_list_alloc(const char *driver, struct mailbox_list **list_r,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char **error_r)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const struct mailbox_list *const *class_p;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mailbox_list *list;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen unsigned int idx;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *error_r = t_strdup_printf("Unknown mailbox list driver: %s",
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen driver);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list = *list_r = (*class_p)->v.alloc();
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic const char *fix_path(const char *path)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t len = strlen(path);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (len > 1 && path[len-1] == '/')
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen path = t_strndup(path, len-1);
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen return home_expand(path);
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen}
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainenint mailbox_list_settings_parse(const char *data,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mailbox_list_settings *set,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char **layout, const char **alt_dir_r,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char **error_r)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char *const *tmp, *key, *value;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_assert(*data != '\0');
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *error_r = NULL;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (alt_dir_r != NULL)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *alt_dir_r = NULL;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* <root dir> */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen tmp = t_strsplit(data, ":");
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen set->root_dir = fix_path(*tmp);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen tmp++;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen for (; *tmp != NULL; tmp++) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen value = strchr(*tmp, '=');
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (value == NULL) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen key = *tmp;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen value = "";
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen } else {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen key = t_strdup_until(*tmp, value);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen value++;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (strcmp(key, "INBOX") == 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen set->inbox_path = fix_path(value);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen else if (strcmp(key, "INDEX") == 0)
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen set->index_dir = fix_path(value);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen else if (strcmp(key, "CONTROL") == 0)
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen set->control_dir = fix_path(value);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen else if (strcmp(key, "ALT") == 0 && alt_dir_r != NULL)
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen *alt_dir_r = fix_path(value);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen else if (strcmp(key, "LAYOUT") == 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *layout = value;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen else if (strcmp(key, "SUBSCRIPTIONS") == 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen set->subscription_fname = fix_path(value);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen else if (strcmp(key, "DIRNAME") == 0)
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen set->maildir_name = value;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen else {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return -1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen set->index_dir = "";
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return 0;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenvoid mailbox_list_init(struct mailbox_list *list, struct mail_namespace *ns,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const struct mailbox_list_settings *set,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen enum mailbox_list_flags flags)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0');
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_assert(set->subscription_fname == NULL ||
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *set->subscription_fname != '\0');
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->ns = ns;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->flags = flags;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->file_create_mode = (mode_t)-1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->file_create_gid = (gid_t)-1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* copy settings */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->set.index_dir = set->index_dir == NULL ||
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen p_strdup(list->pool, set->index_dir);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen p_strdup(list->pool, set->control_dir);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->set.subscription_fname =
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen p_strdup(list->pool, set->subscription_fname);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen list->set.maildir_name = p_strdup(list->pool, set->maildir_name);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->set.mail_storage_flags = set->mail_storage_flags;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->set.lock_method = set->lock_method;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if ((flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen list->name, list->set.root_dir,
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen list->set.control_dir == NULL ?
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen "" : list->set.control_dir,
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen list->set.inbox_path == NULL ?
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen "" : list->set.inbox_path);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen if (hook_mailbox_list_created != NULL)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen hook_mailbox_list_created(list);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen list->set.mail_storage_flags = NULL;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen list->set.lock_method = NULL;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen}
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainenvoid mailbox_list_deinit(struct mailbox_list *list)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen{
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen i_free_and_null(list->error_string);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen list->v.deinit(list);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen}
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen{
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen return list->name;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen}
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen{
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen return list->hierarchy_sep;
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen}
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen{
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen return list->flags;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenstruct mail_namespace *
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen return list->ns;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen mode_t *mode_r, gid_t *gid_r)
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen const char *path;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen struct stat st;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen if (list->file_create_mode != (mode_t)-1) {
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen *mode_r = list->file_create_mode;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen *gid_r = list->file_create_gid;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen return;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (stat(path, &st) < 0) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (!ENOTFOUND(errno)) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen path);
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen } else if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
153ed0fbca1f5f944b70937dfd71911db172ca97Timo Sirainen i_info("Namespace %s: Permission lookup failed from %s",
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list->ns->prefix, path);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* return safe defaults */
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen *mode_r = 0600;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *gid_r = (gid_t)-1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen list->file_create_mode = st.st_mode & 0666;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen /* directory's GID is used automatically for new files */
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen list->file_create_gid = (gid_t)-1;
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen } else if ((st.st_mode & 0060) == 0) {
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen /* group doesn't have any permissions, so don't bother
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen changing it */
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen list->file_create_gid = (gid_t)-1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen } else if (getegid() == st.st_gid) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* using our own gid, no need to change it */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list->file_create_gid = (gid_t)-1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen } else {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list->file_create_gid = st.st_gid;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_info("Namespace %s: Using permissions from %s: "
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen "mode=0%o gid=%ld", list->ns->prefix, path,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen (int)list->file_create_mode,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen list->file_create_gid == (gid_t)-1 ? -1L :
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen (long)list->file_create_gid);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen *mode_r = list->file_create_mode;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen *gid_r = list->file_create_gid;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen mode_t *mode_r, gid_t *gid_r)
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen mode_t mode;
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen mailbox_list_get_permissions(list, &mode, gid_r);
d28179fd78550a58be44dcb1e3e830ab7d33172dTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen /* add the execute bit if either read or write bit is set */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if ((mode & 0600) != 0) mode |= 0100;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if ((mode & 0060) != 0) mode |= 0010;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if ((mode & 0006) != 0) mode |= 0001;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
b3f4c31f1533e25380f49f77d5bb1251bf43db2aTimo Sirainen *mode_r = mode;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenbool mailbox_list_is_valid_pattern(struct mailbox_list *list,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const char *pattern)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return list->v.is_valid_pattern(list, pattern);
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen}
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainenbool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const char *name)
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen{
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen return list->v.is_valid_existing_name(list, name);
e44028b5df7045dd9e7f324175e73e3ff490cb5dTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainenbool mailbox_list_is_valid_create_name(struct mailbox_list *list,
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen const char *name)
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen return list->v.is_valid_create_name(list, name);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenconst char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen enum mailbox_list_path_type type)
c096257fbdaf4b9fcf8eb97aae94afdbb4e71ed4Timo Sirainen{
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen mailbox_list_clear_error(list);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return list->v.get_path(list, name, type);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenconst char *mailbox_list_get_temp_prefix(struct mailbox_list *list)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return list->v.get_temp_prefix(list, FALSE);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
const char *mailbox_list_get_global_temp_prefix(struct mailbox_list *list)
{
return list->v.get_temp_prefix(list, TRUE);
}
const char *mailbox_list_join_refpattern(struct mailbox_list *list,
const char *ref, const char *pattern)
{
if (list->v.join_refpattern != NULL)
return list->v.join_refpattern(list, ref, pattern);
/* the default implementation: */
if (*ref != '\0') {
/* merge reference and pattern */
pattern = t_strconcat(ref, pattern, NULL);
}
return pattern;
}
int mailbox_list_get_mailbox_name_status(struct mailbox_list *list,
const char *name,
enum mailbox_name_status *status)
{
mailbox_list_clear_error(list);
if (!mailbox_list_is_valid_existing_name(list, name)) {
*status = MAILBOX_NAME_INVALID;
return 0;
}
return list->v.get_mailbox_name_status(list, name, status);
}
struct mailbox_list_iterate_context *
mailbox_list_iter_init(struct mailbox_list *list, const char *pattern,
enum mailbox_list_iter_flags flags)
{
const char *patterns[2];
patterns[0] = pattern;
patterns[1] = NULL;
return mailbox_list_iter_init_multiple(list, patterns, flags);
}
struct mailbox_list_iterate_context *
mailbox_list_iter_init_multiple(struct mailbox_list *list,
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
i_assert(*patterns != NULL);
mailbox_list_clear_error(list);
return list->v.iter_init(list, patterns, flags);
}
const struct mailbox_info *
mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
{
return ctx->list->v.iter_next(ctx);
}
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_set_subscribed(struct mailbox_list *list,
const char *name, bool set)
{
mailbox_list_clear_error(list);
return list->v.set_subscribed(list, name, set);
}
int mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
if (!mailbox_list_is_valid_existing_name(list, name)) {
mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
if (strcmp(name, "INBOX") == 0 &&
(list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
}
return list->v.delete_mailbox(list, name);
}
int mailbox_list_rename_mailbox(struct mailbox_list *list,
const char *oldname, const char *newname)
{
if (!mailbox_list_is_valid_existing_name(list, oldname) ||
!mailbox_list_is_valid_create_name(list, newname)) {
mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
}
return list->v.rename_mailbox(list, oldname, newname);
}
static int mailbox_list_try_delete(struct mailbox_list *list, const char *dir)
{
if (unlink_directory(dir, TRUE) == 0 || errno == ENOENT)
return 0;
if (errno == ENOTEMPTY) {
/* We're most likely using NFS and we can't delete
.nfs* files. */
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
"Mailbox is still open in another session, "
"can't delete it.");
} else {
mailbox_list_set_critical(list,
"unlink_directory(%s) failed: %m", dir);
}
return -1;
}
int mailbox_list_delete_index_control(struct mailbox_list *list,
const char *name)
{
const char *path, *index_dir, *dir;
path = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
/* delete the index directory first, so that if we crash we don't
leave indexes for deleted mailboxes lying around */
index_dir = mailbox_list_get_path(list, name,
MAILBOX_LIST_PATH_TYPE_INDEX);
if (*index_dir != '\0' && strcmp(index_dir, path) != 0) {
if (mailbox_list_try_delete(list, index_dir) < 0)
return -1;
}
/* control directory next */
dir = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_CONTROL);
if (*dir != '\0' && strcmp(dir, path) != 0 &&
strcmp(dir, index_dir) != 0) {
if (mailbox_list_try_delete(list, index_dir) < 0)
return -1;
}
return 0;
}
static void node_fix_parents(struct mailbox_node *node)
{
/* If we happened to create any of the parents, we need to mark them
nonexistent. */
node = node->parent;
for (; node != NULL; node = node->parent) {
if ((node->flags & MAILBOX_MATCHED) == 0)
node->flags |= MAILBOX_NONEXISTENT;
}
}
static void
mailbox_list_iter_update_real(struct mailbox_list_iter_update_context *ctx,
const char *name)
{
struct mail_namespace *ns = ctx->iter_ctx->list->ns;
struct mailbox_node *node;
enum mailbox_info_flags create_flags = 0, always_flags;
enum imap_match_result match;
const char *p;
bool created, add_matched;
if (ctx->update_only ||
(ctx->iter_ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0)
create_flags = MAILBOX_NONEXISTENT | MAILBOX_NOCHILDREN;
always_flags = ctx->leaf_flags;
add_matched = TRUE;
for (;;) {
created = FALSE;
match = imap_match(ctx->glob, name);
if (match == IMAP_MATCH_YES) {
node = ctx->update_only ?
mailbox_tree_lookup(ctx->tree_ctx, name) :
mailbox_tree_get(ctx->tree_ctx, name, &created);
if (created) {
node->flags = create_flags;
if (create_flags != 0)
node_fix_parents(node);
}
if (node != NULL) {
if (!ctx->update_only && add_matched)
node->flags |= MAILBOX_MATCHED;
node->flags |= always_flags;
}
/* We don't want to show the parent mailboxes unless
something else matches them, but if they are matched
we want to show them having child subscriptions */
add_matched = FALSE;
} else {
if ((match & IMAP_MATCH_PARENT) == 0)
break;
/* We've a (possibly) non-subscribed parent mailbox
which has a subscribed child mailbox. Make sure we
return the parent mailbox. */
}
if (!ctx->match_parents)
break;
/* see if parent matches */
p = strrchr(name, ns->sep);
if (p == NULL)
break;
name = t_strdup_until(name, p);
create_flags &= ~MAILBOX_NOCHILDREN;
always_flags = MAILBOX_CHILDREN | ctx->parent_flags;
}
}
void mailbox_list_iter_update(struct mailbox_list_iter_update_context *ctx,
const char *name)
{
T_BEGIN {
mailbox_list_iter_update_real(ctx, name);
} T_END;
}
bool mailbox_list_name_is_too_large(const char *name, char sep)
{
unsigned int levels = 1, level_len = 0;
for (; *name != '\0'; name++) {
if (*name == sep) {
if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
return TRUE;
levels++;
level_len = 0;
} else {
level_len++;
}
}
if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
return TRUE;
if (levels > MAILBOX_MAX_HIERARCHY_LEVELS)
return TRUE;
return FALSE;
}
enum mailbox_list_file_type
mailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
{
enum mailbox_list_file_type type;
#ifdef HAVE_DIRENT_D_TYPE
switch (d->d_type) {
case DT_UNKNOWN:
type = MAILBOX_LIST_FILE_TYPE_UNKNOWN;
break;
case DT_REG:
type = MAILBOX_LIST_FILE_TYPE_FILE;
break;
case DT_DIR:
type = MAILBOX_LIST_FILE_TYPE_DIR;
break;
case DT_LNK:
type = MAILBOX_LIST_FILE_TYPE_SYMLINK;
break;
default:
type = MAILBOX_LIST_FILE_TYPE_OTHER;
break;
}
#else
type = MAILBOX_LIST_FILE_TYPE_UNKNOWN;
#endif
return type;
}
const char *mailbox_list_get_last_error(struct mailbox_list *list,
enum mail_error *error_r)
{
*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), CRITICAL_MSG_STAMP, tm) > 0 ?
i_strdup(str) : i_strdup(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;
}