doc/wiki/Makefile.am
src/anvil/anvil
src/auth/auth
+src/lib-settings/settings-history-core.c
src/config/all-settings.c
src/config/config
src/config/doveconf
string_t *full_line;
char *line;
int fd, ret = 0;
- bool handled, dump_defaults = (path == NULL);
+ bool dump_defaults = (path == NULL);
*config_r = NULL;
if (!config_parser_get_version(&ctx, &config_line) &&
ctx.error == NULL) T_BEGIN {
- handled = old_settings_handle(&ctx, &config_line);
- if (!handled)
- config_parser_apply_line(&ctx, &config_line);
+ old_settings_handle(&ctx, &config_line);
+ config_parser_apply_line(&ctx, &config_line);
} T_END;
if (ctx.error != NULL) {
case SET_STR_NOVARS:
case SET_ENUM: {
string_t *default_str = NULL;
+ bool default_changed = FALSE;
+ const char *old_default;
i_assert(info->defaults != NULL);
- if (!dump_default || module_parser->change_counters[define_idx] == 0) {
+ if (module_parser->change_counters[define_idx] <= CONFIG_PARSER_CHANGE_DEFAULTS) {
+ /* Setting isn't explicitly set. We need to see
+ if its default has changed. */
+ if (old_settings_default(ctx->dovecot_config_version,
+ def->key, &old_default)) {
+ default_str = t_str_new(strlen(old_default));
+ str_append(default_str, old_default);
+ default_changed = TRUE;
+ }
+ }
+
+ if ((!dump_default || module_parser->change_counters[define_idx] == 0) &&
+ default_str == NULL) {
const void *default_value =
CONST_PTR_OFFSET(info->defaults,
def->offset);
actually changed from its default. */
break;
}
- if (module_parser->change_counters[define_idx] != 0) {
+ if (module_parser->change_counters[define_idx] >
+ CONFIG_PARSER_CHANGE_DEFAULTS) {
+ /* explicitly set */
+ str_append(ctx->value,
+ module_parser->settings[define_idx].str);
+ } else if (module_parser->change_counters[define_idx] ==
+ CONFIG_PARSER_CHANGE_DEFAULTS && !default_changed) {
+ /* default not changed by old version checks */
str_append(ctx->value,
module_parser->settings[define_idx].str);
} else {
/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "array.h"
#include "master-service.h"
+#include "settings-history.h"
#include "config-parser-private.h"
#include "old-set-parser.h"
va_end(args);
}
-bool old_settings_handle(struct config_parser_context *ctx ATTR_UNUSED,
- const struct config_line *line)
+static void old_settings_handle_rename(struct config_parser_context *ctx,
+ struct config_line *line)
+{
+ struct settings_history *history = settings_history_get();
+ const struct setting_history_rename *rename;
+
+ if (ctx->dovecot_config_version[0] == '\0')
+ return;
+
+ array_foreach(&history->renames, rename) {
+ if (version_cmp(rename->version,
+ ctx->dovecot_config_version) <= 0)
+ break;
+ if (strcmp(rename->old_key, line->key) == 0) {
+ obsolete(ctx, "%s has been renamed to %s",
+ rename->old_key, rename->new_key);
+ line->key = rename->new_key;
+ break;
+ }
+ }
+}
+
+void old_settings_handle(struct config_parser_context *ctx,
+ struct config_line *line)
{
switch (line->type) {
case CONFIG_LINE_TYPE_SKIP:
case CONFIG_LINE_TYPE_KEYFILE:
case CONFIG_LINE_TYPE_KEYVALUE:
case CONFIG_LINE_TYPE_KEYVARIABLE:
+ old_settings_handle_rename(ctx, line);
break;
}
+}
+
+bool old_settings_default(const char *dovecot_config_version,
+ const char *key, const char **old_default_r)
+{
+ struct settings_history *history = settings_history_get();
+ const struct setting_history_default *def;
+
+ if (dovecot_config_version[0] == '\0')
+ return FALSE;
+
+ array_foreach(&history->defaults, def) {
+ if (version_cmp(def->version, dovecot_config_version) <= 0)
+ break;
+ if (strcmp(def->key, key) == 0) {
+ *old_default_r = def->old_value;
+ return TRUE;
+ }
+ }
return FALSE;
}
struct config_parser_context;
-bool old_settings_handle(struct config_parser_context *ctx,
- const struct config_line *line);
+void old_settings_handle(struct config_parser_context *ctx,
+ struct config_line *line);
+bool old_settings_default(const char *dovecot_config_version,
+ const char *key, const char **old_default_r);
#endif
libsettings_la_SOURCES = \
settings.c \
+ settings-history.c \
settings-parser.c
headers = \
settings.h \
+ settings-history.h \
settings-parser.h
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
+BUILT_SOURCES = settings-history-core.c
+
+settings-history.c: settings-history-core.c
+
+settings-history-core.c: $(top_srcdir)/src/lib-settings/settings-history.pl settings-history-core.txt
+ $(AM_V_GEN)$(top_srcdir)/src/lib-settings/settings-history.pl settings-history-core.txt $(DOVECOT_PRO_BUILD) > settings-history-core.c || rm -f settings-history-core.c
+
+EXTRA_DIST = \
+ settings-history-core.txt \
+ settings-history.pl
+
test_programs = \
test-settings-parser \
test-settings
--- /dev/null
+/* Copyright (c) 2025 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "settings-history.h"
+
+#include "settings-history-core.c"
+
+static struct settings_history history;
+
+static void settings_history_free(void)
+{
+ array_free(&history.defaults);
+ array_free(&history.renames);
+}
+
+struct settings_history *settings_history_get(void)
+{
+ if (array_is_created(&history.defaults))
+ return &history;
+
+ i_array_init(&history.defaults,
+ N_ELEMENTS(settings_history_core_defaults) + 16);
+ array_append(&history.defaults,
+ settings_history_core_defaults,
+ N_ELEMENTS(settings_history_core_defaults));
+ i_array_init(&history.renames,
+ N_ELEMENTS(settings_history_core_renames) + 16);
+ array_append(&history.renames,
+ settings_history_core_renames,
+ N_ELEMENTS(settings_history_core_renames));
+
+ lib_atexit(settings_history_free);
+ return &history;
+}
+
+void settings_history_register_defaults(
+ const struct setting_history_default *defaults, unsigned int count)
+{
+ struct settings_history *history = settings_history_get();
+
+ array_append(&history->defaults, defaults, count);
+}
+
+void settings_history_register_renames(
+ const struct setting_history_rename *renames, unsigned int count)
+{
+ struct settings_history *history = settings_history_get();
+
+ array_append(&history->renames, renames, count);
+}
--- /dev/null
+#ifndef SETTINGS_HISTORY_H
+#define SETTINGS_HISTORY_H
+
+struct setting_history_default {
+ const char *key;
+ const char *old_value;
+ const char *version;
+};
+
+struct setting_history_rename {
+ const char *old_key, *new_key;
+ const char *version;
+};
+
+struct settings_history {
+ ARRAY(struct setting_history_default) defaults;
+ ARRAY(struct setting_history_rename) renames;
+};
+
+struct settings_history *settings_history_get(void);
+
+/* Register new defaults/renames. The strings are assumed to be statically
+ allocated, i.e. they are not duplicated. */
+void settings_history_register_defaults(
+ const struct setting_history_default *defaults, unsigned int count);
+void settings_history_register_renames(
+ const struct setting_history_rename *renames, unsigned int count);
+
+#endif
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use version;
+use 5.010;
+
+my ($input_path, $pro_edition) = ($ARGV[0], $ARGV[1]);
+
+# output renames
+print "static const struct setting_history_rename settings_history_core_renames[] = {\n";
+my $f;
+open $f, "<:encoding(utf8)", $input_path or die "$!";
+my $prev_version = "";
+while (<$f>) {
+ chomp;
+ if (/^rename\t/) {
+ my ($type, $old_key, $new_key, $ce_version, $pro_version) = split("\t");
+ my $version = $pro_edition ? $pro_version : $ce_version;
+ if ($version ne "") {
+ die "bad version: $version" if $version !~ /^((\d+)\.)*(\d+)$/;
+ print " { \"$old_key\", \"$new_key\", \"$version\" },\n";
+ if ($prev_version ne "") {
+ die "Bad version sorting order" if version->parse($version) > version->parse($prev_version);
+ }
+ $prev_version = $version;
+ }
+ } elsif (! /^default\t/) {
+ die "Unknown line: $_";
+ }
+}
+close $f;
+print "};\n";
+
+# output defaults
+print "static const struct setting_history_default settings_history_core_defaults[] = {\n";
+open $f, "<:encoding(utf8)", $input_path or die "$!";
+while (<$f>) {
+ chomp;
+ if (/^default\t/) {
+ my ($type, $key, $old_value, $ce_version, $pro_version) = split("\t");
+ my $version = $pro_edition ? $pro_version : $ce_version;
+ if ($version ne "") {
+ die "bad version: $version" if $version !~ /^((\d+)\.)*(\d+)$/;
+ print " { \"$key\", \"$old_value\", \"$version\" },\n";
+ if ($prev_version ne "") {
+ die "Bad version sorting order" if version->parse($version) > version->parse($prev_version);
+ }
+ $prev_version = $version;
+ }
+ }
+}
+close $f;
+print "};\n";