diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-storage/mail-storage-settings.c | 809 |
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; +} |