Expansion item ${listquote }. Bug 1066
[exim.git] / src / src / convert4r3.src
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
10 use warnings;
11 BEGIN { pop @INC if $INC[-1] eq '.' };
12
13 use Getopt::Long;
14 use File::Basename;
15
16 GetOptions(
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
32 sub checkline{
33 my($line) = $_[0];
34
35 return "comment" if $line =~ /^\s*(#|$)/;
36 return "end" if $line =~ /^\s*end\s*$/;
37
38 # Macros are recognized only in the first section of the file.
39
40 return "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*$/;
46 return ($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
60 sub add_transport{
61 my($option) = @_;
62
63 my($key) = "$prefix$driver.${option}_transport";
64 if (!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
96 sub negate {
97 my($list) = $_[0];
98
99 return $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;
113 foreach $item (@split)
114 {
115 $item =~ s/>%%%%</::/g;
116 }
117
118 $" = " : \\\n ! ";
119 return "! @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
133 sub skipblanks {
134 my($i) = $_[0];
135 if ($last_was_blank)
136 {
137 $i++ while $c[$i+1] =~ /^\s*$/;
138 }
139 return $i;
140 }
141
142
143
144
145
146 ##################################################
147 # Get base name of data key #
148 ##################################################
149
150 sub base {
151 return "$_[0]" if $_[0] !~ /^(?:d|r|t)\.[^.]+\.(.*)/;
152 return $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
166 sub amalgamate {
167 my($accept,$reject,$reject_except,$name);
168 my($last_was_negated) = 0;
169 my($join) = "";
170
171 $accept = $o{$_[0]};
172 $reject = $o{$_[1]};
173 $reject_except = $o{$_[2]};
174 $name = $_[3];
175
176 if ($_[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 }
182 else
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
189 print STDOUT "# >> Option rewritten by convert4r3\n";
190 print STDOUT "${i1}$name = \"";
191
192 if (defined $reject_except)
193 {
194 print STDOUT "$reject_except";
195 $join = " : \\\n ";
196 $last_was_negated = ($_[4] ne "+");
197 }
198 if (defined $reject)
199 {
200 print STDOUT "$join$reject";
201 $join = " : \\\n ";
202 $last_was_negated = ($_[4] eq "+");
203 }
204 if (defined $accept)
205 {
206 print STDOUT "$join$accept";
207 $last_was_negated = ($_[4] ne "+");
208 $join = " : \\\n ";
209 }
210
211 print STDOUT "$join*" if $last_was_negated;
212
213 print STDOUT "\"\n";
214
215 my($driver_name);
216 my($driver_type) = "";
217
218 if ($_[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
226 my($x) = ($driver_type ne "")? " in \"$driver_name\" $driver_type" : "";
227
228 my($l0) = &base($_[0]);
229 my($l1) = &base($_[1]);
230 my($l2) = &base($_[2]);
231
232
233 if ($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 }
245 else
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
267 sub pair{
268 my($l1) = $o{"$_[0]"};
269 my($l2) = $o{"$_[1]"};
270
271 return $l2 if (!defined $l1);
272 return $l1 if (!defined $l2);
273
274 ($l1) = $l1 =~ /^"?(.*?)"?\s*$/s;
275 ($l2) = $l2 =~ /^"?(.*?)"?\s*$/s;
276
277 return "$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
291 sub amalgamatepairs {
292 my($accept) = &pair($_[0], $_[1]);
293 my($reject) = &pair($_[2], $_[3]);
294 my($reject_except) = &pair($_[4], $_[5]);
295 my($last_was_negated) = 0;
296 my($join) = "";
297
298 if ($_[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 }
304 else
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
311 print STDOUT "# >> Option rewritten by convert4r3\n";
312 print STDOUT "${i1}$_[6] = \"";
313
314 if (defined $reject_except)
315 {
316 print STDOUT "$reject_except";
317 $join = " : \\\n ";
318 $last_was_negated = ($_[7] ne "+");
319 }
320 if (defined $reject)
321 {
322 print STDOUT "$join$reject";
323 $join = " : \\\n ";
324 $last_was_negated = ($_[7] eq "+");
325 }
326 if (defined $accept)
327 {
328 print STDOUT "$join$accept";
329 $last_was_negated = ($_[7] ne "+");
330 $join = " : \\\n ";
331 }
332
333 print STDOUT "$join*" if $last_was_negated;
334 print STDOUT "\"\n";
335 }
336
337
338
339 ##################################################
340 # Amalgamate boolean and exception list(s) #
341 ##################################################
342
343 sub amalgboolandlist {
344 my($name,$bool,$e1,$e2) = @_;
345
346 print STDOUT "# >> Option rewritten by convert4r3\n";
347 if ($bool eq "false")
348 {
349 printf STDOUT "$i1$name =\n";
350 }
351 else
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
386 sub mask {
387 my($address,$mask) = @_;
388 my($length) = 0;
389 my($i, $j);
390
391 my(@bytes) = split /\./, $mask;
392
393 for ($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
418 if (!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
425 return sprintf "$address/%d", $length;
426 }
427
428
429
430
431
432 ##################################################
433 # Main program #
434 ##################################################
435
436 print 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
459 chomp(@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
464 for ($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
476 for ($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
1354 print STDERR "\nEnd of configuration file conversion.\n";
1355 print STDERR "\n*******************************************************\n";
1356 print STDERR "***** Please review the generated file carefully. *****\n";
1357 print STDERR "*******************************************************\n\n";
1358
1359 print STDERR "In particular:\n\n";
1360
1361 print STDERR "(1) If you use regular expressions in any options that have\n";
1362 print STDERR " been rewritten by this script, they might have been put\n";
1363 print STDERR " inside quotes, when then were not previously quoted. This\n";
1364 print STDERR " means that any backslashes in them must now be escaped.\n\n";
1365
1366 print STDERR "(2) If your configuration refers to any external files that\n";
1367 print STDERR " contain lists of network addresses, check that the masks\n";
1368 print STDERR " are specified as single numbers, e.g. /24 and NOT as dotted\n";
1369 print STDERR " quads (e.g. 255.255.255.0) because Exim release 3.00 does\n";
1370 print STDERR " not recognize the dotted quad form.\n\n";
1371
1372 print STDERR "(3) If your configuration uses macros for lists of domains or\n";
1373 print STDERR " hosts or addresses, check to see if any of the references\n";
1374 print STDERR " have been negated. If so, you will have to rework things,\n";
1375 print STDERR " because the negation will apply only to the first item in\n";
1376 print STDERR " the macro-generated list.\n\n";
1377
1378 print STDERR "(4) If you do not generate deliveries to pipes, files, or\n";
1379 print STDERR " auto-replies in your aliasfile and forwardfile directors,\n";
1380 print STDERR " you can remove the added transport settings.\n\n";
1381
1382 # End of convert4r3