summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/mail-storage-settings.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-storage/mail-storage-settings.c809
1 files changed, 809 insertions, 0 deletions
diff --git a/src/lib-storage/mail-storage-settings.c b/src/lib-storage/mail-storage-settings.c
new file mode 100644
index 0000000..9421956
--- /dev/null
+++ b/src/lib-storage/mail-storage-settings.c
@@ -0,0 +1,809 @@
+/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hash-format.h"
+#include "var-expand.h"
+#include "unichar.h"
+#include "hostpid.h"
+#include "settings-parser.h"
+#include "message-address.h"
+#include "message-header-parser.h"
+#include "smtp-address.h"
+#include "mail-index.h"
+#include "mail-user.h"
+#include "mail-namespace.h"
+#include "mail-storage-private.h"
+#include "mail-storage-settings.h"
+#include "iostream-ssl.h"
+
+#include <stddef.h>
+
+static bool mail_storage_settings_check(void *_set, pool_t pool, const char **error_r);
+static bool namespace_settings_check(void *_set, pool_t pool, const char **error_r);
+static bool mailbox_settings_check(void *_set, pool_t pool, const char **error_r);
+static bool mail_user_settings_check(void *_set, pool_t pool, const char **error_r);
+static bool mail_user_settings_expand_check(void *_set, pool_t pool ATTR_UNUSED, const char **error_r);
+
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type(#name, name, struct mail_storage_settings)
+
+static const struct setting_define mail_storage_setting_defines[] = {
+ DEF(STR_VARS, mail_location),
+ { .type = SET_ALIAS, .key = "mail" },
+ DEF(STR_VARS, mail_attachment_fs),
+ DEF(STR_VARS, mail_attachment_dir),
+ DEF(STR, mail_attachment_hash),
+ DEF(SIZE, mail_attachment_min_size),
+ DEF(STR, mail_attachment_detection_options),
+ DEF(STR_VARS, mail_attribute_dict),
+ DEF(UINT, mail_prefetch_count),
+ DEF(STR, mail_cache_fields),
+ DEF(STR, mail_always_cache_fields),
+ DEF(STR, mail_never_cache_fields),
+ DEF(STR, mail_server_comment),
+ DEF(STR, mail_server_admin),
+ DEF(TIME_HIDDEN, mail_cache_unaccessed_field_drop),
+ DEF(SIZE_HIDDEN, mail_cache_record_max_size),
+ DEF(SIZE_HIDDEN, mail_cache_max_size),
+ DEF(UINT_HIDDEN, mail_cache_min_mail_count),
+ DEF(SIZE_HIDDEN, mail_cache_purge_min_size),
+ DEF(UINT_HIDDEN, mail_cache_purge_delete_percentage),
+ DEF(UINT_HIDDEN, mail_cache_purge_continued_percentage),
+ DEF(UINT_HIDDEN, mail_cache_purge_header_continue_count),
+ DEF(SIZE_HIDDEN, mail_index_rewrite_min_log_bytes),
+ DEF(SIZE_HIDDEN, mail_index_rewrite_max_log_bytes),
+ DEF(SIZE_HIDDEN, mail_index_log_rotate_min_size),
+ DEF(SIZE_HIDDEN, mail_index_log_rotate_max_size),
+ DEF(TIME_HIDDEN, mail_index_log_rotate_min_age),
+ DEF(TIME_HIDDEN, mail_index_log2_max_age),
+ DEF(TIME, mailbox_idle_check_interval),
+ DEF(UINT, mail_max_keyword_length),
+ DEF(TIME, mail_max_lock_timeout),
+ DEF(TIME, mail_temp_scan_interval),
+ DEF(UINT, mail_vsize_bg_after_count),
+ DEF(UINT, mail_sort_max_read_count),
+ DEF(BOOL, mail_save_crlf),
+ DEF(ENUM, mail_fsync),
+ DEF(BOOL, mmap_disable),
+ DEF(BOOL, dotlock_use_excl),
+ DEF(BOOL, mail_nfs_storage),
+ DEF(BOOL, mail_nfs_index),
+ DEF(BOOL, mailbox_list_index),
+ DEF(BOOL, mailbox_list_index_very_dirty_syncs),
+ DEF(BOOL, mailbox_list_index_include_inbox),
+ DEF(BOOL, mail_debug),
+ DEF(BOOL, mail_full_filesystem_access),
+ DEF(BOOL, maildir_stat_dirs),
+ DEF(BOOL, mail_shared_explicit_inbox),
+ DEF(ENUM, lock_method),
+ DEF(STR, pop3_uidl_format),
+
+ DEF(STR, hostname),
+ DEF(STR, recipient_delimiter),
+
+ SETTING_DEFINE_LIST_END
+};
+
+const struct mail_storage_settings mail_storage_default_settings = {
+ .mail_location = "",
+ .mail_attachment_fs = "sis posix",
+ .mail_attachment_dir = "",
+ .mail_attachment_hash = "%{sha1}",
+ .mail_attachment_min_size = 1024*128,
+ .mail_attachment_detection_options = "",
+ .mail_attribute_dict = "",
+ .mail_prefetch_count = 0,
+ .mail_cache_fields = "flags",
+ .mail_always_cache_fields = "",
+ .mail_never_cache_fields = "imap.envelope",
+ .mail_server_comment = "",
+ .mail_server_admin = "",
+ .mail_cache_min_mail_count = 0,
+ .mail_cache_unaccessed_field_drop = 60*60*24*30,
+ .mail_cache_record_max_size = 64 * 1024,
+ .mail_cache_max_size = 1024 * 1024 * 1024,
+ .mail_cache_purge_min_size = 32 * 1024,
+ .mail_cache_purge_delete_percentage = 20,
+ .mail_cache_purge_continued_percentage = 200,
+ .mail_cache_purge_header_continue_count = 4,
+ .mail_index_rewrite_min_log_bytes = 8 * 1024,
+ .mail_index_rewrite_max_log_bytes = 128 * 1024,
+ .mail_index_log_rotate_min_size = 32 * 1024,
+ .mail_index_log_rotate_max_size = 1024 * 1024,
+ .mail_index_log_rotate_min_age = 5 * 60,
+ .mail_index_log2_max_age = 3600 * 24 * 2,
+ .mailbox_idle_check_interval = 30,
+ .mail_max_keyword_length = 50,
+ .mail_max_lock_timeout = 0,
+ .mail_temp_scan_interval = 7*24*60*60,
+ .mail_vsize_bg_after_count = 0,
+ .mail_sort_max_read_count = 0,
+ .mail_save_crlf = FALSE,
+ .mail_fsync = "optimized:never:always",
+ .mmap_disable = FALSE,
+ .dotlock_use_excl = TRUE,
+ .mail_nfs_storage = FALSE,
+ .mail_nfs_index = FALSE,
+ .mailbox_list_index = TRUE,
+ .mailbox_list_index_very_dirty_syncs = FALSE,
+ .mailbox_list_index_include_inbox = FALSE,
+ .mail_debug = FALSE,
+ .mail_full_filesystem_access = FALSE,
+ .maildir_stat_dirs = FALSE,
+ .mail_shared_explicit_inbox = FALSE,
+ .lock_method = "fcntl:flock:dotlock",
+ .pop3_uidl_format = "%08Xu%08Xv",
+
+ .hostname = "",
+ .recipient_delimiter = "+",
+};
+
+const struct setting_parser_info mail_storage_setting_parser_info = {
+ .module_name = "mail",
+ .defines = mail_storage_setting_defines,
+ .defaults = &mail_storage_default_settings,
+
+ .type_offset = SIZE_MAX,
+ .struct_size = sizeof(struct mail_storage_settings),
+
+ .parent_offset = SIZE_MAX,
+ .parent = &mail_user_setting_parser_info,
+
+ .check_func = mail_storage_settings_check,
+};
+
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type(#name, name, struct mailbox_settings)
+
+static const struct setting_define mailbox_setting_defines[] = {
+ DEF(STR, name),
+ { .type = SET_ENUM, .key = "auto",
+ .offset = offsetof(struct mailbox_settings, autocreate) } ,
+ DEF(STR, special_use),
+ DEF(STR, driver),
+ DEF(STR, comment),
+ DEF(TIME, autoexpunge),
+ DEF(UINT, autoexpunge_max_mails),
+
+ SETTING_DEFINE_LIST_END
+};
+
+const struct mailbox_settings mailbox_default_settings = {
+ .name = "",
+ .autocreate = MAILBOX_SET_AUTO_NO":"
+ MAILBOX_SET_AUTO_CREATE":"
+ MAILBOX_SET_AUTO_SUBSCRIBE,
+ .special_use = "",
+ .driver = "",
+ .comment = "",
+ .autoexpunge = 0,
+ .autoexpunge_max_mails = 0
+};
+
+const struct setting_parser_info mailbox_setting_parser_info = {
+ .defines = mailbox_setting_defines,
+ .defaults = &mailbox_default_settings,
+
+ .type_offset = offsetof(struct mailbox_settings, name),
+ .struct_size = sizeof(struct mailbox_settings),
+
+ .parent_offset = SIZE_MAX,
+ .parent = &mail_user_setting_parser_info,
+
+ .check_func = mailbox_settings_check
+};
+
+#undef DEF
+#undef DEFLIST_UNIQUE
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type(#name, name, struct mail_namespace_settings)
+#define DEFLIST_UNIQUE(field, name, defines) \
+ { .type = SET_DEFLIST_UNIQUE, .key = name, \
+ .offset = offsetof(struct mail_namespace_settings, field), \
+ .list_info = defines }
+
+static const struct setting_define mail_namespace_setting_defines[] = {
+ DEF(STR, name),
+ DEF(ENUM, type),
+ DEF(STR, separator),
+ DEF(STR_VARS, prefix),
+ DEF(STR_VARS, location),
+ { .type = SET_ALIAS, .key = "mail" },
+ { .type = SET_ALIAS, .key = "mail_location" },
+ DEF(STR_VARS, alias_for),
+
+ DEF(BOOL, inbox),
+ DEF(BOOL, hidden),
+ DEF(ENUM, list),
+ DEF(BOOL, subscriptions),
+ DEF(BOOL, ignore_on_failure),
+ DEF(BOOL, disabled),
+ DEF(UINT, order),
+
+ DEFLIST_UNIQUE(mailboxes, "mailbox", &mailbox_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
+};
+
+const struct mail_namespace_settings mail_namespace_default_settings = {
+ .name = "",
+ .type = "private:shared:public",
+ .separator = "",
+ .prefix = "",
+ .location = "",
+ .alias_for = NULL,
+
+ .inbox = FALSE,
+ .hidden = FALSE,
+ .list = "yes:no:children",
+ .subscriptions = TRUE,
+ .ignore_on_failure = FALSE,
+ .disabled = FALSE,
+ .order = 0,
+
+ .mailboxes = ARRAY_INIT
+};
+
+const struct setting_parser_info mail_namespace_setting_parser_info = {
+ .defines = mail_namespace_setting_defines,
+ .defaults = &mail_namespace_default_settings,
+
+ .type_offset = offsetof(struct mail_namespace_settings, name),
+ .struct_size = sizeof(struct mail_namespace_settings),
+
+ .parent_offset = offsetof(struct mail_namespace_settings, user_set),
+ .parent = &mail_user_setting_parser_info,
+
+ .check_func = namespace_settings_check
+};
+
+#undef DEF
+#undef DEFLIST_UNIQUE
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type(#name, name, struct mail_user_settings)
+#define DEFLIST_UNIQUE(field, name, defines) \
+ { .type = SET_DEFLIST_UNIQUE, .key = name, \
+ .offset = offsetof(struct mail_user_settings, field), \
+ .list_info = defines }
+
+static const struct setting_define mail_user_setting_defines[] = {
+ DEF(STR, base_dir),
+ DEF(STR, auth_socket_path),
+ DEF(STR_VARS, mail_temp_dir),
+
+ DEF(STR, mail_uid),
+ DEF(STR, mail_gid),
+ DEF(STR_VARS, mail_home),
+ DEF(STR_VARS, mail_chroot),
+ DEF(STR, mail_access_groups),
+ DEF(STR, mail_privileged_group),
+ DEF(STR, valid_chroot_dirs),
+
+ DEF(UINT, first_valid_uid),
+ DEF(UINT, last_valid_uid),
+ DEF(UINT, first_valid_gid),
+ DEF(UINT, last_valid_gid),
+
+ DEF(STR, mail_plugins),
+ DEF(STR, mail_plugin_dir),
+
+ DEF(STR, mail_log_prefix),
+
+ DEF(STR, hostname),
+ DEF(STR_VARS, postmaster_address),
+
+ DEFLIST_UNIQUE(namespaces, "namespace", &mail_namespace_setting_parser_info),
+ { .type = SET_STRLIST, .key = "plugin",
+ .offset = offsetof(struct mail_user_settings, plugin_envs) },
+
+ SETTING_DEFINE_LIST_END
+};
+
+static const struct mail_user_settings mail_user_default_settings = {
+ .base_dir = PKG_RUNDIR,
+ .auth_socket_path = "auth-userdb",
+ .mail_temp_dir = "/tmp",
+
+ .mail_uid = "",
+ .mail_gid = "",
+ .mail_home = "",
+ .mail_chroot = "",
+ .mail_access_groups = "",
+ .mail_privileged_group = "",
+ .valid_chroot_dirs = "",
+
+ .first_valid_uid = 500,
+ .last_valid_uid = 0,
+ .first_valid_gid = 1,
+ .last_valid_gid = 0,
+
+ .mail_plugins = "",
+ .mail_plugin_dir = MODULEDIR,
+
+ .mail_log_prefix = "%s(%u)<%{pid}><%{session}>: ",
+
+ .hostname = "",
+ .postmaster_address = "postmaster@%{if;%d;ne;;%d;%{hostname}}",
+
+ .namespaces = ARRAY_INIT,
+ .plugin_envs = ARRAY_INIT
+};
+
+const struct setting_parser_info mail_user_setting_parser_info = {
+ .module_name = "mail",
+ .defines = mail_user_setting_defines,
+ .defaults = &mail_user_default_settings,
+
+ .type_offset = SIZE_MAX,
+ .struct_size = sizeof(struct mail_user_settings),
+
+ .parent_offset = SIZE_MAX,
+
+ .check_func = mail_user_settings_check,
+#ifndef CONFIG_BINARY
+ .expand_check_func = mail_user_settings_expand_check,
+#endif
+};
+
+const void *
+mail_user_set_get_driver_settings(const struct setting_parser_info *info,
+ const struct mail_user_settings *set,
+ const char *driver)
+{
+ const void *dset;
+
+ dset = settings_find_dynamic(info, set, driver);
+ if (dset == NULL) {
+ i_panic("Default settings not found for storage driver %s",
+ driver);
+ }
+ return dset;
+}
+
+const struct mail_storage_settings *
+mail_user_set_get_storage_set(struct mail_user *user)
+{
+ return mail_user_set_get_driver_settings(user->set_info, user->set,
+ MAIL_STORAGE_SET_DRIVER_NAME);
+}
+
+const void *mail_namespace_get_driver_settings(struct mail_namespace *ns,
+ struct mail_storage *storage)
+{
+ return mail_user_set_get_driver_settings(storage->user->set_info,
+ ns->user_set, storage->name);
+}
+
+const struct dynamic_settings_parser *
+mail_storage_get_dynamic_parsers(pool_t pool)
+{
+ struct dynamic_settings_parser *parsers;
+ struct mail_storage *const *storages;
+ unsigned int i, j, count;
+
+ storages = array_get(&mail_storage_classes, &count);
+ parsers = p_new(pool, struct dynamic_settings_parser, 1 + count + 1);
+ parsers[0].name = MAIL_STORAGE_SET_DRIVER_NAME;
+ parsers[0].info = &mail_storage_setting_parser_info;
+
+ for (i = 0, j = 1; i < count; i++) {
+ if (storages[i]->v.get_setting_parser_info == NULL)
+ continue;
+
+ parsers[j].name = storages[i]->name;
+ parsers[j].info = storages[i]->v.get_setting_parser_info();
+ j++;
+ }
+ parsers[j].name = NULL;
+ return parsers;
+}
+
+static void
+fix_base_path(struct mail_user_settings *set, pool_t pool, const char **str)
+{
+ if (*str != NULL && **str != '\0' && **str != '/')
+ *str = p_strconcat(pool, set->base_dir, "/", *str, NULL);
+}
+
+/* <settings checks> */
+static bool mail_cache_fields_parse(const char *key, const char *value,
+ const char **error_r)
+{
+ const char *const *arr;
+
+ for (arr = t_strsplit_spaces(value, " ,"); *arr != NULL; arr++) {
+ const char *name = *arr;
+
+ if (strncasecmp(name, "hdr.", 4) == 0 &&
+ !message_header_name_is_valid(name+4)) {
+ *error_r = t_strdup_printf(
+ "Invalid %s: %s is not a valid header name",
+ key, name);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static bool mail_storage_settings_check(void *_set, pool_t pool,
+ const char **error_r)
+{
+ struct mail_storage_settings *set = _set;
+ struct hash_format *format;
+ const char *p, *error;
+ bool uidl_format_ok;
+ char c;
+
+ if (set->mailbox_idle_check_interval == 0) {
+ *error_r = "mailbox_idle_check_interval must not be 0";
+ return FALSE;
+ }
+
+ if (strcmp(set->mail_fsync, "optimized") == 0)
+ set->parsed_fsync_mode = FSYNC_MODE_OPTIMIZED;
+ else if (strcmp(set->mail_fsync, "never") == 0)
+ set->parsed_fsync_mode = FSYNC_MODE_NEVER;
+ else if (strcmp(set->mail_fsync, "always") == 0)
+ set->parsed_fsync_mode = FSYNC_MODE_ALWAYS;
+ else {
+ *error_r = t_strdup_printf("Unknown mail_fsync: %s",
+ set->mail_fsync);
+ return FALSE;
+ }
+
+ if (set->mail_nfs_index && !set->mmap_disable) {
+ *error_r = "mail_nfs_index=yes requires mmap_disable=yes";
+ return FALSE;
+ }
+ if (set->mail_nfs_index &&
+ set->parsed_fsync_mode != FSYNC_MODE_ALWAYS) {
+ *error_r = "mail_nfs_index=yes requires mail_fsync=always";
+ return FALSE;
+ }
+
+ if (!file_lock_method_parse(set->lock_method,
+ &set->parsed_lock_method)) {
+ *error_r = t_strdup_printf("Unknown lock_method: %s",
+ set->lock_method);
+ return FALSE;
+ }
+
+ if (set->mail_cache_max_size > 1024 * 1024 * 1024) {
+ *error_r = "mail_cache_max_size can't be over 1 GB";
+ return FALSE;
+ }
+ if (set->mail_cache_purge_delete_percentage > 100) {
+ *error_r = "mail_cache_purge_delete_percentage can't be over 100";
+ return FALSE;
+ }
+
+ uidl_format_ok = FALSE;
+ for (p = set->pop3_uidl_format; *p != '\0'; p++) {
+ if (p[0] != '%' || p[1] == '\0')
+ continue;
+
+ c = var_get_key(++p);
+ switch (c) {
+ case 'v':
+ case 'u':
+ case 'm':
+ case 'f':
+ case 'g':
+ uidl_format_ok = TRUE;
+ break;
+ case '%':
+ break;
+ default:
+ *error_r = t_strdup_printf(
+ "Unknown pop3_uidl_format variable: %%%c", c);
+ return FALSE;
+ }
+ }
+ if (!uidl_format_ok) {
+ *error_r = "pop3_uidl_format setting doesn't contain any "
+ "%% variables.";
+ return FALSE;
+ }
+
+ if (strchr(set->mail_attachment_hash, '/') != NULL) {
+ *error_r = "mail_attachment_hash setting "
+ "must not contain '/' characters";
+ return FALSE;
+ }
+ if (hash_format_init(set->mail_attachment_hash, &format, &error) < 0) {
+ *error_r = t_strconcat("Invalid mail_attachment_hash setting: ",
+ error, NULL);
+ return FALSE;
+ }
+ if (strchr(set->mail_attachment_hash, '-') != NULL) {
+ *error_r = "mail_attachment_hash setting "
+ "must not contain '-' characters";
+ return FALSE;
+ }
+ hash_format_deinit_free(&format);
+
+ // FIXME: check set->mail_server_admin syntax (RFC 5464, Section 6.2.2)
+
+#ifndef CONFIG_BINARY
+ if (*set->hostname == '\0')
+ set->hostname = p_strdup(pool, my_hostdomain());
+#endif
+
+ /* parse mail_attachment_indicator_options */
+ if (*set->mail_attachment_detection_options != '\0') {
+ ARRAY_TYPE(const_string) content_types;
+ p_array_init(&content_types, pool, 2);
+
+ const char *const *options =
+ t_strsplit_spaces(set->mail_attachment_detection_options, " ");
+
+ while(*options != NULL) {
+ const char *opt = *options;
+
+ if (strcmp(opt, "add-flags") == 0 ||
+ strcmp(opt, "add-flags-on-save") == 0) {
+ set->parsed_mail_attachment_detection_add_flags = TRUE;
+ } else if (strcmp(opt, "no-flags-on-fetch") == 0) {
+ set->parsed_mail_attachment_detection_no_flags_on_fetch = TRUE;
+ } else if (strcmp(opt, "exclude-inlined") == 0) {
+ set->parsed_mail_attachment_exclude_inlined = TRUE;
+ } else if (str_begins(opt, "content-type=")) {
+ const char *value = p_strdup(pool, opt+13);
+ array_push_back(&content_types, &value);
+ } else {
+ *error_r = t_strdup_printf("mail_attachment_detection_options: "
+ "Unknown option: %s", opt);
+ return FALSE;
+ }
+ options++;
+ }
+
+ array_append_zero(&content_types);
+ set->parsed_mail_attachment_content_type_filter = array_front(&content_types);
+ }
+
+ if (!mail_cache_fields_parse("mail_cache_fields",
+ set->mail_cache_fields, error_r))
+ return FALSE;
+ if (!mail_cache_fields_parse("mail_always_cache_fields",
+ set->mail_always_cache_fields, error_r))
+ return FALSE;
+ if (!mail_cache_fields_parse("mail_never_cache_fields",
+ set->mail_never_cache_fields, error_r))
+ return FALSE;
+ return TRUE;
+}
+
+static bool namespace_settings_check(void *_set, pool_t pool ATTR_UNUSED,
+ const char **error_r)
+{
+ struct mail_namespace_settings *ns = _set;
+ struct mail_namespace_settings *const *namespaces;
+ const char *name;
+ unsigned int i, count;
+
+ name = ns->prefix != NULL ? ns->prefix : "";
+
+ if (ns->separator[0] != '\0' && ns->separator[1] != '\0') {
+ *error_r = t_strdup_printf("Namespace '%s': "
+ "Hierarchy separator must be only one character long",
+ name);
+ return FALSE;
+ }
+ if (!uni_utf8_str_is_valid(name)) {
+ *error_r = t_strdup_printf("Namespace prefix not valid UTF8: %s",
+ name);
+ return FALSE;
+ }
+
+ if (ns->alias_for != NULL && !ns->disabled) {
+ if (array_is_created(&ns->user_set->namespaces)) {
+ namespaces = array_get(&ns->user_set->namespaces,
+ &count);
+ } else {
+ namespaces = NULL;
+ count = 0;
+ }
+ for (i = 0; i < count; i++) {
+ if (strcmp(namespaces[i]->prefix, ns->alias_for) == 0)
+ break;
+ }
+ if (i == count) {
+ *error_r = t_strdup_printf(
+ "Namespace '%s': alias_for points to "
+ "unknown namespace: %s", name, ns->alias_for);
+ return FALSE;
+ }
+ if (namespaces[i]->alias_for != NULL) {
+ *error_r = t_strdup_printf(
+ "Namespace '%s': alias_for chaining isn't "
+ "allowed: %s -> %s", name, ns->alias_for,
+ namespaces[i]->alias_for);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static bool mailbox_special_use_exists(const char *name)
+{
+ if (name[0] != '\\')
+ return FALSE;
+ name++;
+
+ if (strcasecmp(name, "All") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Archive") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Drafts") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Flagged") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Important") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Junk") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Sent") == 0)
+ return TRUE;
+ if (strcasecmp(name, "Trash") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static bool
+mailbox_special_use_check(struct mailbox_settings *set, pool_t pool,
+ const char **error_r)
+{
+ const char *const *uses, *str;
+ unsigned int i;
+
+ uses = t_strsplit_spaces(set->special_use, " ");
+ for (i = 0; uses[i] != NULL; i++) {
+ if (!mailbox_special_use_exists(uses[i])) {
+ *error_r = t_strdup_printf(
+ "mailbox %s: unknown special_use: %s",
+ set->name, uses[i]);
+ return FALSE;
+ }
+ }
+ /* make sure there are no extra spaces */
+ str = t_strarray_join(uses, " ");
+ if (strcmp(str, set->special_use) != 0)
+ set->special_use = p_strdup(pool, str);
+ return TRUE;
+}
+
+static bool mailbox_settings_check(void *_set, pool_t pool,
+ const char **error_r)
+{
+ struct mailbox_settings *set = _set;
+
+ if (!uni_utf8_str_is_valid(set->name)) {
+ *error_r = t_strdup_printf("mailbox %s: name isn't valid UTF-8",
+ set->name);
+ return FALSE;
+ }
+ if (*set->special_use != '\0') {
+ if (!mailbox_special_use_check(set, pool, error_r))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static bool mail_user_settings_check(void *_set, pool_t pool ATTR_UNUSED,
+ const char **error_r ATTR_UNUSED)
+{
+ struct mail_user_settings *set = _set;
+
+#ifndef CONFIG_BINARY
+ fix_base_path(set, pool, &set->auth_socket_path);
+
+ if (*set->hostname == '\0')
+ set->hostname = p_strdup(pool, my_hostdomain());
+ if (set->postmaster_address[0] == SETTING_STRVAR_UNEXPANDED[0] &&
+ set->postmaster_address[1] == '\0') {
+ /* check for valid looking fqdn in hostname */
+ if (strchr(set->hostname, '.') == NULL) {
+ *error_r = "postmaster_address setting not given";
+ return FALSE;
+ }
+ set->postmaster_address =
+ p_strconcat(pool, SETTING_STRVAR_UNEXPANDED,
+ "postmaster@", set->hostname, NULL);
+ }
+#else
+ if (*set->mail_plugins != '\0' &&
+ access(set->mail_plugin_dir, R_OK | X_OK) < 0) {
+ *error_r = t_strdup_printf(
+ "mail_plugin_dir: access(%s) failed: %m",
+ set->mail_plugin_dir);
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+#ifndef CONFIG_BINARY
+static bool parse_postmaster_address(const char *address, pool_t pool,
+ struct mail_user_settings *set,
+ const char **error_r) ATTR_NULL(3)
+{
+ struct message_address *addr;
+ struct smtp_address *smtp_addr;
+
+ addr = message_address_parse(pool,
+ (const unsigned char *)address,
+ strlen(address), 2, 0);
+ if (addr == NULL || addr->domain == NULL || addr->invalid_syntax ||
+ smtp_address_create_from_msg(pool, addr, &smtp_addr) < 0) {
+ *error_r = t_strdup_printf(
+ "invalid address `%s' specified for the "
+ "postmaster_address setting", address);
+ return FALSE;
+ }
+ if (addr->next != NULL) {
+ *error_r = "more than one address specified for the "
+ "postmaster_address setting";
+ return FALSE;
+ }
+ if (addr->name == NULL || *addr->name == '\0')
+ addr->name = "Postmaster";
+ if (set != NULL) {
+ set->_parsed_postmaster_address = addr;
+ set->_parsed_postmaster_address_smtp = smtp_addr;
+ }
+ return TRUE;
+}
+
+static bool
+mail_user_settings_expand_check(void *_set, pool_t pool,
+ const char **error_r ATTR_UNUSED)
+{
+ struct mail_user_settings *set = _set;
+ const char *error;
+
+ /* Parse if possible. Perform error handling later. */
+ (void)parse_postmaster_address(set->postmaster_address, pool,
+ set, &error);
+ return TRUE;
+}
+#endif
+
+/* </settings checks> */
+
+static void
+get_postmaster_address_error(const struct mail_user_settings *set,
+ const char **error_r)
+{
+ if (parse_postmaster_address(set->postmaster_address,
+ pool_datastack_create(), NULL, error_r))
+ i_panic("postmaster_address='%s' parsing succeeded unexpectedly after it had already failed",
+ set->postmaster_address);
+}
+
+bool mail_user_set_get_postmaster_address(const struct mail_user_settings *set,
+ const struct message_address **address_r,
+ const char **error_r)
+{
+ *address_r = set->_parsed_postmaster_address;
+ if (*address_r != NULL)
+ return TRUE;
+ /* parsing failed - do it again to get the error */
+ get_postmaster_address_error(set, error_r);
+ return FALSE;
+}
+
+bool mail_user_set_get_postmaster_smtp(const struct mail_user_settings *set,
+ const struct smtp_address **address_r,
+ const char **error_r)
+{
+ *address_r = set->_parsed_postmaster_address_smtp;
+ if (*address_r != NULL)
+ return TRUE;
+ /* parsing failed - do it again to get the error */
+ get_postmaster_address_error(set, error_r);
+ return FALSE;
+}