1#! PERL_COMMAND 2 3# This is a Perl script that reads an Exim run-time configuration file and 4# checks for settings that were valid prior to release 3.00 but which were 5# obsoleted by that release. It writes a new file with suggested changes to 6# the standard output, and commentary about what it has done to stderr. 7 8# It is assumed that the input is a valid Exim configuration file. 9 10use warnings; 11BEGIN { pop @INC if $INC[-1] eq '.' }; 12 13use Getopt::Long; 14use File::Basename; 15 16GetOptions( 17 'version' => sub { 18 print basename($0) . ": $0\n", 19 "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n", 20 "perl(runtime): $^V\n"; 21 exit 0; 22 }, 23); 24 25################################################## 26# Analyse one line # 27################################################## 28 29# This is called for the main and the driver sections, not for retry 30# or rewrite sections (which are unmodified). 31 32sub checkline{ 33my($line) = $_[0]; 34 35return "comment" if $line =~ /^\s*(#|$)/; 36return "end" if $line =~ /^\s*end\s*$/; 37 38# Macros are recognized only in the first section of the file. 39 40return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/; 41 42# Pick out the name at the start and the rest of the line (into global 43# variables) and return whether the start of a driver or not. 44 45($i1,$name,$i2,$rest) = $line =~ /^(\s*)([a-z0-9_]+)(\s*)(.*?)\s*$/; 46return ($rest =~ /^:/)? "driver" : "option"; 47} 48 49 50 51 52################################################## 53# Add transport setting to a director # 54################################################## 55 56# This function adds a transport setting to an aliasfile or forwardfile 57# director if a global setting exists and a local one does not. If neither 58# exist, it adds file/pipe/reply, but not the directory ones. 59 60sub add_transport{ 61my($option) = @_; 62 63my($key) = "$prefix$driver.${option}_transport"; 64if (!exists $o{$key}) 65 { 66 if (exists $o{"address_${option}_transport"}) 67 { 68 print STDOUT "# >> Option added by convert4r3\n"; 69 printf STDOUT "${i1}${option}_transport = %s\n", 70 $o{"address_${option}_transport"}; 71 printf STDERR 72 "\n%03d ${option}_transport added to $driver director.\n", 73 ++$count; 74 } 75 else 76 { 77 if ($option eq "pipe" || $option eq "file" || $option eq "reply") 78 { 79 print STDOUT "# >> Option added by convert4r3\n"; 80 printf STDOUT "${i1}${option}_transport = address_${option}\n"; 81 printf STDERR 82 "\n%03d ${option}_transport added to $driver director.\n", 83 ++$count; 84 } 85 } 86 } 87} 88 89 90 91 92################################################## 93# Negate a list of things # 94################################################## 95 96sub negate { 97my($list) = $_[0]; 98 99return $list if ! defined $list; 100 101($list) = $list =~ /^"?(.*?)"?\s*$/s; 102 103# Under Perl 5.005 we can split very nicely at colons, ignoring double 104# colons, like this: 105# 106# @split = split /\s*(?<!:):(?!:)\s*(?:\\\s*)?/s, $list; 107# 108# However, we'd better make this work under Perl 5.004, since there is 109# a lot of that about. 110 111$list =~ s/::/>%%%%</g; 112@split = split /\s*:\s*(?:\\\s*)?/s, $list; 113foreach $item (@split) 114 { 115 $item =~ s/>%%%%</::/g; 116 } 117 118$" = " : \\\n ! "; 119return "! @split"; 120} 121 122 123 124 125 126################################################## 127# Skip blank lines # 128################################################## 129 130# This function is called after we have generated no output for an option; 131# it skips subsequent blank lines if the previous line was blank. 132 133sub skipblanks { 134my($i) = $_[0]; 135if ($last_was_blank) 136 { 137 $i++ while $c[$i+1] =~ /^\s*$/; 138 } 139return $i; 140} 141 142 143 144 145 146################################################## 147# Get base name of data key # 148################################################## 149 150sub base { 151return "$_[0]" if $_[0] !~ /^(?:d|r|t)\.[^.]+\.(.*)/; 152return $1; 153} 154 155 156 157################################################## 158# Amalgamate accept/reject/reject_except # 159################################################## 160 161# This function amalgamates the three previous kinds of 162# option into a single list, using negation for the middle one if 163# the final argument is "+", or for the outer two if the final 164# argument is "-". 165 166sub amalgamate { 167my($accept,$reject,$reject_except,$name); 168my($last_was_negated) = 0; 169my($join) = ""; 170 171$accept = $o{$_[0]}; 172$reject = $o{$_[1]}; 173$reject_except = $o{$_[2]}; 174$name = $_[3]; 175 176if ($_[4] eq "+") 177 { 178 ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept; 179 $reject = &negate($reject) if defined $reject; 180 ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except; 181 } 182else 183 { 184 $accept = &negate($accept) if defined $accept; 185 ($reject) = $reject =~ /^"?(.*?)"?\s*$/s if defined $reject; 186 $reject_except = &negate($reject_except) if defined $reject_except; 187 } 188 189print STDOUT "# >> Option rewritten by convert4r3\n"; 190print STDOUT "${i1}$name = \""; 191 192if (defined $reject_except) 193 { 194 print STDOUT "$reject_except"; 195 $join = " : \\\n "; 196 $last_was_negated = ($_[4] ne "+"); 197 } 198if (defined $reject) 199 { 200 print STDOUT "$join$reject"; 201 $join = " : \\\n "; 202 $last_was_negated = ($_[4] eq "+"); 203 } 204if (defined $accept) 205 { 206 print STDOUT "$join$accept"; 207 $last_was_negated = ($_[4] ne "+"); 208 $join = " : \\\n "; 209 } 210 211print STDOUT "$join*" if $last_was_negated; 212 213print STDOUT "\"\n"; 214 215my($driver_name); 216my($driver_type) = ""; 217 218if ($_[0] =~ /^(d|r|t)\.([^.]+)\./ || 219 $_[1] =~ /^(d|r|t)\.([^.]+)\./ || 220 $_[2] =~ /^(d|r|t)\.([^.]+)\./) 221 { 222 $driver_type = ($1 eq 'd')? "director" : ($1 eq 'r')? "router" : "transport"; 223 $driver_name = $2; 224 } 225 226my($x) = ($driver_type ne "")? " in \"$driver_name\" $driver_type" : ""; 227 228my($l0) = &base($_[0]); 229my($l1) = &base($_[1]); 230my($l2) = &base($_[2]); 231 232 233if ($l2 eq "") 234 { 235 if ($l0 eq "") 236 { 237 printf STDERR "\n%03d $l1 converted to $name$x.\n", ++$count; 238 } 239 else 240 { 241 printf STDERR "\n%03d $l0 and $l1\n amalgamated into $name$x.\n", 242 ++$count; 243 } 244 } 245else 246 { 247 if ($l1 eq "") 248 { 249 printf STDERR "\n%03d $l0 and $l2\n amalgamated into $name$x.\n", 250 ++$count; 251 } 252 else 253 { 254 printf STDERR "\n%03d $l0, $l1 and $l2\n amalgamated into " . 255 "$name$x.\n", ++$count; 256 } 257 } 258} 259 260 261 262 263################################################## 264# Join two lists, if they exist # 265################################################## 266 267sub pair{ 268my($l1) = $o{"$_[0]"}; 269my($l2) = $o{"$_[1]"}; 270 271return $l2 if (!defined $l1); 272return $l1 if (!defined $l2); 273 274($l1) = $l1 =~ /^"?(.*?)"?\s*$/s; 275($l2) = $l2 =~ /^"?(.*?)"?\s*$/s; 276 277return "$l1 : $l2"; 278} 279 280 281 282 283################################################## 284# Amalgamate accept/reject/reject_except pairs # 285################################################## 286 287# This is like amalgamate, but it combines pairs of arguments, and 288# doesn't output commentary (easier to write a generic one for the few 289# cases). 290 291sub amalgamatepairs { 292my($accept) = &pair($_[0], $_[1]); 293my($reject) = &pair($_[2], $_[3]); 294my($reject_except) = &pair($_[4], $_[5]); 295my($last_was_negated) = 0; 296my($join) = ""; 297 298if ($_[7] eq "+") 299 { 300 ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept; 301 $reject = &negate($reject) if defined $reject; 302 ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except; 303 } 304else 305 { 306 $accept = &negate($accept) if defined $accept; 307 ($reject) = $reject =~ /^"?(.*?)"?$/s if defined $reject; 308 $reject_except = &negate($reject_except) if defined $reject_except; 309 } 310 311print STDOUT "# >> Option rewritten by convert4r3\n"; 312print STDOUT "${i1}$_[6] = \""; 313 314if (defined $reject_except) 315 { 316 print STDOUT "$reject_except"; 317 $join = " : \\\n "; 318 $last_was_negated = ($_[7] ne "+"); 319 } 320if (defined $reject) 321 { 322 print STDOUT "$join$reject"; 323 $join = " : \\\n "; 324 $last_was_negated = ($_[7] eq "+"); 325 } 326if (defined $accept) 327 { 328 print STDOUT "$join$accept"; 329 $last_was_negated = ($_[7] ne "+"); 330 $join = " : \\\n "; 331 } 332 333print STDOUT "$join*" if $last_was_negated; 334print STDOUT "\"\n"; 335} 336 337 338 339################################################## 340# Amalgamate boolean and exception list(s) # 341################################################## 342 343sub amalgboolandlist { 344my($name,$bool,$e1,$e2) = @_; 345 346print STDOUT "# >> Option rewritten by convert4r3\n"; 347if ($bool eq "false") 348 { 349 printf STDOUT "$i1$name =\n"; 350 } 351else 352 { 353 printf STDOUT "$i1$name = "; 354 my($n1) = &negate($o{$e1}); 355 my($n2) = &negate($o{$e2}); 356 if (!defined $n1 && !defined $n2) 357 { 358 print STDOUT "*\n"; 359 } 360 elsif (!defined $n1) 361 { 362 print STDOUT "\"$n2 : \\\n *\"\n"; 363 } 364 elsif (!defined $n2) 365 { 366 print STDOUT "\"$n1 : \\\n *\"\n"; 367 } 368 else 369 { 370 print STDOUT "\"$n1 : \\\n $n2 : \\\n *\"\n"; 371 } 372 } 373} 374 375 376 377################################################## 378# Convert mask format # 379################################################## 380 381# This function converts an address and mask in old-fashioned dotted-quad 382# format into an address plus a new format mask. 383 384@byte_list = (0, 128, 192, 224, 240, 248, 252, 254, 255); 385 386sub mask { 387my($address,$mask) = @_; 388my($length) = 0; 389my($i, $j); 390 391my(@bytes) = split /\./, $mask; 392 393for ($i = 0; $i < 4; $i++) 394 { 395 for ($j = 0; $j <= 8; $j++) 396 { 397 if ($bytes[$i] == $byte_list[$j]) 398 { 399 $length += $j; 400 if ($j != 8) 401 { 402 for ($i++; $i < 4; $i++) 403 { 404 $j = 9 if ($bytes[$i] != 0); 405 } 406 } 407 last; 408 } 409 } 410 411 if ($j > 8) 412 { 413 print STDERR "*** IP mask $mask cannot be converted to /n format. ***\n"; 414 return "$address/$mask"; 415 } 416 } 417 418if (!defined $masks{$mask}) 419 { 420 printf STDERR "\n%03d IP address mask $mask converted to /$length\n", 421 ++$count, $mask, $length; 422 $masks{$mask} = 1; 423 } 424 425return sprintf "$address/%d", $length; 426} 427 428 429 430 431 432################################################## 433# Main program # 434################################################## 435 436print STDERR "Exim pre-release 3.00 configuration file converter.\n"; 437 438$count = 0; 439$seen_helo_accept_junk = 0; 440$seen_hold_domains = 0; 441$seen_receiver_unqualified = 0; 442$seen_receiver_verify_except = 0; 443$seen_receiver_verify_senders = 0; 444$seen_rfc1413_except = 0; 445$seen_sender_accept = 0; 446$seen_sender_accept_recipients = 0; 447$seen_sender_host_accept = 0; 448$seen_sender_host_accept_recipients = 0; 449$seen_sender_host_accept_relay = 0; 450$seen_sender_unqualified = 0; 451$seen_sender_verify_except_hosts = 0; 452$seen_smtp_etrn = 0; 453$seen_smtp_expn = 0; 454$seen_smtp_reserve = 0; 455$semicomma = 0; 456 457# Read the entire file into an array 458 459chomp(@c = <STDIN>); 460 461# First, go through the input and covert any net masks in the old dotted-quad 462# style into the new /n style. 463 464for ($i = 0; $i < scalar(@c); $i++) 465 { 466 $c[$i] =~ 467 s"((?:\d{1,3}\.){3}\d{1,3})/((?:\d{1,3}\.){3}\d{1,3})"&mask($1,$2)"eg; 468 } 469 470# We now make two more passes over the input. In the first pass, we place all 471# the option values into an associative array. Main options are keyed by their 472# names; options for drivers are keyed by a driver type letter, the driver 473# name, and the option name, dot-separated. In the second pass we modify 474# the options if necessary, and write the output file. 475 476for ($pass = 1; $pass < 3; $pass++) 477 { 478 $prefix = ""; 479 $driver = ""; 480 $last_was_blank = 0; 481 482 for ($i = 0; $i < scalar(@c); $i++) 483 { 484 # Everything after the router section is just copied in pass 2 and 485 # ignored in pass 1. 486 487 if ($prefix eq "end") 488 { 489 print STDOUT "$c[$i]\n" if $pass == 2; 490 next; 491 } 492 493 # Analyze the line 494 495 $type = &checkline($c[$i]); 496 497 # Skip comments in pass 1; copy in pass 2 498 499 if ($type eq "comment") 500 { 501 $last_was_blank = ($c[$i] =~ /^\s*$/)? 1 : 0; 502 print STDOUT "$c[$i]\n" if $pass == 2; 503 next; 504 } 505 506 # Skip/copy macro definitions, but must handle continuations 507 508 if ($type eq "macro") 509 { 510 print STDOUT "$c[$i]\n" if $pass == 2; 511 while ($c[$i] =~ /\\\s*$/) 512 { 513 $i++; 514 print STDOUT "$c[$i]\n" if $pass == 2; 515 } 516 $last_was_blank = 0; 517 next; 518 } 519 520 # Handle end of section 521 522 if ($type eq "end") 523 { 524 $prefix = "end"if $prefix eq "r."; 525 $prefix = "r." if $prefix eq "d."; 526 $prefix = "d." if $prefix eq "t."; 527 $prefix = "t." if $prefix eq ""; 528 print STDOUT "$c[$i]\n" if $pass == 2; 529 $last_was_blank = 0; 530 next; 531 } 532 533 # Handle start of a new driver 534 535 if ($type eq "driver") 536 { 537 $driver = $name; 538 print STDOUT "$c[$i]\n" if $pass == 2; 539 $last_was_blank = 0; 540 $seen_domains = 0; 541 $seen_local_parts = 0; 542 $seen_senders = 0; 543 $seen_mx_domains = 0; 544 $seen_serialize = 0; 545 next; 546 } 547 548 # Handle definition of an option 549 550 if ($type eq "option") 551 { 552 # Handle continued strings 553 554 if ($rest =~ /^=\s*".*\\$/) 555 { 556 for (;;) 557 { 558 $rest .= "\n$c[++$i]"; 559 last unless $c[$i] =~ /(\\\s*$|^\s*#)/; 560 } 561 } 562 563 # Remove any terminating commas and semicolons in pass 2 564 565 if ($pass == 2 && $rest =~ /[;,]\s*$/) 566 { 567 $rest =~ s/\s*[;,]\s*$//; 568 if (!$semicomma) 569 { 570 printf STDERR 571 "\n%03d Terminating semicolons and commas removed from driver " . 572 "options.\n", ++$count; 573 $semicomma = 1; 574 } 575 } 576 577 # Convert all booleans to "x = true/false" format, but save the 578 # original so that it can be reproduced unchanged for options that 579 # are not of interest. 580 581 $origname = $name; 582 $origrest = $rest; 583 584 if ($name =~ /^not?_(.*)/) 585 { 586 $name = $1; 587 $rest = "= false"; 588 } 589 elsif ($rest !~ /^=/) 590 { 591 $rest = "= true"; 592 } 593 594 # Set up the associative array key, and get rid of the = on the data 595 596 $key = ($prefix eq "")? "$name" : "$prefix$driver.$name"; 597 ($rest) = $rest =~ /^=\s*(.*)/s; 598 599 # Create the associative array of values in pass 1 600 601 if ($pass == 1) 602 { 603 $o{$key} = $rest; 604 } 605 606 # In pass 2, test for interesting options and do the necessary; copy 607 # all the rest. 608 609 else 610 { 611 ########## Global configuration ########## 612 613 # These global options are abolished 614 615 if ($name eq "address_directory_transport" || 616 $name eq "address_directory2_transport" || 617 $name eq "address_file_transport" || 618 $name eq "address_pipe_transport" || 619 $name eq "address_reply_transport") 620 { 621 ($n2) = $name =~ /^address_(.*)/; 622 printf STDERR "\n%03d $name option deleted.\n", ++$count; 623 printf STDERR " $n2 will be added to appropriate directors.\n"; 624 $i = &skipblanks($i); 625 next; 626 } 627 628 # This debugging option is abolished 629 630 elsif ($name eq "sender_verify_log_details") 631 { 632 printf STDERR "\n%03d $name option deleted.\n", ++$count; 633 printf STDERR " (Little used facility abolished.)\n"; 634 } 635 636 # This option has been renamed 637 638 elsif ($name eq "check_dns_names") 639 { 640 $origname =~ s/check_dns/dns_check/; 641 print STDOUT "# >> Option rewritten by convert4r3\n"; 642 print STDOUT "$i1$origname$i2$origrest\n"; 643 printf STDERR "\n%03d check_dns_names renamed as dns_check_names.\n", 644 ++$count; 645 } 646 647 # helo_accept_junk_nets is abolished 648 649 elsif ($name eq "helo_accept_junk_nets" || 650 $name eq "helo_accept_junk_hosts") 651 { 652 if (!$seen_helo_accept_junk) 653 { 654 &amalgamate("helo_accept_junk_nets", "", 655 "helo_accept_junk_hosts", "helo_accept_junk_hosts", "+"); 656 $seen_helo_accept_junk = 1; 657 } 658 else 659 { 660 $i = &skipblanks($i); 661 next; 662 } 663 } 664 665 # helo_verify_except_{hosts,nets} are abolished, and helo_verify 666 # is now a host list instead of a boolean. 667 668 elsif ($name eq "helo_verify") 669 { 670 &amalgboolandlist("helo_verify", $rest, "helo_verify_except_hosts", 671 "helo_verify_except_nets"); 672 printf STDERR "\n%03d helo_verify converted to host list.\n", 673 ++$count; 674 } 675 elsif ($name eq "helo_verify_except_hosts" || 676 $name eq "helo_verify_except_nets") 677 { 678 $i = &skipblanks($i); 679 next; 680 } 681 682 # helo_verify_nets was an old synonym for host_lookup_nets; only 683 # one of them will be encountered. Change to a new name. 684 685 elsif ($name eq "helo_verify_nets" || 686 $name eq "host_lookup_nets") 687 { 688 print STDOUT "# >> Option rewritten by convert4r3\n"; 689 print STDOUT "${i1}host_lookup$i2$origrest\n"; 690 printf STDERR "\n%03d $name renamed as host_lookup.\n", ++$count; 691 } 692 693 # hold_domains_except is abolished; add as negated items to 694 # hold_domains. 695 696 elsif ($name eq "hold_domains_except" || 697 $name eq "hold_domains") 698 { 699 if ($seen_hold_domains) # If already done with these 700 { # omit, and following blanks. 701 $i = &skipblanks($i); 702 next; 703 } 704 $seen_hold_domains = 1; 705 706 if (exists $o{"hold_domains_except"}) 707 { 708 &amalgamate("hold_domains", "hold_domains_except", "", 709 "hold_domains", "+"); 710 } 711 else 712 { 713 print STDOUT "$i1$origname$i2$origrest\n"; 714 } 715 } 716 717 # ignore_fromline_nets is renamed as ignore_fromline_hosts 718 719 elsif ($name eq "ignore_fromline_nets") 720 { 721 $origname =~ s/_nets/_hosts/; 722 print STDOUT "# >> Option rewritten by convert4r3\n"; 723 print STDOUT "$i1$origname$i2$origrest\n"; 724 printf STDERR 725 "\n%03d ignore_fromline_nets renamed as ignore_fromline_hosts.\n", 726 ++$count; 727 } 728 729 # Output a warning for message filters with no transports set 730 731 elsif ($name eq "message_filter") 732 { 733 print STDOUT "$i1$origname$i2$origrest\n"; 734 735 if (!exists $o{"message_filter_directory_transport"} && 736 !exists $o{"message_filter_directory2_transport"} && 737 !exists $o{"message_filter_file_transport"} && 738 !exists $o{"message_filter_pipe_transport"} && 739 !exists $o{"message_filter_reply_transport"}) 740 { 741 printf STDERR 742 "\n%03d message_filter is set, but no message_filter transports " 743 . "are defined.\n" 744 . " If your filter generates file or pipe deliveries, or " 745 . "auto-replies,\n" 746 . " you will need to define " 747 . "message_filter_{file,pipe,reply}_transport\n" 748 . " options, as required.\n", ++$count; 749 } 750 } 751 752 # queue_remote_except is abolished, and queue_remote is replaced by 753 # queue_remote_domains, which is a host list. 754 755 elsif ($name eq "queue_remote") 756 { 757 &amalgboolandlist("queue_remote_domains", $rest, 758 "queue_remote_except", ""); 759 printf STDERR 760 "\n%03d queue_remote converted to domain list queue_remote_domains.\n", 761 ++$count; 762 } 763 elsif ($name eq "queue_remote_except") 764 { 765 $i = &skipblanks($i); 766 next; 767 } 768 769 # queue_smtp_except is abolished, and queue_smtp is replaced by 770 # queue_smtp_domains, which is a host list. 771 772 elsif ($name eq "queue_smtp") 773 { 774 &amalgboolandlist("queue_smtp_domains", $rest, 775 "queue_smtp_except", ""); 776 printf STDERR 777 "\n%03d queue_smtp converted to domain list queue_smtp_domains.\n", 778 ++$count; 779 } 780 elsif ($name eq "queue_smtp_except") 781 { 782 $i = &skipblanks($i); 783 next; 784 } 785 786 # rbl_except_nets is replaced by rbl_hosts 787 788 elsif ($name eq "rbl_except_nets") 789 { 790 &amalgamate("", "rbl_except_nets", "", "rbl_hosts", "+"); 791 } 792 793 # receiver_unqualified_nets is abolished 794 795 elsif ($name eq "receiver_unqualified_nets" || 796 $name eq "receiver_unqualified_hosts") 797 { 798 if (!$seen_receiver_unqualified) 799 { 800 &amalgamate("receiver_unqualified_nets", "", 801 "receiver_unqualified_hosts", "receiver_unqualified_hosts", "+"); 802 $seen_receiver_unqualified = 1; 803 } 804 else 805 { 806 $i = &skipblanks($i); 807 next; 808 } 809 } 810 811 # receiver_verify_except_{hosts,nets} are replaced by 812 # receiver_verify_hosts. 813 814 elsif ($name eq "receiver_verify_except_hosts" || 815 $name eq "receiver_verify_except_nets") 816 { 817 if (!$seen_receiver_verify_except) 818 { 819 &amalgboolandlist("receiver_verify_hosts", "true", 820 "receiver_verify_except_hosts", "receiver_verify_except_nets"); 821 printf STDERR 822 "\n%03d receiver_verify_except_{hosts,nets} converted to " . 823 "receiver_verify_hosts.\n", 824 ++$count; 825 $seen_receiver_verify_except = 1; 826 } 827 else 828 { 829 $i = &skipblanks($i); 830 next; 831 } 832 } 833 834 # receiver_verify_senders_except is abolished 835 836 elsif ($name eq "receiver_verify_senders" || 837 $name eq "receiver_verify_senders_except") 838 { 839 if (defined $o{"receiver_verify_senders_except"}) 840 { 841 if (!$seen_receiver_verify_senders) 842 { 843 &amalgamate("receiver_verify_senders", 844 "receiver_verify_senders_except", "", 845 "receiver_verify_senders", "+"); 846 $seen_receiver_verify_senders = 1; 847 } 848 else 849 { 850 $i = &skipblanks($i); 851 next; 852 } 853 } 854 else 855 { 856 print STDOUT "$i1$origname$i2$origrest\n"; 857 } 858 } 859 860 # rfc1413_except_{hosts,nets} are replaced by rfc1413_hosts. 861 862 elsif ($name eq "rfc1413_except_hosts" || 863 $name eq "rfc1413_except_nets") 864 { 865 if (!$seen_rfc1413_except) 866 { 867 &amalgboolandlist("rfc1413_hosts", "true", 868 "rfc1413_except_hosts", "rfc1413_except_nets"); 869 printf STDERR 870 "\n%03d rfc1413_except_{hosts,nets} converted to rfc1413_hosts.\n", 871 ++$count; 872 $seen_rfc1413_except = 1; 873 } 874 else 875 { 876 $i = &skipblanks($i); 877 next; 878 } 879 } 880 881 # sender_accept and sender_reject_except are abolished 882 883 elsif ($name eq "sender_accept" || 884 $name eq "sender_reject") 885 { 886 if (!$seen_sender_accept) 887 { 888 &amalgamate("sender_accept", "sender_reject", 889 "sender_reject_except", "sender_reject", "-"); 890 $seen_sender_accept = 1; 891 } 892 else 893 { 894 $i = &skipblanks($i); 895 next; 896 } 897 } 898 899 # sender_accept_recipients is also abolished; sender_reject_except 900 # also used to apply to this, so we include it here as well. 901 902 elsif ($name eq "sender_accept_recipients" || 903 $name eq "sender_reject_recipients") 904 { 905 if (!$seen_sender_accept_recipients) 906 { 907 &amalgamate("sender_accept_recipients", "sender_reject_recipients", 908 "sender_reject_except", "sender_reject_recipients", "-"); 909 $seen_sender_accept_recipients = 1; 910 } 911 else 912 { 913 $i = &skipblanks($i); 914 next; 915 } 916 } 917 918 # sender_reject_except must be removed 919 920 elsif ($name eq "sender_reject_except") 921 { 922 $i = &skipblanks($i); 923 next; 924 } 925 926 # sender_{host,net}_{accept,reject}[_except] all collapse into 927 # host_reject. 928 929 elsif ($name eq "sender_host_accept" || 930 $name eq "sender_net_accept" || 931 $name eq "sender_host_reject" || 932 $name eq "sender_net_reject") 933 { 934 if (!$seen_sender_host_accept) 935 { 936 &amalgamatepairs("sender_host_accept", "sender_net_accept", 937 "sender_host_reject", "sender_net_reject", 938 "sender_host_reject_except", "sender_net_reject_except", 939 "host_reject", "-"); 940 printf STDERR "\n%03d sender_{host,net}_{accept,reject} and " . 941 "sender_{host_net}_reject_except\n" . 942 " amalgamated into host_reject.\n", ++$count; 943 $seen_sender_host_accept = 1; 944 } 945 else 946 { 947 $i = &skipblanks($i); 948 next; 949 } 950 } 951 952 # sender_{host,net}_{accept,reject}_recipients all collapse into 953 # host_reject_recipients. 954 955 elsif ($name eq "sender_host_accept_recipients" || 956 $name eq "sender_net_accept_recipients" || 957 $name eq "sender_host_reject_recipients" || 958 $name eq "sender_net_reject_recipients") 959 { 960 if (!$seen_sender_host_accept_recipients) 961 { 962 &amalgamatepairs("sender_host_accept_recipients", 963 "sender_net_accept_recipients", 964 "sender_host_reject_recipients", 965 "sender_net_reject_recipients", 966 "sender_host_reject_except", "sender_net_reject_except", 967 "host_reject_recipients", "-"); 968 printf STDERR "\n%03d sender_{host,net}_{accept,reject}_recipients" 969 . "\n and sender_{host_net}_reject_except" 970 . "\n amalgamated into host_reject_recipients.\n", ++$count; 971 $seen_sender_host_accept_recipients = 1; 972 } 973 else 974 { 975 $i = &skipblanks($i); 976 next; 977 } 978 } 979 980 # sender_{host,net}_reject_except must be removed 981 982 elsif ($name eq "sender_host_reject_except" || 983 $name eq "sender_net_reject_except") 984 { 985 $i = &skipblanks($i); 986 next; 987 } 988 989 # sender_{host,net}_{accept,reject}_relay all collapse into 990 # host_accept_relay. 991 992 elsif ($name eq "sender_host_accept_relay" || 993 $name eq "sender_net_accept_relay" || 994 $name eq "sender_host_reject_relay" || 995 $name eq "sender_net_reject_relay") 996 { 997 if (!$seen_sender_host_accept_relay) 998 { 999 &amalgamatepairs("sender_host_accept_relay", 1000 "sender_net_accept_relay", 1001 "sender_host_reject_relay", 1002 "sender_net_reject_relay", 1003 "sender_host_reject_relay_except", 1004 "sender_net_reject_relay_except", 1005 "host_accept_relay", "+"); 1006 printf STDERR "\n%03d sender_{host,net}_{accept,reject}_relay" 1007 . "\n and sender_{host_net}_reject_relay_except" 1008 . "\n amalgamated into host_accept_relay.\n", ++$count; 1009 $seen_sender_host_accept_relay = 1; 1010 } 1011 else 1012 { 1013 $i = &skipblanks($i); 1014 next; 1015 } 1016 } 1017 1018 # sender_{host,net}_reject_relay_except must be removed 1019 1020 elsif ($name eq "sender_host_reject_relay_except" || 1021 $name eq "sender_net_reject_relay_except") 1022 { 1023 $i = &skipblanks($i); 1024 next; 1025 } 1026 1027 1028 # sender_unqualified_nets is abolished 1029 1030 elsif ($name eq "sender_unqualified_nets" || 1031 $name eq "sender_unqualified_hosts") 1032 { 1033 if (!$seen_sender_unqualified) 1034 { 1035 &amalgamate("sender_unqualified_nets", "", 1036 "sender_unqualified_hosts", "sender_unqualified_hosts", "+"); 1037 $seen_sender_unqualified = 1; 1038 } 1039 else 1040 { 1041 $i = &skipblanks($i); 1042 next; 1043 } 1044 } 1045 1046 # sender_verify_except_{hosts,nets} are replaced by sender_verify_hosts. 1047 1048 elsif ($name eq "sender_verify_except_hosts" || 1049 $name eq "sender_verify_except_nets") 1050 { 1051 if (!$seen_sender_verify_except_hosts) 1052 { 1053 &amalgboolandlist("sender_verify_hosts", "true", 1054 "sender_verify_except_hosts", "sender_verify_except_nets"); 1055 printf STDERR 1056 "\n%03d sender_verify_except_{hosts,nets} converted to " . 1057 "sender_verify_hosts.\n", 1058 ++$count; 1059 $seen_sender_verify_except_hosts = 1; 1060 } 1061 else 1062 { 1063 $i = &skipblanks($i); 1064 next; 1065 } 1066 } 1067 1068 # smtp_etrn_nets is abolished 1069 1070 elsif ($name eq "smtp_etrn_nets" || 1071 $name eq "smtp_etrn_hosts") 1072 { 1073 if (!$seen_smtp_etrn) 1074 { 1075 &amalgamate("smtp_etrn_nets", "", 1076 "smtp_etrn_hosts", "smtp_etrn_hosts", "+"); 1077 $seen_smtp_etrn = 1; 1078 } 1079 else 1080 { 1081 $i = &skipblanks($i); 1082 next; 1083 } 1084 } 1085 1086 # smtp_expn_nets is abolished 1087 1088 elsif ($name eq "smtp_expn_nets" || 1089 $name eq "smtp_expn_hosts") 1090 { 1091 if (!$seen_smtp_expn) 1092 { 1093 &amalgamate("smtp_expn_nets", "", 1094 "smtp_expn_hosts", "smtp_expn_hosts", "+"); 1095 $seen_smtp_expn = 1; 1096 } 1097 else 1098 { 1099 $i = &skipblanks($i); 1100 next; 1101 } 1102 } 1103 1104 # This option has been renamed 1105 1106 elsif ($name eq "smtp_log_connections") 1107 { 1108 $origname =~ s/smtp_log/log_smtp/; 1109 print STDOUT "# >> Option rewritten by convert4r3\n"; 1110 print STDOUT "$i1$origname$i2$origrest\n"; 1111 printf STDERR "\n%03d smtp_log_connections renamed as " . 1112 "log_smtp_connections.\n", 1113 ++$count; 1114 } 1115 1116 # smtp_reserve_nets is abolished 1117 1118 elsif ($name eq "smtp_reserve_nets" || 1119 $name eq "smtp_reserve_hosts") 1120 { 1121 if (!$seen_smtp_reserve) 1122 { 1123 &amalgamate("smtp_reserve_nets", "", 1124 "smtp_reserve_hosts", "smtp_reserve_hosts", "+"); 1125 $seen_smtp_reserve = 1; 1126 } 1127 else 1128 { 1129 $i = &skipblanks($i); 1130 next; 1131 } 1132 } 1133 1134 ########### Driver configurations ########## 1135 1136 # For aliasfile and forwardfile directors, add file, pipe, and 1137 # reply transports - copying from the globals if they are set. 1138 1139 elsif ($name eq "driver") 1140 { 1141 $driver_type = $rest; 1142 print STDOUT "$i1$origname$i2$origrest\n"; 1143 if ($rest eq "aliasfile" || $rest eq "forwardfile") 1144 { 1145 &add_transport("directory"); 1146 &add_transport("directory2"); 1147 &add_transport("file"); 1148 &add_transport("pipe"); 1149 &add_transport("reply") if $rest eq "forwardfile"; 1150 } 1151 } 1152 1153 # except_domains is abolished; add as negated items to domains. 1154 1155 elsif ($name eq "except_domains" || 1156 $name eq "domains") 1157 { 1158 if ($seen_domains) # If already done with these 1159 { # omit, and following blanks. 1160 $i = &skipblanks($i); 1161 next; 1162 } 1163 $seen_domains = 1; 1164 1165 if (exists $o{"$prefix$driver.except_domains"}) 1166 { 1167 &amalgamate("$prefix$driver.domains", 1168 "$prefix$driver.except_domains", "", 1169 "domains", "+"); 1170 } 1171 else 1172 { 1173 print STDOUT "$i1$origname$i2$origrest\n"; 1174 } 1175 } 1176 1177 # except_local_parts is abolished; add as negated items to 1178 # local_parts. 1179 1180 elsif ($name eq "except_local_parts" || 1181 $name eq "local_parts") 1182 { 1183 if ($seen_local_parts) # If already done with these 1184 { # omit, and following blanks. 1185 $i = &skipblanks($i); 1186 next; 1187 } 1188 $seen_local_parts = 1; 1189 1190 if (exists $o{"$prefix$driver.except_local_parts"}) 1191 { 1192 &amalgamate("$prefix$driver.local_parts", 1193 "$prefix$driver.except_local_parts", "", 1194 "local_parts", "+"); 1195 } 1196 else 1197 { 1198 print STDOUT "$i1$origname$i2$origrest\n"; 1199 } 1200 } 1201 1202 # except_senders is abolished; add as negated items to senders 1203 1204 elsif ($name eq "except_senders" || 1205 $name eq "senders") 1206 { 1207 if ($seen_senders) # If already done with these 1208 { # omit, and following blanks. 1209 $i = &skipblanks($i); 1210 next; 1211 } 1212 $seen_senders = 1; 1213 1214 if (exists $o{"$prefix$driver.except_senders"}) 1215 { 1216 &amalgamate("$prefix$driver.senders", 1217 "$prefix$driver.except_senders", "", 1218 "senders", "+"); 1219 } 1220 else 1221 { 1222 print STDOUT "$i1$origname$i2$origrest\n"; 1223 } 1224 } 1225 1226 # This option has been renamed 1227 1228 elsif ($name eq "directory" && $driver_type eq "aliasfile") 1229 { 1230 $origname =~ s/directory/home_directory/; 1231 print STDOUT "# >> Option rewritten by convert4r3\n"; 1232 print STDOUT "$i1$origname$i2$origrest\n"; 1233 printf STDERR "\n%03d directory renamed as " . 1234 "home_directory in \"$driver\" director.\n", 1235 ++$count; 1236 } 1237 1238 # This option has been renamed 1239 1240 elsif ($name eq "directory" && $driver_type eq "forwardfile") 1241 { 1242 $origname =~ s/directory/file_directory/; 1243 print STDOUT "# >> Option rewritten by convert4r3\n"; 1244 print STDOUT "$i1$origname$i2$origrest\n"; 1245 printf STDERR "\n%03d directory renamed as " . 1246 "file_directory in \"$driver\" director.\n", 1247 ++$count; 1248 } 1249 1250 # This option has been renamed 1251 1252 elsif ($name eq "forbid_filter_log" && $driver_type eq "forwardfile") 1253 { 1254 $origname =~ s/log/logwrite/; 1255 print STDOUT "# >> Option rewritten by convert4r3\n"; 1256 print STDOUT "$i1$origname$i2$origrest\n"; 1257 printf STDERR "\n%03d forbid_filter_log renamed as " . 1258 "forbid_filter_logwrite in \"$driver\" director.\n", 1259 ++$count; 1260 } 1261 1262 # This option has been renamed 1263 1264 elsif ($name eq "directory" && $driver_type eq "localuser") 1265 { 1266 $origname =~ s/directory/match_directory/; 1267 print STDOUT "# >> Option rewritten by convert4r3\n"; 1268 print STDOUT "$i1$origname$i2$origrest\n"; 1269 printf STDERR "\n%03d directory renamed as " . 1270 "match_directory in \"$driver\" director.\n", 1271 ++$count; 1272 } 1273 1274 # mx_domains_except (and old synonym non_mx_domains) are abolished 1275 # (both lookuphost router and smtp transport) 1276 1277 elsif ($name eq "mx_domains" || 1278 $name eq "mx_domains_except" || 1279 $name eq "non_mx_domains") 1280 { 1281 if ($seen_mx_domains) # If already done with these 1282 { # omit, and following blanks. 1283 $i = &skipblanks($i); 1284 next; 1285 } 1286 $seen_mx_domains = 1; 1287 1288 if (exists $o{"$prefix$driver.mx_domains_except"} || 1289 exists $o{"$prefix$driver.non_mx_domains"}) 1290 { 1291 $o{"$prefix$driver.mx_domains_except"} = 1292 &pair("$prefix$driver.mx_domains_except", 1293 "$prefix$driver.non_mx_domains"); 1294 1295 &amalgamate("$prefix$driver.mx_domains", 1296 "$prefix$driver.mx_domains_except", "", 1297 "mx_domains", "+"); 1298 } 1299 else 1300 { 1301 print STDOUT "$i1$origname$i2$origrest\n"; 1302 } 1303 } 1304 1305 # This option has been renamed 1306 1307 elsif ($name eq "directory" && $driver_type eq "pipe") 1308 { 1309 $origname =~ s/directory/home_directory/; 1310 print STDOUT "# >> Option rewritten by convert4r3\n"; 1311 print STDOUT "$i1$origname$i2$origrest\n"; 1312 printf STDERR "\n%03d directory renamed as " . 1313 "home_directory in \"$driver\" director.\n", 1314 ++$count; 1315 } 1316 1317 # serialize_nets is abolished 1318 1319 elsif ($name eq "serialize_nets" || 1320 $name eq "serialize_hosts") 1321 { 1322 if (!$seen_serialize) 1323 { 1324 &amalgamate("$prefix$driver.serialize_nets", "", 1325 "$prefix$driver.serialize_hosts", "serialize_hosts", "+"); 1326 $seen_serialize = 1; 1327 } 1328 else 1329 { 1330 $i = &skipblanks($i); 1331 next; 1332 } 1333 } 1334 1335 1336 # Option not of interest; reproduce verbatim 1337 1338 else 1339 { 1340 print STDOUT "$i1$origname$i2$origrest\n"; 1341 } 1342 1343 1344 $last_was_blank = 0; 1345 } 1346 } 1347 } 1348 1349 } 1350 1351# Debugging: show the associative array 1352# foreach $key (sort keys %o) { print STDERR "$key = $o{$key}\n"; } 1353 1354print STDERR "\nEnd of configuration file conversion.\n"; 1355print STDERR "\n*******************************************************\n"; 1356print STDERR "***** Please review the generated file carefully. *****\n"; 1357print STDERR "*******************************************************\n\n"; 1358 1359print STDERR "In particular:\n\n"; 1360 1361print STDERR "(1) If you use regular expressions in any options that have\n"; 1362print STDERR " been rewritten by this script, they might have been put\n"; 1363print STDERR " inside quotes, when then were not previously quoted. This\n"; 1364print STDERR " means that any backslashes in them must now be escaped.\n\n"; 1365 1366print STDERR "(2) If your configuration refers to any external files that\n"; 1367print STDERR " contain lists of network addresses, check that the masks\n"; 1368print STDERR " are specified as single numbers, e.g. /24 and NOT as dotted\n"; 1369print STDERR " quads (e.g. 255.255.255.0) because Exim release 3.00 does\n"; 1370print STDERR " not recognize the dotted quad form.\n\n"; 1371 1372print STDERR "(3) If your configuration uses macros for lists of domains or\n"; 1373print STDERR " hosts or addresses, check to see if any of the references\n"; 1374print STDERR " have been negated. If so, you will have to rework things,\n"; 1375print STDERR " because the negation will apply only to the first item in\n"; 1376print STDERR " the macro-generated list.\n\n"; 1377 1378print STDERR "(4) If you do not generate deliveries to pipes, files, or\n"; 1379print STDERR " auto-replies in your aliasfile and forwardfile directors,\n"; 1380print STDERR " you can remove the added transport settings.\n\n"; 1381 1382# End of convert4r3 1383