) {
$mail->{'body'} .= $_;
}
}
-close(QUEUE);
+close($queuefh);
$mail->{'headers'} = \@headers;
-foreach $h (@headers) {
+foreach my $h (@headers) {
$mail->{'header'}->{lc($h->[0])} = $h->[1];
}
$mail->{'file'} = $file;
@@ -1553,11 +1579,11 @@ return $mail;
# recurse_files(dir)
sub recurse_files
{
-opendir(DIR, &translate_filename($_[0])) || return ( $_[0] );
-local @dir = readdir(DIR);
-closedir(DIR);
-local ($f, @rv);
-foreach $f (@dir) {
+opendir(my $dirh, &translate_filename($_[0])) || return ( $_[0] );
+my @dir = readdir($dirh);
+closedir($dirh);
+my @rv;
+foreach my $f (@dir) {
push(@rv, &recurse_files("$_[0]/$f")) if ($f !~ /^\./);
}
return @rv;
@@ -1565,7 +1591,7 @@ return @rv;
sub sort_by_domain
{
-local ($a1, $a2, $b1, $b2);
+my ($a1, $a2, $b1, $b2);
if ($a->{'name'} =~ /^(.*)\@(.*)$/ && (($a1, $a2) = ($1, $2)) &&
$b->{'name'} =~ /^(.*)\@(.*)$/ && (($b1, $b2) = ($1, $2))) {
return $a2 cmp $b2 ? $a2 cmp $b2 : $a1 cmp $b1;
@@ -1589,7 +1615,7 @@ if ($config{'check_config'} && !defined($save_file)) {
sub after_save
{
if (defined($save_file)) {
- local $err = &check_postfix();
+ my $err = &check_postfix();
if ($err) {
©_source_dest($save_file, $config{'postfix_config_file'});
&unlink_file($save_file);
@@ -1627,9 +1653,10 @@ sub ensure_map
{
foreach my $mf (&get_maps_files(&get_real_value($_[0]))) {
if ($mf =~ /^\// && !-e $mf) {
- &open_lock_tempfile(TOUCH, ">$mf", 1) ||
+ my $touchfh = "TOUCH";
+ &open_lock_tempfile($touchfh, ">$mf", 1) ||
&error(&text("efilewrite", $mf, $!));
- &close_tempfile(TOUCH);
+ &close_tempfile($touchfh);
&set_ownership_permissions(undef, undef, 0755, $mf);
}
}
@@ -1650,7 +1677,7 @@ return $_[1]->{'name'};
sub edit_value_header_checks
{
-local ($act, $dest) = split(/\s+/, $_[0]->{'value'}, 2);
+my ($act, $dest) = split(/\s+/, $_[0]->{'value'}, 2);
return &ui_table_row($text{'header_value'},
&ui_select("action", $act,
[ map { [ $_, $text{'header_'.lc($_)} ] }
@@ -1660,7 +1687,7 @@ return &ui_table_row($text{'header_value'},
sub parse_value_header_checks
{
-local $rv = $_[1]->{'action'};
+my $rv = $_[1]->{'action'};
if ($_[1]->{'value'}) {
$rv .= " ".$_[1]->{'value'};
}
@@ -1716,7 +1743,7 @@ return "| $text{'access_addresses'} | \n".
sub edit_value_check_sender_access
{
-local ($act, $dest) = split(/\s+/, $_[0]->{'value'}, 2);
+my ($act, $dest) = split(/\s+/, $_[0]->{'value'}, 2);
return "$text{'header_value'} | \n".
"".&ui_select("action", $act,
[ map { [ $_, $text{'header_'.lc($_)} ] }
@@ -1742,10 +1769,11 @@ sub get_master_config
{
if (!scalar(@master_config_cache)) {
@master_config_cache = ( );
- local $lnum = 0;
- local $prog;
- open(MASTER, "<".$config{'postfix_master'});
- while() {
+ my $lnum = 0;
+ my $prog;
+ open(my $masterfh, "<", $config{'postfix_master'}) ||
+ return \@master_config_cache;
+ while(<$masterfh>) {
s/\r|\n//g;
if (/^(#?)\s*(\S+)\s+(inet|unix|fifo)\s+(y|n|\-)\s+(y|n|\-)\s+(y|n|\-)\s+(\S+)\s+(\S+)\s+(.*)$/) {
# A program line
@@ -1772,7 +1800,7 @@ if (!scalar(@master_config_cache)) {
}
$lnum++;
}
- close(MASTER);
+ close($masterfh);
}
return \@master_config_cache;
}
@@ -1781,9 +1809,9 @@ return \@master_config_cache;
# Adds a new Postfix server process
sub create_master
{
-local ($master) = @_;
-local $conf = &get_master_config();
-local $lref = &read_file_lines($config{'postfix_master'});
+my ($master) = @_;
+my $conf = &get_master_config();
+my $lref = &read_file_lines($config{'postfix_master'});
push(@$lref, &master_line($master));
&flush_file_lines($config{'postfix_master'});
$master->{'line'} = scalar(@$lref)-1;
@@ -1795,10 +1823,10 @@ push(@$conf, $master);
# Removes one Postfix server process
sub delete_master
{
-local ($master) = @_;
-local $conf = &get_master_config();
-local $lref = &read_file_lines($config{'postfix_master'});
-local $lines = $master->{'eline'} - $master->{'line'} + 1;
+my ($master) = @_;
+my $conf = &get_master_config();
+my $lref = &read_file_lines($config{'postfix_master'});
+my $lines = $master->{'eline'} - $master->{'line'} + 1;
splice(@$lref, $master->{'line'}, $lines);
&flush_file_lines($config{'postfix_master'});
@$conf = grep { $_ ne $master } @$conf;
@@ -1814,10 +1842,10 @@ foreach my $c (@$conf) {
# Updates one Postfix server process
sub modify_master
{
-local ($master) = @_;
-local $conf = &get_master_config();
-local $lref = &read_file_lines($config{'postfix_master'});
-local $lines = $master->{'eline'} - $master->{'line'} + 1;
+my ($master) = @_;
+my $conf = &get_master_config();
+my $lref = &read_file_lines($config{'postfix_master'});
+my $lines = $master->{'eline'} - $master->{'line'} + 1;
splice(@$lref, $master->{'line'}, $lines,
&master_line($master));
&flush_file_lines($config{'postfix_master'});
@@ -1832,7 +1860,7 @@ foreach my $c (@$conf) {
# master_line(&master)
sub master_line
{
-local ($prog) = @_;
+my ($prog) = @_;
return ($prog->{'enabled'} ? "" : "#").
join("\t", $prog->{'name'}, $prog->{'type'}, $prog->{'private'},
$prog->{'unpriv'}, $prog->{'chroot'}, $prog->{'wakeup'},
@@ -1841,7 +1869,7 @@ return ($prog->{'enabled'} ? "" : "#").
sub redirect_to_map_list
{
-local ($map_name) = @_;
+my ($map_name) = @_;
if ($map_name =~ /sender_dependent_default_transport_maps/) {
redirect("dependent.cgi");
}
@@ -1861,7 +1889,7 @@ else { &redirect(""); }
sub regenerate_map_table
{
-local ($map_name) = @_;
+my ($map_name) = @_;
if ($map_name =~ /canonical/) { ®enerate_canonical_table(); }
if ($map_name =~ /relocated/) { ®enerate_relocated_table(); }
if ($map_name =~ /virtual/) { ®enerate_virtual_table(); }
@@ -1889,16 +1917,16 @@ if ($map_name =~ /smtpd_sender_restrictions/) {
# Print a table of queued mail messages
sub mailq_table
{
-local ($qfiles) = @_;
+my ($qfiles) = @_;
# Build table data
my @table;
foreach my $q (@$qfiles) {
- local @cols;
+ my @cols;
push(@cols, { 'type' => 'checkbox', 'name' => 'file',
'value' => $q->{'id'} });
push(@cols, &ui_link("view_mailq.cgi?id=$q->{'id'}",$q->{'id'}));
- local $size = &nice_size($q->{'size'});
+ my $size = &nice_size($q->{'size'});
push(@cols, $q->{'date'});
push(@cols, &html_escape($q->{'from'}));
push(@cols, &html_escape($q->{'to'}));
@@ -1931,7 +1959,7 @@ print &ui_form_columns_table("delete_queues.cgi",
# Returns the comment text if a line contains a comment, like # foo
sub is_table_comment
{
-local ($line, $force) = @_;
+my ($line, $force) = @_;
if ($config{'prefix_cmts'} || $force) {
return $line =~ /^\s*#+\s*Webmin:\s*(.*)/ ? $1 : undef;
}
@@ -1944,7 +1972,7 @@ else {
# Returns an array of lines for a comment in a map file, like # foo
sub make_table_comment
{
-local ($cmt, $force) = @_;
+my ($cmt, $force) = @_;
if (!$cmt) {
return ( );
}
@@ -1976,7 +2004,7 @@ sub unlock_postfix_files
# Returns HTML for a button for popping up a map file chooser
sub map_chooser_button
{
-local ($name, $mapname) = @_;
+my ($name, $mapname) = @_;
return &popup_window_button("map_chooser.cgi?mapname=$mapname", 1024, 600, 1,
[ [ "ifield", $name, "map" ] ]);
}
@@ -2000,7 +2028,7 @@ return @rv;
# Returns a list of global MySQL source names in main.cf
sub list_mysql_sources
{
-local @rv;
+my @rv;
my $lref = &read_file_lines($config{'postfix_config_file'});
foreach my $l (@$lref) {
if ($l =~ /^\s*(\S+)_dbname\s*=/) {
@@ -2015,9 +2043,9 @@ return @rv;
# config file.
sub get_backend_config
{
-local ($file) = @_;
-local %rv;
-local $lref = &read_file_lines($file, 1);
+my ($file) = @_;
+my %rv;
+my $lref = &read_file_lines($file, 1);
foreach my $l (@$lref) {
if ($l =~ /^\s*([a-z0-9\_]+)\s*=\s*(.*)/i) {
$rv{$1} = $2;
@@ -2030,9 +2058,9 @@ return \%rv;
# Updates one setting in a backend config file
sub save_backend_config
{
-local ($file, $name, $value) = @_;
-local $lref = &read_file_lines($file);
-local $found = 0;
+my ($file, $name, $value) = @_;
+my $lref = &read_file_lines($file);
+my $found = 0;
for(my $i=0; $i<@$lref; $i++) {
if ($lref->[$i] =~ /^\s*([a-z0-9\_]+)\s*=\s*(.*)/i &&
$1 eq $name) {
@@ -2056,16 +2084,16 @@ if (!$found && defined($value)) {
# Checks if some map (such as a database) can be accessed
sub can_access_map
{
-local ($type, $value) = @_;
+my ($type, $value) = @_;
if (&file_map_type($type)) {
- return undef; # Always can
+ return; # Always can
}
elsif ($type eq "mysql") {
# Parse config, connect to DB
- local $conf;
+ my $conf;
if ($value =~ /^[\/\.]/) {
# Config file
- local $cfile = $value;
+ my $cfile = $value;
if ($cfile !~ /^\//) {
$cfile = &guess_config_dir()."/".$cfile;
}
@@ -2085,11 +2113,11 @@ elsif ($type eq "mysql") {
}
}
# Try a connect, and a query
- local $dbh = &connect_mysql_db($conf);
+ my $dbh = &connect_mysql_db($conf);
if (!ref($dbh)) {
return $dbh;
}
- local $cmd = $dbh->prepare("select ".$conf->{'select_field'}." ".
+ my $cmd = $dbh->prepare("select ".$conf->{'select_field'}." ".
"from ".$conf->{'table'}." ".
"where ".$conf->{'where_field'}." = ".
$conf->{'where_field'}." ".
@@ -2101,21 +2129,21 @@ elsif ($type eq "mysql") {
}
$cmd->finish();
$dbh->disconnect();
- return undef;
+ return;
}
elsif ($type eq "ldap") {
# Parse config, connect to LDAP server
- local $conf = &ldap_value_to_conf($value);
+ my $conf = &ldap_value_to_conf($value);
$conf->{'search_base'} || return &text('ldap_esource', $value);
# Try a connect and a search
- local $ldap = &connect_ldap_db($conf);
+ my $ldap = &connect_ldap_db($conf);
if (!ref($ldap)) {
return $ldap;
}
- local @classes = split(/\s+/, $config{'ldap_class'} ||
+ my @classes = split(/\s+/, $config{'ldap_class'} ||
"inetLocalMailRecipient");
- local $rv = $ldap->search(base => $conf->{'search_base'},
+ my $rv = $ldap->search(base => $conf->{'search_base'},
filter => "(objectClass=$classes[0])",
sizelimit => 1);
if (!$rv || $rv->code && !$rv->all_entries) {
@@ -2123,7 +2151,7 @@ elsif ($type eq "ldap") {
$rv ? $rv->error : "Unknown search error");
}
- return undef;
+ return;
}
else {
return &text('map_unknown', "$type");
@@ -2135,21 +2163,16 @@ else {
# a driver handle on success, or an error message string on failure.
sub connect_mysql_db
{
-local ($conf) = @_;
-local $driver = "mysql";
-local $drh;
-eval <install_driver(\$driver);
-EOF
-if ($@) {
- return &text('mysql_edriver', "DBD::$driver");
- }
-local @hosts = split(/\s+/, $config{'mysql_hosts'} || $conf->{'hosts'});
+my ($conf) = @_;
+my $driver = "mysql";
+my $drh;
+eval { require DBI; DBI->import; $drh = DBI->install_driver($driver); 1 }
+ or return &text('mysql_edriver', "DBD::$driver");
+my @hosts = split(/\s+/, $config{'mysql_hosts'} || $conf->{'hosts'});
@hosts = ( undef ) if (!@hosts); # Localhost only
-local $dbh;
+my $dbh;
foreach my $host (@hosts) {
- local $dbistr = "database=$conf->{'dbname'}";
+ my $dbistr = "database=$conf->{'dbname'}";
if ($host =~ /^unix:(.*)$/) {
# Socket file
$dbistr .= ";mysql_socket=$1";
@@ -2174,19 +2197,17 @@ return $dbh;
# a driver handle on success, or an error message string on failure.
sub connect_ldap_db
{
-local ($conf) = @_;
+my ($conf) = @_;
if (defined($connect_ldap_db_cache)) {
return $connect_ldap_db_cache;
}
-eval "use Net::LDAP";
-if ($@) {
- return &text('ldap_eldapmod', "Net::LDAP");
- }
-local @servers = split(/\s+/, $config{'ldap_host'} ||
+eval { require Net::LDAP; Net::LDAP->import; 1 }
+ or return &text('ldap_eldapmod', "Net::LDAP");
+my @servers = split(/\s+/, $config{'ldap_host'} ||
$conf->{'server_host'} || "localhost");
-local ($ldap, $lasterr);
+my ($ldap, $lasterr);
foreach my $server (@servers) {
- local ($host, $port, $tls);
+ my ($host, $port, $tls);
if ($server =~ /^(\S+):(\d+)$/) {
# Host and port
($host, $port) = ($1, $2);
@@ -2213,7 +2234,7 @@ foreach my $server (@servers) {
$ldap->start_tls;
}
if ($conf->{'bind'} eq 'yes' || $config{'ldap_user'}) {
- local $mesg = $ldap->bind(
+ my $mesg = $ldap->bind(
dn => $config{'ldap_user'} || $conf->{'bind_dn'},
password => $config{'ldap_pass'} || $conf->{'bind_pw'});
if (!$mesg || $mesg->code) {
@@ -2242,11 +2263,11 @@ else {
# Converts a MySQL config file or source name to a config hash ref
sub mysql_value_to_conf
{
-local ($value) = @_;
-local $conf;
+my ($value) = @_;
+my $conf;
if ($value =~ /^[\/\.]/) {
# Config file
- local $cfile = $value;
+ my $cfile = $value;
if ($cfile !~ /^\//) {
$cfile = &guess_config_dir()."/".$cfile;
}
@@ -2268,7 +2289,7 @@ else {
foreach my $k ("hosts", "dbname", "user", "password", "query",
"table", "where_field", "select_field",
"additional_conditions") {
- local $v = &get_real_value($value."_".$k);
+ my $v = &get_real_value($value."_".$k);
$conf->{$k} = $v;
}
if ($conf->{'query'} =~ /^select\s+(\S+)\s+from\s+(\S+)\s+where\s+(\S+)\s*=\s*'\%s'\s*(.*)/i && !$conf->{'table'}) {
@@ -2286,9 +2307,9 @@ return $conf;
# Converts an LDAP config file name to a config hash ref
sub ldap_value_to_conf
{
-local ($value) = @_;
-local $conf;
-local $cfile = $value;
+my ($value) = @_;
+my $conf;
+my $cfile = $value;
if ($cfile !~ /^\//) {
$cfile = &guess_config_dir()."/".$cfile;
}
@@ -2300,7 +2321,7 @@ return &get_backend_config($cfile);
# Returns 1 if some map can have comments. Not allowed for MySQL and LDAP.
sub can_map_comments
{
-local ($name) = @_;
+my ($name) = @_;
foreach my $tv (&get_maps_types_files(&get_real_value($name))) {
return 0 if (!&file_map_type($tv->[0]));
}
@@ -2311,7 +2332,7 @@ return 1;
# Returns 1 if osme map has a file that can be manually edited
sub can_map_manual
{
-local ($name) = @_;
+my ($name) = @_;
foreach my $tv (&get_maps_types_files(&get_real_value($name))) {
return 0 if (!&file_map_type($tv->[0]));
}
@@ -2322,15 +2343,15 @@ return 1;
# Returns 1 if a map of some type is supported by Postfix
sub supports_map_type
{
-local ($type) = @_;
+my ($type) = @_;
if (!scalar(@supports_map_type_cache)) {
- @supports_map_type = ( );
- open(POSTCONF, "$config{'postfix_config_command'} -m |");
- while() {
+ @supports_map_type_cache = ( );
+ open(my $postconffh, "-|", "$config{'postfix_config_command'} -m");
+ while(<$postconffh>) {
s/\r|\n//g;
push(@supports_map_type_cache, $_);
}
- close(POSTCONF);
+ close($postconffh);
}
return &indexoflc($type, @supports_map_type_cache) >= 0;
}
@@ -2339,17 +2360,16 @@ return &indexoflc($type, @supports_map_type_cache) >= 0;
# Converts multiple lines of text into LDAP attributes
sub split_props
{
-local ($text) = @_;
-local %pmap;
-foreach $p (split(/\t+/, $text)) {
+my ($text) = @_;
+my %pmap;
+foreach my $p (split(/\t+/, $text)) {
if ($p =~ /^(\S+):\s*(.*)/) {
push(@{$pmap{$1}}, $2);
}
}
-local @rv;
-local $k;
-foreach $k (keys %pmap) {
- local $v = $pmap{$k};
+my @rv;
+foreach my $k (keys %pmap) {
+ my $v = $pmap{$k};
if (@$v == 1) {
push(@rv, $k, $v->[0]);
}
@@ -2402,7 +2422,7 @@ return ( "check_client_access",
sub file_map_type
{
-local ($type) = @_;
+my ($type) = @_;
return 1 if ($type eq 'hash' || $type eq 'regexp' || $type eq 'pcre' ||
$type eq 'btree' || $type eq 'dbm' || $type eq 'cidr' ||
$type eq 'lmdb');
@@ -2413,13 +2433,13 @@ return 0;
# Looks up the value of a named property in a list
sub in_props
{
-local ($props, $name) = @_;
+my ($props, $name) = @_;
for(my $i=0; $i<@$props; $i++) {
if (lc($props->[$i]) eq lc($name)) {
return $props->[$i+1];
}
}
-return undef;
+return;
}
# For calling from aliases-lib only
@@ -2460,13 +2480,13 @@ push(@rv, &get_maps_files("relay_recipient_maps"));
push(@rv, &get_maps_files("smtpd_sender_restrictions"));
# Add other files in /etc/postfix
-local $cdir = &guess_config_dir();
-opendir(DIR, $cdir);
-foreach $f (readdir(DIR)) {
+my $cdir = &guess_config_dir();
+opendir(my $cdirh, $cdir);
+foreach my $f (readdir($cdirh)) {
next if ($f eq "." || $f eq ".." || $f =~ /\.(db|dir|pag)$/i);
push(@rv, "$cdir/$f");
}
-closedir(DIR);
+closedir($cdirh);
# Add TLS files
foreach my $o ("smtpd_tls_cert_file", "smtpd_tls_key_file","smtpd_tls_CAfile") {
diff --git a/postfix/postinstall.pl b/postfix/postinstall.pl
index 9868e8e00..e5dccb485 100644
--- a/postfix/postinstall.pl
+++ b/postfix/postinstall.pl
@@ -1,4 +1,7 @@
-require 'postfix-lib.pl';
+require 'postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($version_file);
sub module_install
{
diff --git a/postfix/rate.cgi b/postfix/rate.cgi
index 10177941b..968f9e14a 100755
--- a/postfix/rate.cgi
+++ b/postfix/rate.cgi
@@ -7,7 +7,10 @@
#
# << Here are all options seen in Postfix sample-rate.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($default, $no_, $none, %access, %text);
$access{'rate'} || &error($text{'rate_ecannot'});
diff --git a/postfix/reload.cgi b/postfix/reload.cgi
index bf914aad0..28f60e8f7 100755
--- a/postfix/reload.cgi
+++ b/postfix/reload.cgi
@@ -1,7 +1,10 @@
#!/usr/local/bin/perl
# Have Postfix re-read its config
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %text);
$access{'startstop'} || &error($text{'reload_ecannot'});
&error_setup($text{'reload_efailed'});
diff --git a/postfix/relocated.cgi b/postfix/relocated.cgi
index 9207ac74e..dcf1c8c3f 100755
--- a/postfix/relocated.cgi
+++ b/postfix/relocated.cgi
@@ -8,7 +8,10 @@
# << Here are all options seen in Postfix sample-relocated.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our (%access, %text);
&ReadParse();
$access{'relocated'} || &error($text{'relocated_ecannot'});
diff --git a/postfix/resource.cgi b/postfix/resource.cgi
index 03b48b0b0..3add23440 100755
--- a/postfix/resource.cgi
+++ b/postfix/resource.cgi
@@ -7,7 +7,10 @@
#
# << Here are all options seen in Postfix sample-resource.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($default, $no_, $none, %access, %text);
$access{'resource'} || &error($text{'resource_ecannot'});
diff --git a/postfix/sasl.cgi b/postfix/sasl.cgi
index 863751487..0009f4a2d 100755
--- a/postfix/sasl.cgi
+++ b/postfix/sasl.cgi
@@ -1,7 +1,10 @@
#!/usr/local/bin/perl
# Show SMTP authentication related parameters
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($default, $level, $no_, $none, $pmap, $postfix_version, $rh, $rpass, $ruser, %access, @cbs, %opts, %recip, %relay, %text);
$access{'sasl'} || &error($text{'sasl_ecannot'});
&ui_print_header(undef, $text{'sasl_title'}, "");
@@ -23,7 +26,7 @@ print &ui_table_start($text{'sasl_title'}, "width=100%", 2);
%opts = map { $_, 1 }
split(/[\s,]+/, &get_current_value("smtpd_sasl_security_options"));
@cbs = ( );
-foreach $o ("noanonymous", "noplaintext", "noactive", "nodictionary", "forward_secrecy") {
+foreach my $o ("noanonymous", "noplaintext", "noactive", "nodictionary", "forward_secrecy") {
push(@cbs, &ui_checkbox("sasl_opts", $o, $text{'sasl_'.$o}, $opts{$o}));
}
print &ui_table_row($text{'sasl_opts'}, join(" \n", @cbs), 3);
@@ -32,7 +35,7 @@ print &ui_table_row($text{'sasl_opts'}, join(" \n", @cbs), 3);
%recip = map { $_, 1 }
split(/[\s,]+/, &get_current_value("smtpd_recipient_restrictions"));
@cbs = ( );
-foreach $o (&list_smtpd_restrictions()) {
+foreach my $o (&list_smtpd_restrictions()) {
push(@cbs, &ui_checkbox("sasl_recip", $o, $text{'sasl_'.$o},
$recip{$o}));
}
@@ -42,7 +45,7 @@ print &ui_table_row($text{'sasl_recip'}, join(" \n", @cbs), 3);
%relay = map { $_, 1 }
split(/[\s,]+/, &get_current_value("smtpd_relay_restrictions"));
@cbs = ( );
-foreach $o (&list_smtpd_restrictions()) {
+foreach my $o (&list_smtpd_restrictions()) {
push(@cbs, &ui_checkbox("sasl_relay", $o, $text{'sasl_'.$o},
$relay{$o}));
}
diff --git a/postfix/save_alias.cgi b/postfix/save_alias.cgi
index 75dd700f6..ebe35bfc7 100755
--- a/postfix/save_alias.cgi
+++ b/postfix/save_alias.cgi
@@ -6,7 +6,10 @@
# Save, modify, delete an alias for Postfix
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, $i, $loga, $module_config_directory, $t, $v, %access, @afiles, @aliases, %in, %newa, %text, @values);
&ReadParse();
$access{'aliases'} || &error($text{'aliases_ecannot'});
@@ -15,21 +18,22 @@ $access{'aliases'} || &error($text{'aliases_ecannot'});
# Get the alias (if editing or deleting)
@afiles = &get_aliases_files(&get_current_value("alias_maps"));
@aliases = &list_postfix_aliases();
+my $alias;
if (!$in{'new'}) {
- $a = $aliases[$in{'num'}];
+ $alias = $aliases[$in{'num'}];
}
&lock_alias_files(\@afiles);
if ($in{'delete'}) {
# delete some alias
- &delete_postfix_alias($a);
- $loga = $a;
+ &delete_postfix_alias($alias);
+ $loga = $alias;
}
else {
# saving or creating .. check inputs
$in{'name'} =~ /^[^:@ ]+$/ ||
&error(&text('asave_eaddr', $in{'name'}));
- if ($in{'new'} || uc($a->{'name'}) ne uc($in{'name'})) {
+ if ($in{'new'} || uc($alias->{'name'}) ne uc($in{'name'})) {
# is this name taken?
for($i=0; $i<@aliases; $i++) {
if (uc($in{'name'}) eq uc($aliases[$i]->{'name'})) {
@@ -86,7 +90,7 @@ else {
&create_postfix_alias(\%newa);
}
else {
- &modify_postfix_alias($a, \%newa);
+ &modify_postfix_alias($alias, \%newa);
}
$loga = \%newa;
}
diff --git a/postfix/save_client.cgi b/postfix/save_client.cgi
index b5ccd2852..fc14789c8 100755
--- a/postfix/save_client.cgi
+++ b/postfix/save_client.cgi
@@ -1,7 +1,10 @@
#!/usr/local/bin/perl
# Save SMTP authentication options
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %newopts, %oldopts, @opts, %text, @v);
&ReadParse();
@@ -23,7 +26,7 @@ else {
%newopts = map { $_, 1 } split(/\0/, $in{'client'});
# Save boolean options
- foreach $o (&list_client_restrictions()) {
+ foreach my $o (&list_client_restrictions()) {
if ($newopts{$o} && !$oldopts{$o}) {
push(@opts, $o);
}
@@ -33,9 +36,9 @@ else {
}
# Save options with values
- foreach $o (&list_multi_client_restrictions()) {
+ foreach my $o (&list_multi_client_restrictions()) {
# Find all current positions
- local @pos;
+ my @pos;
for(my $i=0; $i<@opts; $i++) {
push(@pos, $i) if ($opts[$i] eq $o);
}
diff --git a/postfix/save_manual.cgi b/postfix/save_manual.cgi
index 57718ac0d..0a0229476 100755
--- a/postfix/save_manual.cgi
+++ b/postfix/save_manual.cgi
@@ -1,7 +1,10 @@
#!/usr/local/bin/perl
# Update a manually edited map file
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, @files, %in, %text);
&ReadParseMime();
&error_setup($text{'manual_err'});
$access{'manual'} || &error($text{'manual_ecannot'});
@@ -10,9 +13,10 @@ $access{'manual'} || &error($text{'manual_ecannot'});
# Save the data
$in{'data'} =~ s/\r//g;
-&open_lock_tempfile(FILE, ">$in{'file'}");
-&print_tempfile(FILE, $in{'data'});
-&close_tempfile(FILE);
+my $filefh = "FILE";
+&open_lock_tempfile($filefh, ">$in{'file'}");
+&print_tempfile($filefh, $in{'data'});
+&close_tempfile($filefh);
# Regenerate map
®enerate_map_table($in{'map_name'});
diff --git a/postfix/save_map.cgi b/postfix/save_map.cgi
index 62e88533a..a70b5ae9e 100755
--- a/postfix/save_map.cgi
+++ b/postfix/save_map.cgi
@@ -6,7 +6,10 @@
# Save, modify, delete a map for Postfix
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($action, $err, $logmap, $nfunc, $vfunc, $whatfailed, %access, %in, %text);
&ReadParse();
@@ -21,7 +24,7 @@ my $add = 1; my %map;
## added to split main_parameter:sub_parameter
my ($mainparm,$subparm)=split /:/,$in{'map_name'};
-foreach $trans (@{$maps})
+foreach my $trans (@{$maps})
{
if ($trans->{'number'} == $in{'num'}) { $add = 0; %map = %{$trans}; }
}
@@ -75,7 +78,7 @@ if ($in{'delete'})
elsif ($add == 0)
{
# modify an existing map
- local %newmap = ( 'name' => $in{'name'},
+ my %newmap = ( 'name' => $in{'name'},
'value' => $in{'value'},
'cmt' => $in{'cmt'} );
&modify_mapping($in{'map_name'}, \%map, \%newmap);
@@ -85,7 +88,7 @@ elsif ($add == 0)
else
{
# add a new map -- much more easy! :-)
- local %newmap = ( 'name' => $in{'name'},
+ my %newmap = ( 'name' => $in{'name'},
'value' => $in{'value'},
'cmt' => $in{'cmt'} );
&create_mapping($in{'map_name'}, \%newmap);
diff --git a/postfix/save_master.cgi b/postfix/save_master.cgi
index b24365b73..243c7d379 100755
--- a/postfix/save_master.cgi
+++ b/postfix/save_master.cgi
@@ -1,7 +1,10 @@
#!/usr/local/bin/perl
# Create, update or delete a server process
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($clash, $err, $master, $prog, %access, %config, %in, %text);
$access{'master'} || &error($text{'master_ecannot'});
&ReadParse();
&error_setup($text{'master_err'});
diff --git a/postfix/save_opts.cgi b/postfix/save_opts.cgi
index 8fd04612f..9000a82e7 100755
--- a/postfix/save_opts.cgi
+++ b/postfix/save_opts.cgi
@@ -6,7 +6,10 @@
# Save Postfix options
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_aliases.cgi b/postfix/save_opts_aliases.cgi
index 3aa4e8eb5..19f936160 100755
--- a/postfix/save_opts_aliases.cgi
+++ b/postfix/save_opts_aliases.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for aliases
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_bcc.cgi b/postfix/save_opts_bcc.cgi
index 924116142..7b699e71f 100755
--- a/postfix/save_opts_bcc.cgi
+++ b/postfix/save_opts_bcc.cgi
@@ -1,6 +1,9 @@
#!/usr/local/bin/perl
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_body.cgi b/postfix/save_opts_body.cgi
index 09d85119e..7aaa88bd8 100755
--- a/postfix/save_opts_body.cgi
+++ b/postfix/save_opts_body.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for virtual tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_canonical.cgi b/postfix/save_opts_canonical.cgi
index f59f1d577..530e5c074 100755
--- a/postfix/save_opts_canonical.cgi
+++ b/postfix/save_opts_canonical.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for canonical tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_dependent.cgi b/postfix/save_opts_dependent.cgi
index f9ee4af8b..12b733030 100755
--- a/postfix/save_opts_dependent.cgi
+++ b/postfix/save_opts_dependent.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for sender transport maps
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_header.cgi b/postfix/save_opts_header.cgi
index b3551a163..25bdd62a3 100755
--- a/postfix/save_opts_header.cgi
+++ b/postfix/save_opts_header.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for virtual tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_misc.cgi b/postfix/save_opts_misc.cgi
index d2e5c6a09..95d57fb97 100755
--- a/postfix/save_opts_misc.cgi
+++ b/postfix/save_opts_misc.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special case in which we need to regenerate the relocated table
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_relocated.cgi b/postfix/save_opts_relocated.cgi
index a35558e42..001a9cc96 100755
--- a/postfix/save_opts_relocated.cgi
+++ b/postfix/save_opts_relocated.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for relocated tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_sni.cgi b/postfix/save_opts_sni.cgi
index 1d5b4645a..e5d78213b 100755
--- a/postfix/save_opts_sni.cgi
+++ b/postfix/save_opts_sni.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for sni tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_transport.cgi b/postfix/save_opts_transport.cgi
index cc64860fe..75d7179a6 100755
--- a/postfix/save_opts_transport.cgi
+++ b/postfix/save_opts_transport.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for transport tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_opts_virtual.cgi b/postfix/save_opts_virtual.cgi
index c22c102c5..eba22e3e5 100755
--- a/postfix/save_opts_virtual.cgi
+++ b/postfix/save_opts_virtual.cgi
@@ -6,7 +6,10 @@
# Save Postfix options ; special because for virtual tables
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, $virtual_maps, %access, %in, %text);
&ReadParse();
diff --git a/postfix/save_sasl.cgi b/postfix/save_sasl.cgi
index e0d529529..c57cc52e1 100755
--- a/postfix/save_sasl.cgi
+++ b/postfix/save_sasl.cgi
@@ -1,7 +1,10 @@
#!/usr/local/bin/perl
# Save SMTP authentication options
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, $newmap, $old, $pmap, $postfix_version, $rh, %access, %in, %newrecip, %newrelay, @opts, @recip, @relay, %text);
&ReadParse();
@@ -36,7 +39,7 @@ if (!$in{'login_none'}) {
# Save recipient options that we care about
@recip = split(/[\s,]+/, &get_current_value("smtpd_recipient_restrictions"));
%newrecip = map { $_, 1 } split(/\0/, $in{'sasl_recip'});
-foreach $o (&list_smtpd_restrictions()) {
+foreach my $o (&list_smtpd_restrictions()) {
if ($newrecip{$o}) {
push(@recip, $o) if (&indexof($o, @recip) < 0);
}
@@ -49,7 +52,7 @@ foreach $o (&list_smtpd_restrictions()) {
# Save relay options that we care about
@relay = split(/[\s,]+/, &get_current_value("smtpd_relay_restrictions"));
%newrelay = map { $_, 1 } split(/\0/, $in{'sasl_relay'});
-foreach $o (&list_smtpd_restrictions()) {
+foreach my $o (&list_smtpd_restrictions()) {
if ($newrelay{$o}) {
push(@relay, $o) if (&indexof($o, @relay) < 0);
}
diff --git a/postfix/smtp.cgi b/postfix/smtp.cgi
index 2dfb09d01..ee86e79b5 100755
--- a/postfix/smtp.cgi
+++ b/postfix/smtp.cgi
@@ -7,7 +7,10 @@
#
# << Here are all options seen in Postfix sample-smtp.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($default, $inet, $level, $no_, $none, $postfix_version, $pref, %access, %inet, @opts, %text);
$access{'smtp'} || &error($text{'smtp_ecannot'});
diff --git a/postfix/smtpd.cgi b/postfix/smtpd.cgi
index c855c8191..698bfd4cb 100755
--- a/postfix/smtpd.cgi
+++ b/postfix/smtpd.cgi
@@ -8,7 +8,10 @@
#
# << Here are all options seen in Postfix sample-smtpd.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($default, $no_, $none, %access, %text);
&ReadParse();
$access{'smtpd'} || &error($text{'smtpd_ecannot'});
diff --git a/postfix/sni.cgi b/postfix/sni.cgi
index 414f6064d..4802f70bc 100755
--- a/postfix/sni.cgi
+++ b/postfix/sni.cgi
@@ -8,7 +8,10 @@
# << Here are all options seen in Postfix sample-sni.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our (%access, %text);
&ReadParse();
$access{'sni'} || &error($text{'sni_ecannot'});
diff --git a/postfix/start.cgi b/postfix/start.cgi
index 60808424a..7d1e229b7 100755
--- a/postfix/start.cgi
+++ b/postfix/start.cgi
@@ -5,7 +5,10 @@
#
# Start postfix
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %text);
$access{'startstop'} || &error($text{'start_ecannot'});
&error_setup($text{'start_efailed'});
diff --git a/postfix/stop.cgi b/postfix/stop.cgi
index 8f102b606..4eaafb3f6 100755
--- a/postfix/stop.cgi
+++ b/postfix/stop.cgi
@@ -5,7 +5,10 @@
#
# Stop postfix
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($err, %access, %text);
$access{'startstop'} || &error($text{'stop_ecannot'});
&error_setup($text{'stop_efailed'});
diff --git a/postfix/t/perlcritic.t b/postfix/t/perlcritic.t
new file mode 100644
index 000000000..57f011f1e
--- /dev/null
+++ b/postfix/t/perlcritic.t
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More;
+
+BEGIN {
+ eval { require Perl::Critic; 1 }
+ or plan skip_all => 'Perl::Critic not installed';
+}
+
+use File::Find;
+
+sub script_dir
+{
+ my $path = $0;
+ if ($path =~ m{^/}) {
+ $path =~ s{/[^/]+$}{};
+ return $path;
+ }
+ my $cwd = `pwd`;
+ chomp($cwd);
+ if ($path =~ m{/}) {
+ $path =~ s{/[^/]+$}{};
+ return $cwd.'/'.$path;
+ }
+ return $cwd;
+}
+
+my $bindir = script_dir();
+my $module_dir = "$bindir/..";
+chdir($module_dir) or die "chdir: $!";
+
+my @files;
+find(
+ sub {
+ # Skip symlinks: several postfix files (aliases-lib.pl, autoreply.pl,
+ # filter.pl, edit_*file.cgi, save_*file.cgi, boxes-lib.pl) are symlinks
+ # into the sendmail and mailboxes modules. Those belong to other
+ # modules and are linted by their own test suites.
+ return if -l;
+ return if -d;
+ return unless /\.(pl|cgi)\z/;
+ # ".pl" is also the Polish translation suffix in Webmin. Skip
+ # ".pl" when a sibling "" (no extension) exists, so
+ # data files like config.info.pl and module.info.pl are not linted
+ # as Perl. (Same heuristic as the repo-root compile.t.)
+ if (/^(.*)\.pl\z/ && -e $1) {
+ return;
+ }
+ push(@files, $File::Find::name);
+ },
+ '.'
+);
+
+@files = sort @files;
+if (!@files) {
+ plan skip_all => 'no perl files to check';
+}
+
+my $critic = Perl::Critic->new(
+ -profile => "$bindir/../../.perlcriticrc",
+);
+
+foreach my $file (@files) {
+ my @violations = $critic->critique($file);
+ is(scalar @violations, 0, "$file perlcritic");
+ if (@violations) {
+ diag join("", @violations);
+ }
+}
+
+done_testing();
diff --git a/postfix/t/run-tests.t b/postfix/t/run-tests.t
new file mode 100644
index 000000000..4b0fdfbb7
--- /dev/null
+++ b/postfix/t/run-tests.t
@@ -0,0 +1,249 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More;
+use Cwd qw(abs_path);
+use File::Temp qw(tempdir);
+
+sub script_dir
+{
+ my $path = $0;
+ if ($path =~ m{^/}) {
+ $path =~ s{/[^/]+$}{};
+ return $path;
+ }
+ my $cwd = `pwd`;
+ chomp($cwd);
+ if ($path =~ m{/}) {
+ $path =~ s{/[^/]+$}{};
+ return $cwd.'/'.$path;
+ }
+ return $cwd;
+}
+
+my $bindir = script_dir();
+my $rootdir = abs_path("$bindir/../..") or die "rootdir: $!";
+
+my $confdir = tempdir(CLEANUP => 1);
+my $vardir = tempdir(CLEANUP => 1);
+
+# Global Webmin config
+open(my $cfh, ">", "$confdir/config") or die "config: $!";
+print $cfh "os_type=linux\nos_version=0\n";
+close($cfh);
+open(my $vfh, ">", "$confdir/var-path") or die "var-path: $!";
+print $vfh "$vardir\n";
+close($vfh);
+
+# A main.cf to drive the config parser
+my $maincf = "$confdir/main.cf";
+my $mastercf = "$confdir/master.cf";
+open(my $mc, ">", $maincf) or die "main.cf: $!";
+print $mc <<'EOF';
+myhostname = mail.example.com
+mydestination = example.com,
+ mail.example.com,
+ localhost
+compatibility_level = 2
+util_lt = {{$compatibility_level} < {3} ? {old} : {new}}
+util_ge = {{$compatibility_level} >= {3} ? {high} : {low}}
+util_eq = {{$compatibility_level} == {2} ? {match} : {nomatch}}
+subtest = key1 valueA key2 valueB
+alias_maps = hash:/etc/postfix/aliases, hash:/etc/aliases
+EOF
+close($mc);
+
+# A master.cf with one enabled and one disabled service, plus a continuation
+open(my $ms, ">", $mastercf) or die "master.cf: $!";
+print $ms <<'EOF';
+smtp inet n - y - - smtpd
+#qmgr unix n - n 300 1 qmgr
+pickup unix n - y 60 1 pickup
+ -o content_filter=foo
+EOF
+close($ms);
+
+# Per-module config
+mkdir "$confdir/postfix" or die "postfix confdir: $!";
+open(my $mod, ">", "$confdir/postfix/config") or die "module config: $!";
+print $mod "postfix_config_file=$maincf\n";
+print $mod "postfix_master=$mastercf\n";
+print $mod "postfix_config_command=/bin/true\n";
+print $mod "postfix_control_command=/bin/true\n";
+print $mod "prefix_cmts=0\n";
+close($mod);
+
+# Pre-seed the version file so loading the lib does not shell out to postconf.
+open(my $ver, ">", "$confdir/postfix/version") or die "version: $!";
+print $ver "3.4.0\n";
+close($ver);
+
+$ENV{'WEBMIN_CONFIG'} = $confdir;
+$ENV{'WEBMIN_VAR'} = $vardir;
+$ENV{'FOREIGN_MODULE_NAME'} = 'postfix';
+$ENV{'FOREIGN_ROOT_DIRECTORY'} = $rootdir;
+
+chdir("$bindir/..") or die "chdir: $!";
+
+require "$bindir/../postfix-lib.pl";
+our (%config, $postfix_version, $virtual_maps, $ldap_timeout, $config_dir);
+
+# --- load-time globals -----------------------------------------------------
+is($postfix_version, '3.4.0', 'postfix_version read from version file');
+is($virtual_maps, 'virtual_alias_maps', 'virtual_maps for >= 2.x');
+is($ldap_timeout, 'ldap_timeout', 'ldap_timeout for >= 2.x');
+is($config_dir, $confdir, 'guess_config_dir is dirname of main.cf');
+
+# --- file_map_type ---------------------------------------------------------
+ok(file_map_type('hash'), 'hash is a file map type');
+ok(file_map_type('pcre'), 'pcre is a file map type');
+ok(file_map_type('cidr'), 'cidr is a file map type');
+ok(!file_map_type('mysql'),'mysql is not a file map type');
+ok(!file_map_type('ldap'), 'ldap is not a file map type');
+
+# --- get_maps_types_files --------------------------------------------------
+is_deeply([ get_maps_types_files('hash:/etc/postfix/canonical') ],
+ [ [ 'hash', '/etc/postfix/canonical' ] ],
+ 'single type:file parsed');
+is_deeply([ get_maps_types_files(
+ 'hash:/etc/postfix/canonical, proxy:pcre:/etc/postfix/x') ],
+ [ [ 'hash', '/etc/postfix/canonical' ],
+ [ 'pcre', '/etc/postfix/x' ] ],
+ 'multiple maps and proxy: prefix parsed');
+is_deeply([ get_maps_types_files('mysql:/etc/postfix/m.cf') ],
+ [ [ 'mysql', '/etc/postfix/m.cf' ] ],
+ 'mysql backend type:file parsed');
+is_deeply([ get_maps_types_files('') ], [],
+ 'empty value yields no maps');
+is_deeply([ get_maps_types_files('garbage-without-colon') ], [],
+ 'unparseable value yields no maps');
+
+# --- get_maps_files (path extraction) --------------------------------------
+is_deeply([ get_maps_files('hash:/etc/postfix/aliases,hash:/etc/aliases') ],
+ [ '/etc/postfix/aliases', '/etc/aliases' ],
+ 'get_maps_files extracts both file paths');
+is_deeply([ get_maps_files('static:foo') ], [],
+ 'get_maps_files ignores non-path map values');
+
+# --- get_current_value (main.cf parser) ------------------------------------
+is(get_current_value('myhostname', 1), 'mail.example.com',
+ 'single-line parameter parsed');
+my $dest = get_current_value('mydestination', 1);
+like($dest, qr/example\.com/, 'continuation line: first value present');
+like($dest, qr/localhost/, 'continuation line: trailing value joined');
+is(get_current_value('no_such_param', 1), undef,
+ 'unknown parameter with nodef returns undef (no postconf fallback)');
+is(get_current_value('subtest:key1', 1), 'valueA',
+ 'sub-parameter extraction (foo:bar) returns value after the key');
+
+# --- resolve_current_value (compatibility_level conditionals) --------------
+# Exercises the operator-dispatch rewrite of the old stringy eval.
+is(resolve_current_value('util_lt'), 'old',
+ 'resolve "<": level 2 is < 3, takes true branch');
+is(resolve_current_value('util_ge'), 'low',
+ 'resolve ">=": level 2 is not >= 3, takes false branch');
+is(resolve_current_value('util_eq'), 'match',
+ 'resolve "==": level 2 == 2, takes true branch');
+is(resolve_current_value('myhostname'), 'mail.example.com',
+ 'resolve passes through a plain value unchanged');
+
+# --- master.cf parser + serializer -----------------------------------------
+my $master = get_master_config();
+is(ref($master), 'ARRAY', 'get_master_config returns array ref');
+is(scalar(@$master), 3, 'three service entries parsed');
+
+my ($smtp) = grep { $_->{'name'} eq 'smtp' } @$master;
+my ($qmgr) = grep { $_->{'name'} eq 'qmgr' } @$master;
+my ($pickup) = grep { $_->{'name'} eq 'pickup' } @$master;
+
+ok($smtp, 'smtp service parsed');
+ok($smtp->{'enabled'}, 'smtp is enabled');
+is($smtp->{'type'}, 'inet', 'smtp type');
+is($smtp->{'chroot'}, 'y', 'smtp chroot column');
+is($smtp->{'command'}, 'smtpd','smtp command');
+
+ok($qmgr, 'commented service still parsed');
+ok(!$qmgr->{'enabled'}, 'commented service is disabled');
+
+ok($pickup, 'pickup service parsed');
+is($pickup->{'command'}, 'pickup -o content_filter=foo',
+ 'continuation line appended to command');
+
+# master_line round-trips an entry back to its on-disk form
+is(master_line($smtp),
+ "smtp\tinet\tn\t-\ty\t-\t-\tsmtpd",
+ 'master_line serializes an enabled service with tabs');
+is(master_line($qmgr),
+ "#qmgr\tunix\tn\t-\tn\t300\t1\tqmgr",
+ 'master_line prefixes a disabled service with #');
+
+# --- is_table_comment / make_table_comment ---------------------------------
+{
+ local $config{'prefix_cmts'} = 0;
+ is(is_table_comment('# hello world'), 'hello world',
+ 'plain comment text extracted when prefix_cmts off');
+ is_deeply([ make_table_comment('a note') ], [ '# a note' ],
+ 'make_table_comment emits a plain # line');
+ is_deeply([ make_table_comment('') ], [],
+ 'make_table_comment emits nothing for empty comment');
+}
+{
+ local $config{'prefix_cmts'} = 1;
+ is(is_table_comment('# Webmin: tagged'), 'tagged',
+ 'Webmin-tagged comment extracted when prefix_cmts on');
+ is(is_table_comment('# untagged'), undef,
+ 'untagged comment ignored when prefix_cmts on');
+ is_deeply([ make_table_comment('z') ], [ '# Webmin: z' ],
+ 'make_table_comment emits a Webmin-tagged line when prefix_cmts on');
+}
+
+# --- in_props --------------------------------------------------------------
+is(in_props([ qw(cn foo objectClass top) ], 'objectClass'), 'top',
+ 'in_props returns value following a matched name');
+is(in_props([ qw(cn foo) ], 'mail'), undef,
+ 'in_props returns undef for an absent name');
+is(in_props([ qw(CN foo) ], 'cn'), 'foo',
+ 'in_props matches case-insensitively');
+
+# --- get_ldap_key ----------------------------------------------------------
+is_deeply([ get_ldap_key({}) ],
+ [ 'mailacceptinggeneralid', '(mailacceptinggeneralid=*)' ],
+ 'get_ldap_key default attribute and filter');
+is_deeply([ get_ldap_key({ 'query_filter' => 'mail=%s' }) ],
+ [ 'mail', '(mail=*)' ],
+ 'get_ldap_key derives attribute and filter from query_filter');
+
+# --- make_map_ldap_dn ------------------------------------------------------
+{
+ local $config{'ldap_doms'} = 1; # allow sub-domain DNs
+ local $config{'ldap_id'} = undef; # default to cn
+ my $conf = { 'search_base' => 'dc=example,dc=com', 'scope' => 'sub' };
+ is(make_map_ldap_dn({ 'name' => 'user@dom.com' }, $conf),
+ 'cn=user,cn=dom.com,dc=example,dc=com',
+ 'make_map_ldap_dn builds a per-user DN inside a domain');
+ is(make_map_ldap_dn({ 'name' => '@dom.com' }, $conf),
+ 'cn=default,cn=dom.com,dc=example,dc=com',
+ 'make_map_ldap_dn builds a catch-all DN for a domain');
+ is(make_map_ldap_dn({ 'name' => 'literal' }, $conf),
+ 'cn=literal,dc=example,dc=com',
+ 'make_map_ldap_dn builds a flat DN for a non-address name');
+}
+
+# --- get_backend_config ----------------------------------------------------
+my $backend = "$confdir/mysql.cf";
+open(my $bfh, ">", $backend) or die "backend: $!";
+print $bfh "user = postfix\npassword = secret\n# a comment\nhosts = localhost\n";
+close($bfh);
+my $bc = get_backend_config($backend);
+is($bc->{'user'}, 'postfix', 'backend config user parsed');
+is($bc->{'password'}, 'secret', 'backend config password parsed');
+is($bc->{'hosts'}, 'localhost', 'backend config hosts parsed');
+
+# --- list_smtpd_restrictions (version-dependent constant) ------------------
+my @restr = list_smtpd_restrictions();
+ok((grep { $_ eq 'permit_mynetworks' } @restr),
+ 'smtpd restrictions include permit_mynetworks');
+ok((grep { $_ eq 'reject_unknown_reverse_client_hostname' } @restr),
+ '>= 2.3 uses reject_unknown_reverse_client_hostname');
+
+done_testing();
diff --git a/postfix/transport.cgi b/postfix/transport.cgi
index 6f06e8894..a341fc107 100755
--- a/postfix/transport.cgi
+++ b/postfix/transport.cgi
@@ -8,7 +8,10 @@
# << Here are all options seen in Postfix sample-transport.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our (%access, %text);
&ReadParse();
$access{'transport'} || &error($text{'transport_ecannot'});
diff --git a/postfix/view_mailq.cgi b/postfix/view_mailq.cgi
index ed6b9ced7..35851bb7d 100755
--- a/postfix/view_mailq.cgi
+++ b/postfix/view_mailq.cgi
@@ -2,8 +2,11 @@
# view_mailq.cgi
# Display some message from the mail queue
-require './postfix-lib.pl';
-require './boxes-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($body, $bodyhtml, $desc, $mail, $rlink, $subs, %access, @attach, %config, %in, @sub, %text);
+require './boxes-lib.pl'; ## no critic
&ReadParse();
$access{'mailq'} || &error($text{'mailq_ecannot'});
@@ -12,9 +15,9 @@ $mail || &error($text{'mailq_egone'});
&parse_mail($mail);
@sub = split(/\0/, $in{'sub'});
$subs = join("", map { "&sub=$_" } @sub);
-foreach $s (@sub) {
+foreach my $s (@sub) {
# We are looking at a mail within a mail ..
- local $amail = &extract_mail($mail->{'attach'}->[$s]->{'data'});
+ my $amail = &extract_mail($mail->{'attach'}->[$s]->{'data'});
&parse_mail($amail);
$mail = $amail;
}
@@ -49,7 +52,7 @@ if ($in{'headers'}) {
print &ui_table_row($text{'mail_rfc'},
&html_escape($mail->{'fromline'}));
}
- foreach $h (@{$mail->{'headers'}}) {
+ foreach my $h (@{$mail->{'headers'}}) {
print &ui_table_row($h->[0],
&html_escape(&decode_mimewords($h->[1])), 1, [ "nowrap" ]);
}
@@ -84,7 +87,7 @@ print &ui_table_end();
# Find body attachment
@attach = @{$mail->{'attach'}};
-foreach $a (@attach) {
+foreach my $a (@attach) {
if ($a->{'type'} eq 'text/plain') {
$body = $a;
last;
@@ -93,7 +96,7 @@ foreach $a (@attach) {
if ($body) {
print &ui_table_start($text{'view_body'}, "width=100%", 2);
$bodyhtml = "";
- foreach $l (&wrap_lines($body->{'data'}, $config{'wrap_width'})) {
+ foreach my $l (&wrap_lines($body->{'data'}, $config{'wrap_width'})) {
$bodyhtml .= &link_urls_and_escape($l)."\n";
}
print &ui_table_row(undef, "".$bodyhtml." ", 2);
@@ -107,7 +110,7 @@ if (@attach) {
print &ui_columns_start([ $text{'view_afile'}, $text{'view_atype'},
$text{'view_asize'} ], 100, 0);
my $attachment_id;
- foreach $a (@attach) {
+ foreach my $a (@attach) {
$attachment_id++;
if ($a->{'type'} eq 'message/rfc822') {
print &ui_columns_row([
diff --git a/postfix/virtual.cgi b/postfix/virtual.cgi
index aa8ed9420..db13e44e6 100755
--- a/postfix/virtual.cgi
+++ b/postfix/virtual.cgi
@@ -8,7 +8,10 @@
# << Here are all options seen in Postfix sample-virtual.cf >>
-require './postfix-lib.pl';
+require './postfix-lib.pl'; ## no critic
+use strict;
+use warnings;
+our ($postfix_version, $virtual_maps, %access, %text);
&ReadParse();
$access{'virtual'} || &error($text{'virtual_ecannot'});
|