diff --git a/doc/sympa_config.podpl b/doc/sympa_config.podpl index b5457d5c4..09e7bb41d 100644 --- a/doc/sympa_config.podpl +++ b/doc/sympa_config.podpl @@ -7,7 +7,6 @@ use Cwd qw(); use English qw(-no_match_vars); use Getopt::Long; -use Sympa::ConfDef; use Sympa::Config::Schema; use Sympa::Constants; use Sympa::ListOpt; @@ -67,35 +66,40 @@ foreach my $okey ( and $pinfo->{$_}->{obsolete} =~ /\A[a-z]/ } _keys($pinfo) ) { - my $nkey = $pinfo->{$okey}->{obsolete}; + my $pii = $pinfo->{$okey}; + my $ppi = [$okey]; - $parameters .= sprintf "=head3 C<%s>\n\n", _escape_pod($okey); - $parameters .= sprintf "See L|/%s>.\n\n", _escape_pod($nkey), - _escape_pod($nkey); -} - -$parameters .= "=head2 Obsoleted F parameters\n\n"; -$parameters .= "These parameters were used in F or F"; -$parameters .= " on Sympa 6.2.56 or earlier and are no longer"; -$parameters .= " recommended.\n\n"; -foreach my $okey (sort keys %Sympa::Config::Schema::obsolete_robot_params) { - my $nkey = $Sympa::Config::Schema::obsolete_robot_params{$okey}; - - $parameters .= sprintf "=head3 C<%s>\n\n", _escape_pod($okey); - $parameters .= sprintf "See L|/%s>.\n\n", _escape_pod($nkey), - _escape_pod($nkey); + $parameters .= sprintf "=head3 C<%s>\n\n", _escape_pod($okey); + _render($pii, $ppi); } $parameters .= "=head2 Deprecated parameters\n\n"; $parameters .= "These parameters were deprecated."; $parameters .= " They may not be used anymore.\n\n"; foreach my $okey ( - sort grep { - $pinfo->{$_}->{obsolete} - and $pinfo->{$_}->{obsolete} !~ /\A[a-z]/ - } _keys($pinfo) + sort('tracking', + grep { + $pinfo->{$_}->{obsolete} + and $pinfo->{$_}->{obsolete} !~ /\A[a-z]/ + } _keys($pinfo)) ) { - $parameters .= sprintf "=head3 C<%s>\n\n", _escape_pod($okey); + if ($okey eq 'tracking') { + # Special: 'tracking' is a name of paragraph in list config. + $parameters .= "=head3 C (domain and site)\n\n"; + _render( + { context => [qw(domain site)], + obsolete => 'tracking.tracking', + not_after => '6.2.56', + }, + [] + ); + } else { + my $pii = $pinfo->{$okey}; + my $ppi = [$okey]; + + $parameters .= sprintf "=head3 C<%s>\n\n", _escape_pod($okey); + _render($pii, $ppi); + } } printf do { local $RS; }, Sympa::Constants::CONFIG(), $parameters, @@ -108,12 +112,7 @@ sub _render { my $ppi = shift; if ($pii->{obsolete}) { - if ($pii->{obsolete} eq '1') { - $parameters .= "Deprecated.\n\n"; - } else { - $parameters .= sprintf "Obsoleted. Use L|/%s>.\n\n", - $pii->{obsolete}, $pii->{obsolete}; - } + _render_obsolete($pii, $ppi); } elsif ($pii->{occurrence} =~ /n$/ and ref $pii->{format} eq 'ARRAY') { _render_set($pii, $ppi); } elsif (ref $pii->{format} eq 'HASH') { @@ -152,12 +151,7 @@ sub _render_paragraph { #$parameters .= "=over\n\n" x (scalar @$pnames); if ($pii->{obsolete}) { - if ($pii->{obsolete} eq '1') { - $parameters .= "Deprecated.\n\n"; - } else { - $parameters .= sprintf "Obsoleted. Use L|/%s>.\n\n", - $pii->{obsolete}, join '.', @$pnames, $pii->{obsolete}; - } + _render_obsolete($pii); } elsif ($pii->{occurrence} =~ /n$/ and ref $pii->{format} eq 'ARRAY') { _render_set($pii, $ppi); @@ -181,6 +175,7 @@ sub _render_set { _format($pinfo); _default($pinfo, $pnames); _context($pinfo); + _version($pinfo); $parameters .= "=back\n\n"; $parameters .= sprintf "%s\n\n", join "\n\n", split /\n/, @@ -202,6 +197,7 @@ sub _render_scalar { _format($pinfo); _default($pinfo, $pnames); _context($pinfo); + _version($pinfo); $parameters .= "=back\n\n"; @@ -212,6 +208,23 @@ sub _render_scalar { _sample($pinfo, $pnames); } +sub _render_obsolete { + my $pii = shift; + + return unless $pii->{obsolete}; + + if ($pii->{obsolete} eq '1') { + $parameters .= "Deprecated.\n\n"; + } else { + $parameters .= sprintf "See L|/%s>.\n\n", + $pii->{obsolete}, $pii->{obsolete}; + } + $parameters .= "=over\n\n"; + _context($pii); + _version($pii); + $parameters .= "=back\n\n"; +} + sub _format { my $pinfo = shift; @@ -220,7 +233,7 @@ sub _format { if ($pinfo->{occurrence} =~ /n$/) { if ($pinfo->{split_char}) { $parameters .= - sprintf "Multiple values allowed, separated by C<%s>.\n\n", + sprintf "Multiple values allowed, separated by \"C<%s>\".\n\n", $pinfo->{split_char}; } else { $parameters .= "Multiple occurrences allowed.\n\n"; @@ -289,6 +302,8 @@ sub _format { $format =~ s/\A\(\?\^:(.*)\)\z/$1/ or $format =~ s/\A\(\?-xism:(.*)\)\z/$1/; $parameters .= sprintf "/C<%s>/\n\n", _escape_pod($format); + } else { + $parameters .= "Any.\n\n"; } } @@ -342,6 +357,26 @@ sub _context { } } +sub _version { + my $pinfo = shift; + + my $param_text; + my ($nb, $na) = @{$pinfo}{qw(not_before not_after)}; + undef $nb if ($nb // '') =~ /^[?]+$/; + undef $na if ($na // '') =~ /^[?]+$/; + + if ($nb and $na) { + $param_text = sprintf "%s to %s.", $nb, $na; + } elsif ($nb) { + $param_text = sprintf "%s and later.", $nb; + } elsif ($na) { + $param_text = sprintf "up to %s.", $na; + } + + $parameters .= "=item Available versions:\n\n$param_text\n\n" + if $param_text; +} + sub _sample { my $pinfo = shift; my $pnames = shift; diff --git a/src/lib/Conf.pm b/src/lib/Conf.pm index 73666d43d..46e528acb 100644 --- a/src/lib/Conf.pm +++ b/src/lib/Conf.pm @@ -78,40 +78,6 @@ foreach my $hash (@Sympa::ConfDef::params) { our $params_by_categories = _get_parameters_names_by_category(); -my %old_params = ( - trusted_ca_options => 'capath,cafile', - 'msgcat' => '', - queueexpire => '', - clean_delay_queueother => '', - web_recode_to => 'filesystem_encoding', # ??? - 5.2 - 'localedir' => '', - 'ldap_export_connection_timeout' => '', # 3.3b3 - 4.1? - 'ldap_export_dnmanager' => '', # ,, - 'ldap_export_host' => '', # ,, - 'ldap_export_name' => '', # ,, - 'ldap_export_password' => '', # ,, - 'ldap_export_suffix' => '', # ,, - 'tri' => 'sort', # ??? - 1.3.4-1 - 'sort' => '', # 1.4.0 - ??? - 'pidfile' => '', # ??? - 6.1.17 - 'pidfile_distribute' => '', # ,, - 'pidfile_creation' => '', # ,, - 'pidfile_bulk' => '', # ,, - 'archived_pidfile' => '', # ,, - 'bounced_pidfile' => '', # ,, - 'task_manager_pidfile' => '', # ,, - 'email_gecos' => 'gecos', # 6.2a.?? - 6.2a.33 - 'lock_method' => '', # 5.3b.3 - 6.2a.33 - 'html_editor_file' => 'html_editor_url', # 6.2a - 'openssl' => '', # ?? - 6.2a.40 - 'distribution_mode' => '', # 5.0a.1 - 6.2a.40 - 'queuedistribute' => '', # ,, - - # These are not yet implemented - 'crl_dir' => '', - 'dkim_header_list' => '', -); - my %trusted_applications = ( 'trusted_application' => { 'occurrence' => '0-n', @@ -177,6 +143,7 @@ sub load { my $force_reload; my $config_err = 0; + my $unknown; my %line_numbered_config; $log->syslog('debug3', @@ -185,12 +152,12 @@ sub load { # Will force the robot.conf reloading, as sympa.conf is the default. $force_reload = 1; ## Loading the Sympa main config file. - if (my $config_loading_result = - _load_config_file_to_hash({'path_to_config_file' => $config_file})) { + if (my $config_loading_result = _load_config_file_to_hash($config_file)) { %line_numbered_config = %{$config_loading_result->{'numbered_config'}}; %Conf = %{$config_loading_result->{'config'}}; $config_err = $config_loading_result->{'errors'}; + $unknown = $config_loading_result->{unknown}; } else { return undef; } @@ -200,18 +167,13 @@ sub load { # Users may define parameters with a typo or other errors. Check that # the parameters # we found in the config file are all well defined Sympa parameters. - $config_err += _detect_unknown_parameters_in_config( - { 'config_hash' => \%Conf, - 'config_file_line_numbering_reference' => \%line_numbered_config, - } - ); + $config_err += $unknown; - _set_listmasters_entry({'config_hash' => \%Conf, 'main_config' => 1}); + _set_listmasters_entry(\%Conf); ## Some parameters must have a value specifically defined in the ## config. If not, it is an error. - $config_err += _detect_missing_mandatory_parameters( - {'config_hash' => \%Conf, 'file_to_check' => $config_file}); + $config_err += _detect_missing_mandatory_parameters(\%Conf); # Some parameters need special treatments to get their final values. _infer_server_specific_parameter_values({'config_hash' => \%Conf,}); @@ -299,18 +261,21 @@ sub load_robots { ## returns a robot conf parameter sub get_robot_conf { - my ($robot, $param) = @_; + my ($robot, $key) = @_; - $param = $Sympa::Config::Schema::obsolete_robot_params{$param} // $param; + # Resolve alias. + my ($k, $o) = ($key, $key); + do { + ($k, $o) = ($o, ($params{$o} // {})->{obsolete}); + } while ($o and $params{$o}); + $key = $k; - if (defined $robot && $robot ne '*') { - if ( defined $Conf{'robots'}{$robot} - && defined $Conf{'robots'}{$robot}{$param}) { - return $Conf{'robots'}{$robot}{$param}; - } + if (defined $robot and $robot ne '*') { + return $Conf{'robots'}{$robot}{$key} + if defined($Conf{'robots'}{$robot} // {})->{$key}; } - ## default - return $Conf{$param}; + # default + return $Conf{$key}; } =over 4 @@ -549,10 +514,7 @@ sub conf_2_db { my $config; if (my $result_of_config_loading = _load_config_file_to_hash( - { 'path_to_config_file' => $Conf{'etc'} . '/' - . $robot - . '/robot.conf' - } + $Conf{'etc'} . '/' . $robot . '/robot.conf' ) ) { $config = $result_of_config_loading->{'config'}; @@ -1662,79 +1624,84 @@ sub _load_a_param { ## loaded, due to an error. ## Returns undef if something went wrong while attempting to read the file. sub _load_config_file_to_hash { - my $param = shift; + my $config_file = shift; my $line_num = 0; - ## Open the configuration file or return and read the lines. - unless (open(IN, $param->{'path_to_config_file'})) { - $log->syslog( - 'notice', - 'Unable to open %s: %m', - $param->{'path_to_config_file'} - ); + # Open the configuration file or return and read the lines. + my $ifh; + unless (open $ifh, '<', $config_file) { + $log->syslog('notice', 'Unable to open %s: %m', $config_file); return undef; } # Initialize result. my $result = { errors => 0, + unknown => 0, config => {}, numbered_config => {}, }; - while () { + while (<$ifh>) { $line_num++; # skip empty or commented lines next if (/^\s*$/ || /^[\#;]/); + # match "keyword value" pattern - if (/^(\S+)\s+(.+)$/) { - my ($keyword, $value) = ($1, $2); - $value =~ s/\s*$//; + unless (/^(\S+)\s+(.+)$/) { + $log->syslog('err', 'Error at line %d: %s', + $line_num, $config_file, $_); + $result->{errors}++; + next; + } + my ($key, $val) = ($1, $2); + $val =~ s/\s*$//; + + # Deprecated syntax: `command` + if ($val =~ /^\`(.*)\`$/) { + die sprintf + "%s: Backtick (`...`) in %s is no longer allowed. Check and modify configuration.\n", + $val, $config_file; + } - # Deprecated syntax: `command` - if ($value =~ /^\`(.*)\`$/) { - die sprintf - "%s: Backtick (`...`) in sympa.conf is no longer allowed. Check and modify configuration.\n", - $value; - } + # Unknown parameter name. + unless ($params{$key}) { + $log->syslog('err', 'Line %d, unknown field: %s in %s', + $line_num, $key, $config_file); + $result->{unknown}++; + next; + } - $keyword = - $Sympa::Config::Schema::obsolete_robot_params{$keyword} - // $keyword; - # Resolve renamed parameters FIXME - $keyword = { - merge_feature => - 'personalization_feature', # 6.0b.2 - 6.2.59b.1 - use_blacklist => 'use_blocklist', # 5.3a.4 - 6.2.60 - domains_blacklist => 'domains_blocklist', # 6.2.41b.1 - 6.2.60 - }->{$keyword} // $keyword; - - if (exists $params{$keyword} - and ( - 1 == ($params{$keyword}{'multiple'} // 0) #FIXME - or $keyword eq 'custom_robot_parameter' - ) - ) { - if (defined $result->{'config'}{$keyword}) { - push @{$result->{'config'}{$keyword}}, $value; - push @{$result->{'numbered_config'}{$keyword}}, - [$value, $line_num]; - } else { - $result->{'config'}{$keyword} = [$value]; - $result->{'numbered_config'}{$keyword} = - [[$value, $line_num]]; - } + # Resolve alias. + my ($k, $o) = ($key, $key); + do { + ($k, $o) = ($o, ($params{$o} // {})->{obsolete}); + } while ($o and $params{$o}); + $key = $k; + + if ($params{$key}->{multiple} #FIXME: not implemented yet + or $key eq 'custom_robot_parameter' + or $key eq 'listmaster' + ) { + if (my $split_char = $params{$key}->{split_char}) { + my @vals = + grep { length $_ } split(/\s*$split_char\s*/, $val); + $result->{config}{$key} = [@vals]; + $result->{numbered_config}{$key} = + [map { [$_, $line_num] } @vals]; + } elsif ($result->{config}{$key}) { + push @{$result->{config}{$key}}, $val; + push @{$result->{numbered_config}{$key}}, [$val, $line_num]; } else { - $result->{'config'}{$keyword} = $value; - $result->{'numbered_config'}{$keyword} = [$value, $line_num]; + $result->{config}{$key} = [$val]; + $result->{numbered_config}{$key} = [[$val, $line_num]]; } } else { - $log->syslog('err', 'Error at line %d: %s', - $line_num, $param->{'path_to_config_file'}, $_); - $result->{'errors'}++; + $result->{config}{$key} = $val; + $result->{numbered_config}{$key} = [$val, $line_num]; } } - close(IN); + close $ifh; return $result; } @@ -1753,44 +1720,8 @@ sub _remove_unvalid_robot_entry { return 1; } -sub _detect_unknown_parameters_in_config { - my $param = shift; - my $number_of_unknown_parameters_found = 0; - foreach my $parameter (sort keys %{$param->{'config_hash'}}) { - next if (exists $params{$parameter}); - if (defined $old_params{$parameter}) { - if ($old_params{$parameter}) { - $log->syslog( - 'err', - 'Line %d of sympa.conf, parameter %s is no more available, read documentation for new parameter(s) %s', - $param->{'config_file_line_numbering_reference'} - {$parameter}[1], - $parameter, - $old_params{$parameter} - ); - } else { - $log->syslog( - 'err', - 'Line %d of sympa.conf, parameter %s is now obsolete', - $param->{'config_file_line_numbering_reference'} - {$parameter}[1], - $parameter - ); - next; - } - } else { - $log->syslog( - 'err', - 'Line %d, unknown field: %s in sympa.conf', - $param->{'config_file_line_numbering_reference'}{$parameter} - [1], - $parameter - ); - } - $number_of_unknown_parameters_found++; - } - return $number_of_unknown_parameters_found; -} +# No longer used. +#sub _detect_unknown_parameters_in_config; sub _infer_server_specific_parameter_values { my $param = shift; @@ -1817,11 +1748,11 @@ sub _infer_server_specific_parameter_values { } my @dmarc = split /[,\s]+/, - ($param->{'config_hash'}{'dmarc_protection_mode'} || ''); + ($param->{'config_hash'}{'dmarc_protection.mode'} || ''); if (@dmarc) { - $param->{'config_hash'}{'dmarc_protection_mode'} = \@dmarc; + $param->{'config_hash'}{'dmarc_protection.mode'} = \@dmarc; } else { - delete $param->{'config_hash'}{'dmarc_protection_mode'}; + delete $param->{'config_hash'}{'dmarc_protection.mode'}; } ## Set Regexp for accepted list suffixes @@ -2027,26 +1958,23 @@ sub _load_robot_secondary_config_files { #sub _set_hardcoded_parameter_values; sub _detect_missing_mandatory_parameters { - my $param = shift; - my $number_of_errors = 0; - $param->{'file_to_check'} =~ /^(\/.*\/)?([^\/]+)$/; - my $config_file_name = $2; - foreach my $parameter (keys %params) { -## next if (defined $params{$parameter}->{'file'} && $params{$parameter}->{'file'} ne $config_file_name); - unless (defined $param->{'config_hash'}{$parameter} - or defined $params{$parameter}->{'default'} - or defined $params{$parameter}->{'optional'}) { - $log->syslog('err', 'Required field not found in sympa.conf: %s', - $parameter); - $number_of_errors++; + my $config_hash = shift; + + my $errors = 0; + foreach my $key (sort keys %params) { + next if defined $config_hash->{$key}; + next if $params{$key}->{optional}; + + if (defined $params{$key}->{default}) { + $config_hash->{$key} = $params{$key}->{default}; next; } - unless (defined $param->{'config_hash'}{$parameter}) { - $param->{'config_hash'}{$parameter} = - $params{$parameter}->{'default'}; - } + + $log->syslog('err', 'Required field not found in sympa.conf: %s', + $key); + $errors++; } - return $number_of_errors; + return $errors; } ## Some functionalities activated by some parameter values require that @@ -2094,8 +2022,7 @@ sub _load_single_robot_config { my $config_err; my $config_file = "$Conf{'etc'}/$robot/robot.conf"; - if (my $config_loading_result = - _load_config_file_to_hash({'path_to_config_file' => $config_file})) { + if (my $config_loading_result = _load_config_file_to_hash($config_file)) { $robot_conf = $config_loading_result->{'config'}; $config_err = $config_loading_result->{'errors'}; } else { @@ -2117,14 +2044,14 @@ sub _load_single_robot_config { } my @dmarc = split /[,\s]+/, - ($robot_conf->{'dmarc_protection_mode'} || ''); + ($robot_conf->{'dmarc_protection.mode'} || ''); if (@dmarc) { - $robot_conf->{'dmarc_protection_mode'} = \@dmarc; + $robot_conf->{'dmarc_protection.mode'} = \@dmarc; } else { - delete $robot_conf->{'dmarc_protection_mode'}; + delete $robot_conf->{'dmarc_protection.mode'}; } - _set_listmasters_entry({'config_hash' => $robot_conf}); + _set_listmasters_entry($robot_conf); _infer_robot_parameter_values({'config_hash' => $robot_conf}); @@ -2141,56 +2068,28 @@ sub _load_single_robot_config { } sub _set_listmasters_entry { - my $param = shift; - my $number_of_valid_email = 0; - my $number_of_email_provided = 0; - # listmaster is a list of email separated by commas - if (defined $param->{'config_hash'}{'listmaster'} - && $param->{'config_hash'}{'listmaster'} !~ /^\s*$/) { - $param->{'config_hash'}{'listmaster'} =~ s/\s//g; - my @emails_provided = - split(/,/, $param->{'config_hash'}{'listmaster'}); - $number_of_email_provided = $#emails_provided + 1; - foreach my $lismaster_address (@emails_provided) { - if (Sympa::Tools::Text::valid_email($lismaster_address)) { - # Note: 'listmasters' was obsoleted. - push @{$param->{'config_hash'}{'listmasters'}}, - $lismaster_address; - $number_of_valid_email++; - } else { - $log->syslog( - 'err', - 'Robot %s config: Listmaster address "%s" is not a valid email', - $param->{'config_hash'}{'domain'}, - $lismaster_address - ); - } - } - } else { - if ($param->{'main_config'}) { - $log->syslog('err', - 'Robot %s config: No listmaster defined. This is the main config. It MUST define at least one listmaster. Stopping here' - ); - return undef; + my $config_hash = shift; + + my @values = + grep { + if (Sympa::Tools::Text::valid_email($_)) { + 1; } else { - # Note: 'listmasters' was obsoleted. - $param->{'config_hash'}{'listmasters'} = $Conf{'listmasters'}; - $param->{'config_hash'}{'listmaster'} = $Conf{'listmaster'}; - $number_of_valid_email = - $#{$param->{'config_hash'}{'listmasters'}}; + $log->syslog( + 'err', + 'Robot %s config: Listmaster address "%s" is not a valid email', + $config_hash->{'domain'}, + $_ + ); + 0; } + } @{$config_hash->{'listmaster'} // []}; + + if (@values) { + $config_hash->{'listmaster'} = join ',', @values; #FIXME + } else { + delete $config_hash->{'listmaster'}; } - if ($number_of_email_provided > $number_of_valid_email) { - $log->syslog( - 'err', - 'Robot %s config: All the listmasters addresses found were not valid. Out of %s addresses provided, %s only are valid email addresses', - $param->{'config_hash'}{'domain'}, - $number_of_email_provided, - $number_of_valid_email - ); - return undef; - } - return $number_of_valid_email; } # No longer used. diff --git a/src/lib/Sympa/Config/Schema.pm b/src/lib/Sympa/Config/Schema.pm index caaf1802c..f3ea04325 100644 --- a/src/lib/Sympa/Config/Schema.pm +++ b/src/lib/Sympa/Config/Schema.pm @@ -207,8 +207,11 @@ our %pgroup = ( }, ); -my $site_obsolete = - {context => [qw(site)], group => '_obsoleted', obsolete => 1}; +my %site_obsolete = ( + context => [qw(site)], + group => '_obsoleted', + obsolete => 1 +); our %pinfo = ( @@ -269,8 +272,16 @@ our %pinfo = ( gettext_id => 'Display name of Sympa', gettext_comment => 'This parameter is used for display name in the "From:" header field for the messages sent by Sympa itself.', - format => '.+', + format => '.+', + not_before => '6.2a.34', }, + email_gecos => { + context => [qw(site)], + obsolete => 'gecos', + not_before => '6.2a.5', + not_after => '6.2a.33', + }, + legacy_character_support_feature => { context => [qw(site)], order => 1.13, @@ -496,6 +507,7 @@ our %pinfo = ( gettext_id => 'Whether to use the alias wrapper', gettext_comment => 'If the program to update alias database does not require root privileges, set this parameter to "off" and remove the wrapper file sympa_newaliases-wrapper.', + not_before => '6.2.59b.1', }, aliases_db_type => { context => [qw(domain site)], @@ -550,9 +562,10 @@ our %pinfo = ( }, owner => { - context => [qw(list)], - obsolete => 1, - format => { + context => [qw(list)], + obsolete => 1, + not_after => '6.2.32', + format => { email => { context => [qw(list)], obsolete => 1, @@ -588,9 +601,10 @@ our %pinfo = ( }, editor => { - context => [qw(list)], - obsolete => 1, - format => { + context => [qw(list)], + obsolete => 1, + not_after => '6.2.32', + format => { email => { context => [qw(list)], obsolete => 1, @@ -644,7 +658,9 @@ our %pinfo = ( format_s => '$host', filters => ['canonic_domain'], length => 20, - obsolete => 1 + # Site parameter became an alias of "domain" on 6.2a.0 + # List parameter no longer is available after 6.2.32 exclusive + obsolete => 1, }, lang => { @@ -686,6 +702,12 @@ our %pinfo = ( format => '\d+', length => 8, default => '0', + not_before => '6.2a.5', + }, + default_max_list_members => { + context => [qw(domain site)], + obsolete => 'max_list_members', + not_after => '6.2.56', }, # Incoming @@ -770,6 +792,11 @@ our %pinfo = ( occurrence => '1', default => '5', }, + default_list_priority => { + context => [qw(domain site)], + obsolete => 'priority', + not_after => '6.2.56', + }, incoming_max_count => { context => [qw(site)], @@ -779,7 +806,8 @@ our %pinfo = ( gettext_id => 'Max number of sympa.pl workers', gettext_comment => 'Max number of workers of sympa.pl daemon processing incoming spool.', - format => '\d+', + format => '\d+', + not_before => '6.2b.5', }, sleep => { @@ -1135,14 +1163,20 @@ our %pinfo = ( format => ['on', 'off'], occurrence => '1', default => 'off', + not_before => '6.2.59b.2', + }, + merge_feature => { + obsolete => 'personalization_feature', + not_before => '6.0b.2', + not_after => '6.2.59b.1', }, - merge_feature => {obsolete => 'personalization_feature'}, personalization => { context => [qw(list domain site)], order => 20.161, group => 'sending', gettext_id => "Message personalization", + not_before => '6.2.59b.2', format => { web_apply_on => { context => [qw(list domain site)], @@ -1170,6 +1204,7 @@ our %pinfo = ( order => 20.17, group => 'sending', gettext_id => 'Hook modules for message processing', + not_before => '6.2a.41', format => { pre_distribute => { context => [qw(list)], @@ -1197,6 +1232,7 @@ our %pinfo = ( format => ['on', 'off'], occurrence => '1', default => 'on', + not_before => '6.2a.0', }, remove_headers => { @@ -1272,6 +1308,7 @@ our %pinfo = ( format => '[-\w*]+(?:[.][-\w*]+)+', split_char => ',', sample => '*.example.org,www.example.com', + not_before => '6.2.19b.2', }, sympa_packet_priority => { @@ -1415,6 +1452,7 @@ our %pinfo = ( default => 'auth', gettext_id => 'Who is able to change user\'s email', scenario => 'move_user', + not_before => '6.2.19b.1', }, use_blocklist => { context => [qw(domain site)], @@ -1425,9 +1463,15 @@ our %pinfo = ( split_char => ',', gettext_comment => 'List of operations separated by comma for which blocklist filter is applied. Setting this parameter to "none" will hide the blocklist feature.', - format => '[-.\w]+', + format => '[-.\w]+', + not_before => '6.2.61b.1', + }, + use_blacklist => { + context => [qw(domain site)], + obsolete => 'use_blocklist', + not_before => '5.3a.4', + not_after => '6.2.60', }, - use_blacklist => {obsolete => 'use_blocklist'}, ### Priviledges on the lists @@ -1529,6 +1573,7 @@ our %pinfo = ( length => 72, occurrence => '0-1', split_char => ' ', + not_before => '6.2.23b.3', }, owner_domain_min => { @@ -1544,6 +1589,7 @@ our %pinfo = ( length => 2, occurrence => '0-1', default => '0', + not_before => '6.2.23b.3', }, shared_doc => { @@ -1579,6 +1625,21 @@ our %pinfo = ( } } }, + d_read => { + context => [qw(domain site)], + obsolete => 'shared_doc.d_read', + not_after => '6.2.56', + }, + d_edit => { + context => [qw(domain site)], + obsolete => 'shared_doc.d_edit', + not_after => '6.2.56', + }, + default_shared_quota => { + context => [qw(domain site)], + obsolete => 'shared_doc.quota', + not_after => '6.2.56', + }, ### Archives page ### @@ -1614,13 +1675,15 @@ our %pinfo = ( format => ['on', 'off'], occurrence => '1', default => 'off', + not_before => '6.2b.1', }, web_archive => { context => [qw(list domain site)], - obsolete => '1', # Merged into archive. group => 'archives', gettext_id => "Web archives", + obsolete => '1', # Merged into archive. + not_after => '6.2a.43', format => { access => { context => [qw(list domain site)], @@ -1671,7 +1734,8 @@ our %pinfo = ( gettext_id => "access right", format => ['open', 'private', 'public', 'owner', 'closed'], synonym => {'open' => 'public'}, - obsolete => 1, # Use archive.mail_access + obsolete => 1, # Use archive.mail_access + not_after => '6.2a.43', }, web_access => { context => [qw(list domain site)], @@ -1679,6 +1743,7 @@ our %pinfo = ( gettext_id => "access right", scenario => 'archive_web_access', default => 'closed', + not_before => '6.2b.1', }, mail_access => { context => [qw(list domain site)], @@ -1688,7 +1753,8 @@ our %pinfo = ( synonym => { 'open' => 'public', # Compat. with <=6.2b.3. }, - default => 'closed', + default => 'closed', + not_before => '6.2b.1', }, quota => { context => [qw(list site)], @@ -1696,7 +1762,8 @@ our %pinfo = ( gettext_id => "quota", gettext_unit => 'Kbytes', format => '\d+', - length => 8 + length => 8, + not_before => '6.2b.1', }, max_month => { context => [qw(list)], @@ -1704,10 +1771,26 @@ our %pinfo = ( gettext_id => "Maximum number of month archived", gettext_unit => 'months', format => '\d+', - length => 3 + length => 3, + not_before => '6.2b.1', } } }, + archive_web_access => { + context => [qw(domain site)], + obsolete => 'archive.web_access', + not_after => '6.2.56', + }, + archive_mail_access => { + context => [qw(domain site)], + obsolete => 'archive.mail_access', + not_after => '6.2.56', + }, + default_archive_quota => { + context => [qw(site)], + obsolete => 'archive.quota', + not_after => '6.2.56', + }, archive_crypted_msg => { context => [qw(list)], @@ -1768,6 +1851,16 @@ our %pinfo = ( } } }, + bounce_halt_rate => { + context => [qw(site)], + obsolete => 'bounce.halt_rate', + not_after => '6.2.56', + }, + bounce_warn_rate => { + context => [qw(site)], + obsolete => 'bounce.warn_rate', + not_after => '6.2.56', + }, bouncers_level1 => { context => [qw(list domain site)], @@ -1809,6 +1902,11 @@ our %pinfo = ( } } }, + default_bounce_level1_rate => { + context => [qw(domain site)], + obsolete => 'bouncers_level1.rate', + not_after => '6.2.56', + }, bouncers_level2 => { context => [qw(list domain site)], @@ -1850,6 +1948,11 @@ our %pinfo = ( } } }, + default_bounce_level2_rate => { + context => [qw(domain site)], + obsolete => 'bouncers_level2.rate', + not_after => '6.2.56', + }, verp_rate => { context => [qw(list domain site)], @@ -1869,6 +1972,7 @@ our %pinfo = ( order => 50.05, group => 'bounces', gettext_id => "Message tracking feature", + not_before => '6.2a.0', format => { delivery_status_notification => { context => [qw(list site)], @@ -1891,6 +1995,13 @@ our %pinfo = ( format => ['on', 'on_demand', 'off'], occurrence => '1', default => 'off', + not_before => '6.2a.41', + }, + message_delivery_notification => { + context => [qw(list)], + obsolete => 'message_disposition_notification', + not_before => '6.2a.0', + not_after => '6.2a.40', }, tracking => { context => [qw(list site)], @@ -1898,6 +2009,7 @@ our %pinfo = ( gettext_id => "who can view message tracking", scenario => 'tracking', default => 'owner', + not_before => '6.2a.3', }, retention_period => { context => [qw(list site)], @@ -1910,10 +2022,35 @@ our %pinfo = ( gettext_unit => 'days', format => '\d+', default => '90', - length => 5 + length => 5, + not_before => '6.2a.3', } } }, + tracking_default_retention_period => { + context => [qw(site)], + obsolete => 'tracking.retention_period', + not_before => '6.2a.3', + not_after => '6.2.56', + }, + tracking_delivery_status_notification => { + context => [qw(site)], + obsolete => 'tracking.delivery_status_notification', + not_before => '6.2a.0', + not_after => '6.2.56', + }, + tracking_message_disposition_notification => { + context => [qw(site)], + obsolete => 'tracking.message_disposition_notification', + not_before => '6.2a.41', + not_after => '6.2.56', + }, + tracking_message_delivery_notification => { + context => [qw(site)], + obsolete => 'tracking_message_disposition_notification', + not_before => '6.2a.0', + not_after => '6.2a.40', + }, welcome_return_path => { context => [qw(list site)], @@ -2158,6 +2295,7 @@ our %pinfo = ( gettext_id => 'Global unsubscription', default => 'auth', # Compat. to <=6.2.52 scenario => 'family_signoff', + not_before => '6.2.54', }, ### Tag-based spam filtering @@ -2343,7 +2481,8 @@ our %pinfo = ( gettext_id => 'Directory for message outgoing spool', gettext_comment => 'This parameter is named such by historical reason.', - format => '.+', + format => '.+', + not_before => '6.2a.41', }, tmpdir => { context => [qw(site)], @@ -2396,6 +2535,7 @@ our %pinfo = ( gettext_comment => 'This task cleans old content in spools.', default => 'daily', task => 'purge_spools', + not_before => '6.2b.4', }, clean_delay_queue => { context => [qw(site)], @@ -2497,6 +2637,7 @@ our %pinfo = ( format => '\d+', gettext_unit => 'days', default => '14', + not_before => '6.2.6', }, clean_delay_tmpdir => { context => [qw(site)], @@ -2521,7 +2662,8 @@ our %pinfo = ( gettext_id => 'File containing trusted CA certificates', gettext_comment => 'This can be used alternatively and/or additionally to "capath".', - format => '.+', + format => '.+', + not_before => '3.3.6b.1', }, capath => { context => [qw(site)], @@ -2530,7 +2672,8 @@ our %pinfo = ( gettext_id => 'Directory containing trusted CA certificates', gettext_comment => "CA certificates in this directory are used for client authentication.\nThe certificates need to have names including hash of subject, or symbolic links to them with such names. The links may be created by using \"c_rehash\" script bundled in OpenSSL.", - format => '.+', + format => '.+', + not_before => '3.3.6b.1', }, key_passwd => { context => [qw(site)], @@ -2591,6 +2734,7 @@ our %pinfo = ( order => 60.02, group => 'data_source', gettext_id => 'Subscribers defined in an external data source', + notbefore => '6.2b.1', format => { source => { context => [qw(list)], @@ -2707,9 +2851,16 @@ our %pinfo = ( #gettext_id => 'Default of SQL fetch timeout', #gettext_comment => # 'Default timeout while performing a fetch with include_sql_query.', - format => '\d+', - length => 6, - default => '300', + format => '\d+', + length => 6, + default => '300', + not_before => '6.2a.0', + }, + default_sql_fetch_timeout => { + context => [qw(site)], + obsolete => 'sql_fetch_timeout', + not_before => '6.2a.0', + not_after => '6.2.56', }, user_data_source => { @@ -2833,7 +2984,9 @@ our %pinfo = ( gettext_id => "List inclusion", format_s => '$listname(\@$host)?(\s+filter\s+.+)?', occurrence => '0-n', - obsolete => 1, # 2.2.6 - 6.2.15. + obsolete => 1, # See include_sympa_list + not_before => '2.2.6', + not_after => '6.2.15', }, include_sympa_list => { @@ -2843,7 +2996,9 @@ our %pinfo = ( gettext_id => "List inclusion", gettext_comment => 'Include subscribers from other list. All subscribers of list listname become subscribers of the current list. You may include as many lists as required, using one include_sympa_list paragraph for each included list. Any list at all may be included; you may therefore include lists which are also defined by the inclusion of other lists. Be careful, however, not to include list A in list B and then list B in list A, since this will give rise to an infinite loop.', - format => { + occurrence => '0-n', + not_before => '6.2.16', + format => { name => { context => [qw(list)], order => 1, @@ -2872,7 +3027,6 @@ our %pinfo = ( occurrence => '0-1' }, }, - occurrence => '0-n' }, include_remote_sympa_list => { @@ -2896,14 +3050,16 @@ our %pinfo = ( gettext_id => "data location URL", format => '.+', occurrence => '0-1', # Backward compat. <= 6.2.44 - length => 50 + length => 50, + not_before => '6.2.45b.1', }, user => { context => [qw(list)], order => 3, gettext_id => "remote user", format => '.+', - occurrence => '0-1' + occurrence => '0-1', + not_before => '6.2.45b.1', }, passwd => { context => [qw(list)], @@ -2913,6 +3069,7 @@ our %pinfo = ( field_type => 'password', occurrence => '0-1', length => 10, + not_before => '6.2.45b.1', }, host => { context => [qw(list)], @@ -2945,9 +3102,10 @@ our %pinfo = ( order => 4.8, gettext_id => "certificate for authentication by remote Sympa", - format => ['robot', 'list'], - default => 'list', - obsolete => 1, + format => ['robot', 'list'], + default => 'list', + obsolete => 1, + not_after => '6.2.44', }, timeout => { context => [qw(list)], @@ -2957,6 +3115,7 @@ our %pinfo = ( format => '\d+', length => 6, default => 180, + not_before => '6.2.45b.1', }, ssl_version => { context => [qw(list)], @@ -2969,13 +3128,15 @@ our %pinfo = ( synonym => {'tls' => 'tlsv1'}, occurrence => '0-1', default => 'ssl_any', + not_before => '6.2.45b.1', }, ssl_ciphers => { context => [qw(list)], order => 7, gettext_id => 'SSL ciphers used', format => '.+', - default => 'ALL' + default => 'ALL', + not_before => '6.2.45b.1', }, # ssl_cert # Use cert.pem in list directory # ssl_key # Use private_key in list directory @@ -2990,6 +3151,7 @@ our %pinfo = ( synonym => {'require' => 'required'}, occurrence => '0-1', default => 'optional', + not_before => '6.2.45b.1', }, # ca_path # Not yet implemented # ca_file # Not yet implemented @@ -3043,6 +3205,7 @@ our %pinfo = ( synonym => {'yes' => 'ldaps', 'no' => 'none'}, occurrence => '1', default => 'none', + not_before => '6.2.15', }, use_ssl => { context => [qw(list)], @@ -3050,7 +3213,9 @@ our %pinfo = ( #gettext_id => 'use SSL (LDAPS)', #format => ['yes', 'no'], #default => 'no' - obsolete => 'use_tls', # 5.3a.2 - 6.2.14 + obsolete => 'use_tls', + not_before => '5.3a.2', + not_after => '6.2.14', }, ssl_version => { context => [qw(list)], @@ -3081,6 +3246,7 @@ our %pinfo = ( synonym => {'require' => 'required'}, occurrence => '1', default => 'required', + not_before => '6.2.13', }, # ca_path # Not yet implemented # ca_file # Not yet implemented @@ -3088,11 +3254,13 @@ our %pinfo = ( context => [qw(list)], order => 3, gettext_id => "remote user", - format => '.+' + format => '.+', + not_before => '6.2.57b.1', }, user => { - context => [qw(list)], - obsolete => 'bind_dn' + context => [qw(list)], + obsolete => 'bind_dn', + not_after => '6.2.56', }, bind_password => { context => [qw(list)], @@ -3100,11 +3268,13 @@ our %pinfo = ( gettext_id => "remote password", format => '.+', field_type => 'password', - length => 10 + length => 10, + not_before => '6.2.57b.1', }, passwd => { - context => [qw(list)], - obsolete => 'bind_password' + context => [qw(list)], + obsolete => 'bind_password', + not_after => '6.2.56', }, suffix => { context => [qw(list)], @@ -3166,7 +3336,8 @@ our %pinfo = ( order => 11, gettext_id => "Time ranges when inclusion is not allowed", format_s => '$time_ranges', - occurrence => '0-1' + occurrence => '0-1', + not_before => '6.2a.16', } }, occurrence => '0-n' @@ -3210,6 +3381,7 @@ our %pinfo = ( synonym => {'yes' => 'ldaps', 'no' => 'none'}, occurrence => '1', default => 'none', + not_before => '6.2.15', }, use_ssl => { context => [qw(list)], @@ -3217,7 +3389,9 @@ our %pinfo = ( #gettext_id => 'use SSL (LDAPS)', #format => ['yes', 'no'], #default => 'no' - obsolete => 'use_tls', # 5.3a.2 - 6.2.14 + obsolete => 'use_tls', + not_before => '5.3a.2', + not_after => '6.2.14', }, ssl_version => { context => [qw(list)], @@ -3248,6 +3422,7 @@ our %pinfo = ( synonym => {'require' => 'required'}, occurrence => '1', default => 'required', + not_before => '6.2.13', }, # ca_path # Not yet implemented # ca_file # Not yet implemented @@ -3255,11 +3430,13 @@ our %pinfo = ( context => [qw(list)], order => 3, gettext_id => "remote user", - format => '.+' + format => '.+', + not_before => '6.2.57b.1', }, user => { - context => [qw(list)], - obsolete => 'bind_dn' + context => [qw(list)], + obsolete => 'bind_dn', + not_after => '6.2.56', }, bind_password => { context => [qw(list)], @@ -3267,11 +3444,13 @@ our %pinfo = ( gettext_id => "remote password", format => '.+', field_type => 'password', - length => 10 + length => 10, + not_before => '6.2.57b.1', }, passwd => { - context => [qw(list)], - obsolete => 'bind_password' + context => [qw(list)], + obsolete => 'bind_password', + not_after => '6.2.56', }, suffix1 => { context => [qw(list)], @@ -3386,7 +3565,8 @@ our %pinfo = ( order => 18, gettext_id => "Time ranges when inclusion is not allowed", format_s => '$time_ranges', - occurrence => '0-1' + occurrence => '0-1', + not_before => '6.2a.16', } }, occurrence => '0-n' @@ -3419,12 +3599,13 @@ our %pinfo = ( order => 2, gettext_id => "remote host", format_s => '$host', - # Not required for ODBC - # occurrence => '1' + # occurrence => '1', # Not required for ODBC + not_before => '6.2.57b.1', }, host => { - context => [qw(list)], - obsolete => 'db_host' + context => [qw(list)], + obsolete => 'db_host', + not_after => '6.2.56', }, db_port => { context => [qw(list)], @@ -3443,11 +3624,13 @@ our %pinfo = ( context => [qw(list)], order => 4, gettext_id => "connection options", - format => '.+' + format => '.+', + not_before => '6.2.57b.1', }, connect_options => { - context => [qw(list)], - obsolete => 'db_options' + context => [qw(list)], + obsolete => 'db_options', + not_after => '6.2.56', }, db_env => { context => [qw(list)], @@ -3460,22 +3643,26 @@ our %pinfo = ( order => 6, gettext_id => "remote user", format => '\S+', - occurrence => '1' + occurrence => '1', + not_before => '6.2.57b.1', }, user => { - context => [qw(list)], - obsolete => 'db_user' + context => [qw(list)], + obsolete => 'db_user', + not_after => '6.2.56', }, db_passwd => { context => [qw(list)], order => 7, gettext_id => "remote password", format => '.+', - field_type => 'password' + field_type => 'password', + not_before => '6.2.57b.1', }, passwd => { - context => [qw(list)], - obsolete => 'db_passwd' + context => [qw(list)], + obsolete => 'db_passwd', + not_after => '6.2.56', }, sql_query => { context => [qw(list)], @@ -3497,7 +3684,8 @@ our %pinfo = ( order => 10, gettext_id => "Time ranges when inclusion is not allowed", format_s => '$time_ranges', - occurrence => '0-1' + occurrence => '0-1', + not_before => '6.2a.16', } }, occurrence => '0-n' @@ -3517,6 +3705,11 @@ our %pinfo = ( default => '3600', length => 6 }, + default_ttl => { + context => [qw(site)], + obsolete => 'ttl', + not_after => '6.2.56', + }, distribution_ttl => { context => [qw(list site)], @@ -3535,6 +3728,8 @@ our %pinfo = ( order => 60.14, group => 'data_source', gettext_id => "LDAP query custom attribute", + occurrence => '0-n', + not_before => '6.2a.16', format => { name => { context => [qw(list)], @@ -3566,6 +3761,7 @@ our %pinfo = ( synonym => {'yes' => 'ldaps', 'no' => 'none'}, occurrence => '1', default => 'none', + not_before => '6.2.15', }, use_ssl => { context => [qw(list)], @@ -3573,7 +3769,9 @@ our %pinfo = ( #gettext_id => 'use SSL (LDAPS)', #format => ['yes', 'no'], #default => 'no' - obsolete => 'use_tls', # 6.2a? - 6.2.14 + obsolete => 'use_tls', + not_before => '6.2a?', + not_after => '6.2.14', }, ssl_version => { context => [qw(list)], @@ -3604,6 +3802,7 @@ our %pinfo = ( synonym => {'require' => 'required'}, occurrence => '1', default => 'required', + not_before => '6.2.13', }, # ca_path # Not yet implemented # ca_file # Not yet implemented @@ -3611,11 +3810,13 @@ our %pinfo = ( context => [qw(list)], order => 3, gettext_id => "remote user", - format => '.+' + format => '.+', + not_before => '6.2.57b.1', }, user => { - context => [qw(list)], - obsolete => 'bind_dn' + context => [qw(list)], + obsolete => 'bind_dn', + not_after => '6.2.56', }, bind_password => { context => [qw(list)], @@ -3623,11 +3824,13 @@ our %pinfo = ( gettext_id => "remote password", format => '.+', field_type => 'password', - length => 10 + length => 10, + not_before => '6.2.57b.1', }, passwd => { - context => [qw(list)], - obsolete => 'bind_password' + context => [qw(list)], + obsolete => 'bind_password', + not_after => '6.2.56', }, suffix => { context => [qw(list)], @@ -3699,7 +3902,6 @@ our %pinfo = ( occurrence => '0-1' } }, - occurrence => '0-n' }, include_ldap_2level_ca => { @@ -3707,6 +3909,8 @@ our %pinfo = ( order => 60.15, group => 'data_source', gettext_id => "LDAP 2-level query custom attribute", + occurrence => '0-n', + not_before => '6.2.45b.1', # added on 6.2a.16, but broken for years format => { name => { context => [qw(list)], @@ -3738,6 +3942,7 @@ our %pinfo = ( synonym => {'yes' => 'ldaps', 'no' => 'none'}, occurrence => '1', default => 'none', + not_before => '6.2.15', }, use_ssl => { context => [qw(list)], @@ -3745,7 +3950,9 @@ our %pinfo = ( #gettext_id => 'use SSL (LDAPS)', #format => ['yes', 'no'], #default => 'no' - obsolete => 'use_tls', # 6.2a? - 6.2.14 + obsolete => 'use_tls', + not_before => '6.2a?', + not_after => '6.2.14', }, ssl_version => { context => [qw(list)], @@ -3776,6 +3983,7 @@ our %pinfo = ( synonym => {'require' => 'required'}, occurrence => '1', default => 'required', + not_before => '6.2.13', }, # ca_path # Not yet implemented # ca_file # Not yet implemented @@ -3784,10 +3992,12 @@ our %pinfo = ( order => 3, gettext_id => "remote user", format => '.+', + not_before => '6.2.57b.1', }, user => { - context => [qw(list)], - obsolete => 'bind_dn' + context => [qw(list)], + obsolete => 'bind_dn', + not_after => '6.2.56', }, bind_password => { context => [qw(list)], @@ -3795,11 +4005,13 @@ our %pinfo = ( gettext_id => "remote password", format => '.+', field_type => 'password', - length => 10 + length => 10, + not_before => '6.2.57b.1', }, passwd => { - context => [qw(list)], - obsolete => 'bind_password' + context => [qw(list)], + obsolete => 'bind_password', + not_after => '6.2.56', }, suffix1 => { context => [qw(list)], @@ -3925,7 +4137,6 @@ our %pinfo = ( occurrence => '0-1' } }, - occurrence => '0-n' }, include_sql_ca => { @@ -3933,6 +4144,8 @@ our %pinfo = ( order => 60.16, group => 'data_source', gettext_id => "SQL query custom attribute", + occurrence => '0-n', + not_before => '6.2a.16', format => { name => { context => [qw(list)], @@ -3954,11 +4167,13 @@ our %pinfo = ( gettext_id => "remote host", format_s => '$host', # Not required for ODBC and SQLite. Optional for Oracle. - #occurrence => '1' + #occurrence => '1', + not_before => '6.2.57b.1', }, host => { - context => [qw(list)], - obsolete => 'db_host' + context => [qw(list)], + obsolete => 'db_host', + not_after => '6.2.56', }, db_port => { context => [qw(list)], @@ -3977,11 +4192,13 @@ our %pinfo = ( context => [qw(list)], order => 4.5, gettext_id => "connection options", - format => '.+' + format => '.+', + not_before => '6.2.57b.1', }, connect_options => { - context => [qw(list)], - obsolete => 'db_options' + context => [qw(list)], + obsolete => 'db_options', + not_after => '6.2.56', }, db_env => { context => [qw(list)], @@ -3994,22 +4211,26 @@ our %pinfo = ( order => 6, gettext_id => "remote user", format => '\S+', - occurrence => '1' + occurrence => '1', + not_before => '6.2.57b.1', }, user => { - context => [qw(list)], - obsolete => 'db_user' + context => [qw(list)], + obsolete => 'db_user', + not_after => '6.2.56', }, db_passwd => { context => [qw(list)], order => 7, gettext_id => "remote password", format => '.+', - field_type => 'password' + field_type => 'password', + not_before => '6.2.57b.1', }, passwd => { - context => [qw(list)], - obsolete => 'db_passwd' + context => [qw(list)], + obsolete => 'db_passwd', + not_after => '6.2.56', }, sql_query => { context => [qw(list)], @@ -4041,7 +4262,6 @@ our %pinfo = ( occurrence => '0-1' } }, - occurrence => '0-n' }, ### DKIM page ### @@ -4153,6 +4373,27 @@ our %pinfo = ( }, occurrence => '0-1' }, + dkim_private_key_path => { + context => [qw(domain site)], + obsolete => 'dkim_parameters.private_key_path', + not_after => '6.2.56', + }, + dkim_selector => { + context => [qw(domain site)], + obsolete => 'dkim_parameters.selector', + not_after => '6.2.56', + }, + ## Never implemented. + #dkim_header_list => { + # context => [qw(domain site)], + # obsolete => 'dkim_parameters.header_list', + # not_after => '6.2.56', + #}, + dkim_signer_domain => { + context => [qw(domain site)], + obsolete => 'dkim_parameters.signer_domain', + not_after => '6.2.56', + }, dkim_signature_apply_on => { context => [qw(list domain site)], @@ -4189,6 +4430,7 @@ our %pinfo = ( format => ['on', 'off'], occurrence => '1', default => 'off', + not_before => '6.2.37b.1', }, arc_srvid => { @@ -4197,7 +4439,8 @@ our %pinfo = ( group => 'dkim', gettext_id => 'SRV ID for Authentication-Results used in ARC seal', gettext_comment => 'Typically the domain of the mail server', - format => '\S+', # "value" defined in RFC 2045, 5.1 + format => '\S+', # "value" defined in RFC 2045, 5.1 + not_before => '6.2.37b.1', }, arc_parameters => { @@ -4207,7 +4450,9 @@ our %pinfo = ( gettext_id => "ARC configuration", gettext_comment => 'A set of parameters in order to define outgoing ARC seal', - format => { + occurrence => '0-1', + not_before => '6.2.37b.1', + format => { arc_private_key_path => { context => [qw(list domain site)], order => 1, @@ -4245,7 +4490,24 @@ our %pinfo = ( occurrence => '0-1', }, }, - occurrence => '0-1' + }, + arc_private_key_path => { + context => [qw(domain site)], + obsolete => 'arc_parameters.arc_private_key_path', + not_before => '6.2.37b.1', + not_after => '6.2.56', + }, + arc_selector => { + context => [qw(domain site)], + obsolete => 'arc_parameters.arc_selector', + not_before => '6.2.37b.1', + not_after => '6.2.56', + }, + arc_signer_domain => { + context => [qw(domain site)], + obsolete => 'arc_parameters.arc_signer_domain', + not_before => '6.2.37b.1', + not_after => '6.2.56', }, dmarc_protection => { @@ -4324,6 +4586,26 @@ our %pinfo = ( "Parameters to define how to manage From address processing to avoid some domains' excessive DMARC protection", occurrence => '0-1', }, + dmarc_protection_domain_regex => { + context => [qw(domain site)], + obsolete => 'dmarc_protection.domain_regex', + not_after => '6.2.56', + }, + dmarc_protection_mode => { + context => [qw(domain site)], + obsolete => 'dmarc_protection.mode', + not_after => '6.2.56', + }, + dmarc_protection_other_email => { + context => [qw(domain site)], + obsolete => 'dmarc_protection.other_email', + not_after => '6.2.56', + }, + dmarc_protection_phrase => { + context => [qw(domain site)], + obsolete => 'dmarc_protection.phrase', + not_after => '6.2.56', + }, ### Optional features @@ -4337,7 +4619,8 @@ our %pinfo = ( 'SMTP HELO (EHLO) parameter used for address verification', gettext_comment => 'Default value is the host part of "list_check_smtp" parameter.', - format => '\S+', + format => '\S+', + not_before => '6.2a.0', }, list_check_smtp => { context => [qw(domain site)], @@ -4437,6 +4720,7 @@ our %pinfo = ( 'This parameter is a comma-separated list of names. You can use * as a wildcard character. To use a regex for this, please use prohibited_listnames_regex setting.', sample => 'www,root,*master', #XXXsplit_char => ',', + not_before => '6.2.63b.1', }, prohibited_listnames_regex => { context => [qw(site)], @@ -4446,7 +4730,8 @@ our %pinfo = ( 'Prevent people to use some names for their lists names, based on a regex', gettext_comment => 'This parameter is a regex. Please note that prohibited_listnames and prohibited_listnames_regex will both be applied if set, they are not exclusive.', - sample => 'www|root|.*master', + sample => 'www|root|.*master', + not_before => '6.2.63b.1', }, cache_list_config => { @@ -4510,6 +4795,7 @@ our %pinfo = ( format => '\d+', gettext_unit => 'months', default => '3', + not_before => '6.2b.7', }, umask => { @@ -4532,7 +4818,7 @@ our %pinfo = ( gettext_id => "Account", format => '\S+', length => 10, - obsolete => 1, + obsolete => 1, # Maybe never implemented }, clean_delay_queuemod => { @@ -4563,6 +4849,7 @@ our %pinfo = ( field_type => 'password', length => 15, obsolete => 1, + not_after => '6.2.60', }, custom_attribute => { @@ -4695,6 +4982,11 @@ our %pinfo = ( # 'This task regularly sends subscribers a message which reminds them of their list subscriptions.', task => 'remind', }, + default_remind_task => { + context => [qw(site)], + obsolete => 'remind_task', + not_after => '6.2.56', + }, ### Other (internal attributes of the list) @@ -4714,9 +5006,10 @@ our %pinfo = ( date => { context => [qw(list)], #order => 2, - obsolete => 1, gettext_id => 'date', - format => '.+' + format => '.+', + obsolete => 1, + not_after => '6.2.16', }, date_epoch => { context => [qw(list)], @@ -4747,9 +5040,10 @@ our %pinfo = ( date => { context => [qw(list)], #order => 2, - obsolete => 1, gettext_id => "human readable", - format => '.+' + format => '.+', + obsolete => 1, + not_after => '6.2.16', }, date_epoch => { context => [qw(list)], @@ -4782,10 +5076,11 @@ our %pinfo = ( date => { context => [qw(list)], #order => 2, - obsolete => 1, gettext_id => 'date', format => '.+', - length => 30 + length => 30, + obsolete => 1, + not_after => '6.2.16', }, date_epoch => { context => [qw(list)], @@ -4839,6 +5134,7 @@ our %pinfo = ( order => 110.02, group => 'www_basic', gettext_id => 'URL prefix of WWSympa behind proxy', + not_before => '6.2.56', }, static_content_url => { context => [qw(domain site)], @@ -4880,6 +5176,7 @@ our %pinfo = ( group => 'www_basic', default_s => '$PICTURESDIR', gettext_id => 'Directory for subscribers pictures', + not_before => '6.2.25b.2', }, pictures_url => { context => [qw(site)], @@ -4889,6 +5186,7 @@ our %pinfo = ( gettext_id => 'URL for subscribers pictures', gettext_comment => 'HTTP server have to map it with "pictures_path" directory.', + not_before => '6.2.25b.2', }, mhonarc => { context => [qw(domain site)], @@ -4917,7 +5215,8 @@ our %pinfo = ( file => 'wwsympa.conf', gettext_comment => 'Is FastCGI module for HTTP server installed? This module provides a much faster web interface.', - obsolete => 1, + obsolete => 1, + not_after => '6.2.22', }, logo_html_definition => { @@ -4936,6 +5235,7 @@ our %pinfo = ( group => 'www_appearances', gettext_id => 'Custom favicon', gettext_comment => 'URL of favicon image', + not_before => '6.2a.5', }, color_0 => { @@ -5264,17 +5564,19 @@ our %pinfo = ( gettext_id => 'Enable shared repository', gettext_comment => 'If set to "on", list owners can open shared repository.', - default => 'off', + default => 'off', + not_before => '6.2.41b.2', }, #shared_doc # HTML editor - htmlarea_url => { # Deprecated on 6.2.36 + htmlarea_url => { context => [qw(site)], gettext_id => '', file => 'wwsympa.conf', obsolete => 1, + not_after => '6.2.35b.1', }, use_html_editor => { context => [qw(domain site)], @@ -5283,11 +5585,12 @@ our %pinfo = ( gettext_id => 'Use HTML editor', gettext_comment => 'If set to "on", users will be able to post messages in HTML using a javascript WYSIWYG editor.', - format => ['off', 'on'], - synonym => {'0' => 'off', '1' => 'on'}, - default => 'off', - sample => 'on', - file => 'wwsympa.conf', + format => ['off', 'on'], + synonym => {'0' => 'off', '1' => 'on'}, + default => 'off', + sample => 'on', + file => 'wwsympa.conf', + not_before => '6.2a.0', }, html_editor_url => { context => [qw(domain site)], @@ -5296,7 +5599,8 @@ our %pinfo = ( gettext_id => 'URL of HTML editor', gettext_comment => "URL path to the javascript file making the WYSIWYG HTML editor available. Relative path under or absolute path.\nExample is for TinyMCE 4 installed under /js/tinymce/.", - sample => 'js/tinymce/tinymce.min.js', + sample => 'js/tinymce/tinymce.min.js', + not_before => '6.2a.34', }, html_editor_init => { context => [qw(domain site)], @@ -5307,7 +5611,8 @@ our %pinfo = ( 'Javascript excerpt that enables and configures the WYSIWYG HTML editor.', sample => 'tinymce.init({selector:"#body",language:lang.split(/[^a-zA-Z]+/).join("_")});', - file => 'wwsympa.conf', + file => 'wwsympa.conf', + not_before => '6.2a.0', }, ##{ html_editor_hide: not yet implemented. }, ##{ html_editor_show: not yet implemented. }, @@ -5342,6 +5647,7 @@ our %pinfo = ( file => 'wwsympa.conf', gettext_comment => "\"md5\" or \"bcrypt\".\nIf set to \"md5\", Sympa will use MD5 password hashes. If set to \"bcrypt\", bcrypt hashes will be used instead. This only concerns passwords stored in the Sympa database, not the ones in LDAP.\nShould not be changed! May invalid all user passwords.", + not_before => '6.2.25b.3', }, password_hash_update => { context => [qw(site)], # per-robot config is impossible. @@ -5352,6 +5658,7 @@ our %pinfo = ( file => 'wwsympa.conf', gettext_comment => "On successful login, update the encrypted user password to use the algorithm specified by \"password_hash\". This allows for a graceful transition to a new password hash algorithm. A value of 0 disables updating of existing password hashes. New and reset passwords will use the \"password_hash\" setting in all cases.", + not_before => '6.2.25b.3', }, bcrypt_cost => { context => [qw(site)], # per-robot config is impossible. @@ -5362,6 +5669,7 @@ our %pinfo = ( file => 'wwsympa.conf', gettext_comment => "When \"password_hash\" is set to \"bcrypt\", this sets the \"cost\" parameter of the bcrypt hash function. The default of 12 is expected to require approximately 250ms to calculate the password hash on a 3.2GHz CPU. This only concerns passwords stored in the Sympa database, not the ones in LDAP.\nCan be changed but any new cost setting will only apply to new passwords.", + not_before => '6.2.25b.3', }, # One time ticket @@ -5436,6 +5744,7 @@ our %pinfo = ( gettext_id => 'Script to report spam', gettext_comment => 'If set, when a list moderator report undetected spams for list moderation, this external script is invoked and the message is injected into standard input of the script.', + not_before => '6.2a.0', }, # Various miscellaneous @@ -5449,8 +5758,14 @@ our %pinfo = ( gettext_comment => 'This parameter is a comma-separated list.', sample => 'example.org,spammer.com', split_char => ',', + not_before => '6.2.61b.1', + }, + domains_blacklist => { + context => [qw(site)], + obsolete => 'domains_blocklist', + not_before => '6.2.41b.1', + not_after => '6.2.60', }, - domains_blacklist => {obsolete => 'domains_blocklist'}, quiet_subscription => { context => [qw(site)], @@ -5459,8 +5774,9 @@ our %pinfo = ( gettext_id => 'Quiet subscriptions policy', gettext_comment => 'Global policy for quiet subscriptions: "on" means that subscriptions will never send a notice to the subscriber, "off" will enforce a notice sending, and "optional" (default) allows the use of the list policy.', - format => ['on', 'optional', 'off'], #XXX - default => 'optional', + format => ['on', 'optional', 'off'], #XXX + default => 'optional', + not_before => '6.2.41b.1', }, show_report_abuse => { @@ -5471,9 +5787,10 @@ our %pinfo = ( 'Add a "Report abuse" link in the side menu of the lists', gettext_comment => 'The link is a mailto link, you can change that by overriding web_tt2/report_abuse.tt2', - format => ['on', 'off'], - synonym => {'1' => 'on', '0' => 'off'}, - default => 'off', + format => ['on', 'off'], + synonym => {'1' => 'on', '0' => 'off'}, + default => 'off', + not_before => '6.2.37b.3', }, allow_account_deletion => { context => [qw(site)], @@ -5483,9 +5800,10 @@ our %pinfo = ( 'EXPERIMENTAL! Allow users to delete their account. If enabled, shows a "delete my account" form in user\'s preferences page.', gettext_comment => 'Account deletion unsubscribes the users from his/her lists and removes him/her from lists ownership. It is only available to users using internal authentication (i.e. no LDAP, no SSO...). See https://github.com/sympa-community/sympa/issues/300 for details', - format => ['on', 'off'], - synonym => {'1' => 'on', '0' => 'off'}, - default => 'off', + format => ['on', 'off'], + synonym => {'1' => 'on', '0' => 'off'}, + default => 'off', + not_before => '6.2.41b.1', }, # Web interface: Optional features @@ -5499,6 +5817,7 @@ our %pinfo = ( 'The password validation techniques to be used against user passwords that are added to mailing lists. Options come from Data::Password (http://search.cpan.org/~razinf/Data-Password-1.07/Password.pm#VARIABLES)', sample => 'MINLEN=8,GROUPS=3,DICTIONARY=4,DICTIONARIES=/pentest/dictionaries', + not_before => '6.1.23', }, ldap_force_canonical_email => { @@ -5526,6 +5845,7 @@ our %pinfo = ( order => 156.02, group => 'sympasoap', gettext_id => 'URL of SympaSOAP behind proxy', + not_before => '6.2.19b.1', }, #### End of living parameters #### @@ -5560,52 +5880,157 @@ our %pinfo = ( ## Obsoleted parameters - trusted_ca_options => $site_obsolete, # cf. capath & cafile - msgcat => $site_obsolete, - queueexpire => $site_obsolete, - clean_delay_queueother => $site_obsolete, - web_recode_to => $site_obsolete, # ??? - 5.2 - localedir => $site_obsolete, - ldap_export_connection_timeout => $site_obsolete, # 3.3b3 - 4.1? - ldap_export_dnmanager => $site_obsolete, # ,, - ldap_export_host => $site_obsolete, # ,, - ldap_export_name => $site_obsolete, # ,, - ldap_export_password => $site_obsolete, # ,, - ldap_export_suffix => $site_obsolete, # ,, - tri => $site_obsolete, # ??? - 1.3.4-1 - sort => $site_obsolete, # 1.4.0 - ??? - pidfile => $site_obsolete, # ??? - 6.1.17 - pidfile_distribute => $site_obsolete, # ,, - pidfile_creation => $site_obsolete, # ,, - pidfile_bulk => $site_obsolete, # ,, - archived_pidfile => $site_obsolete, # ,, - bounced_pidfile => $site_obsolete, # ,, - task_manager_pidfile => $site_obsolete, # ,, - email_gecos => $site_obsolete, # 6.2a.?? - 6.2a.33 - lock_method => $site_obsolete, # 5.3b.3 - 6.2a.33 - html_editor_file => $site_obsolete, # 6.2a - openssl => $site_obsolete, # ?? - 6.2a.40 - distribution_mode => $site_obsolete, # 5.0a.1 - 6.2a.40 - queuedistribute => $site_obsolete, # ,, + trusted_ca_options => { + %site_obsolete, + not_after => '3.3.5', # cf. capath & cafile + }, + msgcat => { + %site_obsolete, + not_after => '4.2b.1', # cf. localedir + }, + queueexpire => {%site_obsolete, not_after => '5.1.2',}, + clean_delay_queueother => { + %site_obsolete, + not_before => '5.4a.9', + not_after => '5.4.7', + }, + web_recode_to => { + %site_obsolete, + not_before => '???', + not_after => '5.2', # cf. filesystem_encoding + }, + localedir => { + %site_obsolete, + not_before => '4.2b.2', + not_after => '6.2a.32', + }, + ldap_export_connection_timeout => { + %site_obsolete, + not_before => '3.3b.3', + not_after => '4.1?', + }, + ldap_export_dnmanager => { + %site_obsolete, + not_before => '3.3b.3', + not_after => '4.1?', + }, + ldap_export_host => { + %site_obsolete, + not_before => '3.3b.3', + not_after => '4.1?', + }, + ldap_export_name => { + %site_obsolete, + not_before => '3.3b.3', + not_after => '4.1?', + }, + ldap_export_password => { + %site_obsolete, + not_before => '3.3b.3', + not_after => '4.1?', + }, + ldap_export_suffix => { + %site_obsolete, + not_before => '3.3b.3', + not_after => '4.1?', + }, + tri => { + %site_obsolete, + not_before => '???', + not_after => '1.3.4-1', + }, + sort => { + %site_obsolete, + not_before => '1.4.0', + not_after => '???', + }, + pidfile => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + pidfile_distribute => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + pidfile_creation => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + pidfile_bulk => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + archived_pidfile => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + bounced_pidfile => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + task_manager_pidfile => { + %site_obsolete, + not_before => '???', + not_after => '6.1.17', + }, + lock_method => { + %site_obsolete, + not_before => '5.3b.3', + not_after => '6.2a.33', + }, + html_editor_file => { + %site_obsolete, + not_before => '6.0a.0', + not_after => '6.2a.33', # cf. html_editor_url + }, + openssl => { + %site_obsolete, + not_before => '???', + not_after => '6.2a.40', + }, + distribution_mode => { + %site_obsolete, + not_before => '5.0a.1', + not_after => '6.2a.40', + }, + queuedistribute => { + %site_obsolete, + not_before => '5.0a.1', + not_after => '6.2a.40', + }, log_condition => { - context => [qw(domain site)], - file => 'wwsympa.conf', - obsolete => 1, # 6.2a.29 - 6.2.41b.1 + context => [qw(domain site)], + file => 'wwsympa.conf', + obsolete => 1, + not_before => '6.2a.29', + not_after => '6.2.41b.1', }, log_module => { - context => [qw(domain site)], - file => 'wwsympa.conf', - obsolete => 1, # 6.2a.29 - 6.2.41b.1 + context => [qw(domain site)], + file => 'wwsympa.conf', + obsolete => 1, + not_before => '6.2a.29', + not_after => '6.2.41b.1', }, filesystem_encoding => { - context => [qw(site)], - default => 'utf-8', - obsolete => 1, # 5.3a.7 - 6.2.52 + context => [qw(site)], + default => 'utf-8', + obsolete => 1, + not_before => '5.3a.7', + not_after => '6.2.52', }, http_host => { - context => [qw(domain site)], - obsolete => 1, # ?? - 6.2.54 + context => [qw(domain site)], + obsolete => 1, + not_before => '???', + not_after => '6.2.54', # cf. wwsympa_url_local }, ); @@ -5817,41 +6242,6 @@ our %user_info = ( }, ); -our %obsolete_robot_params = ( - arc_private_key_path => 'arc_parameters.arc_private_key_path', - arc_selector => 'arc_parameters.arc_selector', - arc_signer_domain => 'arc_parameters.arc_signer_domain', - archive_mail_access => 'archive.mail_access', - archive_web_access => 'archive.web_access', - bounce_halt_rate => 'bounce.halt_rate', - bounce_warn_rate => 'bounce.warn_rate', - d_edit => 'shared_doc.d_edit', - d_read => 'shared_doc.d_read', - default_archive_quota => 'archive.quota', - default_bounce_level1_rate => 'bouncers_level1.rate', - default_bounce_level2_rate => 'bouncers_level2.rate', - default_list_priority => 'priority', - default_max_list_members => 'max_list_members', - default_remind_task => 'remind_task', - default_shared_quota => 'shared_doc.quota', - default_sql_fetch_timeout => 'sql_fetch_timeout', - default_ttl => 'ttl', - dkim_header_list => 'dkim_parameters.header_list', - dkim_private_key_path => 'dkim_parameters.private_key_path', - dkim_selector => 'dkim_parameters.selector', - dkim_signer_domain => 'dkim_parameters.signer_domain', - dmarc_protection_domain_regex => 'dmarc_protection.domain_regex', - dmarc_protection_mode => 'dmarc_protection.mode', - dmarc_protection_other_email => 'dmarc_protection.other_email', - dmarc_protection_phrase => 'dmarc_protection.phrase', - tracking => 'tracking.tracking', - tracking_default_retention_period => 'tracking.retention_period', - tracking_delivery_status_notification => - 'tracking.delivery_status_notification', - tracking_message_disposition_notification => - 'tracking.message_disposition_notification', -); - _apply_defaults(); ## Apply defaults to parameters definition (%pinfo) @@ -6127,7 +6517,7 @@ Obsolete parameter ; should not be displayed nor saved. As of 6.2.16, if the value is true value and is not C<1>, -defines parameter alias name mainly for backward compatibility. +it defines reference to a fully upper-compatible new parameter. =item obsolete_values @@ -6137,6 +6527,13 @@ Defined obsolete values for a parameter. These values should not get proposed on the web interface edition form. +=item not_before, not_after + +The duration between these versions (inclusive) during which the parameter +is available. + +Introduced on Sympa 6.2.65b. + =item order Order of parameters within paragraph. diff --git a/src/lib/Sympa/Upgrade.pm b/src/lib/Sympa/Upgrade.pm index 1e3a38d5d..474373f7c 100644 --- a/src/lib/Sympa/Upgrade.pm +++ b/src/lib/Sympa/Upgrade.pm @@ -2183,6 +2183,39 @@ sub upgrade { $log->syslog('notice', '...Done.'); } + if (lower_version($previous_version, '6.2.65b.1')) { + # Site/domain parameter "tracking" has been deprecated and + # should be renamed to "tracking.tracking" to avoid conflict with + # list config paragraph named "tracking". + + _process_all_files( + '', + sub { + my $that = shift; + my $dir = shift; + my $oldfile = shift; + + my $file; + if (ref $that eq 'Sympa::List') { + return; + } elsif ($that and $that ne '*') { + $file = sprintf '%s/robot.conf', $dir; + } else { + $file = Sympa::Constants::CONFIG(); + } + + open my $fh, '<+', $file or next; + + my $text = do { local $RS; <$fh> }; + $text =~ s/(\A|\n)tracking(\s|\z)/${1}tracking.tracking$2/g; + seek $fh, 0, 0; + truncate $fh, 0; + print $fh $text; + close $fh; + } + ); + } + return 1; }