Harden plaintext authenticator
[exim.git] / src / src / convert4r4.src
1 #! PERL_COMMAND
2
3 # This is a Perl script that reads an Exim run-time configuration file for
4 # Exim 3. It makes what changes it can for Exim 4, and also output commentary
5 # on what it has done, and on things it cannot do.
6
7 # It is assumed that the input is a valid Exim 3 configuration file.
8
9 use warnings;
10 BEGIN { pop @INC if $INC[-1] eq '.' };
11
12 use Getopt::Long;
13 use File::Basename;
14
15 GetOptions(
16     'version' => sub {
17         print basename($0) . ": $0\n",
18             "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
19             "perl(runtime): $^V\n";
20             exit 0;
21     },
22 );
23
24 # These are lists of main options which are abolished in Exim 4.
25 # The first contains options that are used to construct new options.
26
27 @skipped_options = (
28 "auth_hosts",
29 "auth_over_tls_hosts",
30 "errors_address",
31 "headers_check_syntax",
32 "headers_checks_fail",
33 "headers_sender_verify",
34 "headers_sender_verify_errmsg",
35 "host_accept_relay",
36 "host_auth_accept_relay",
37 "host_reject_recipients",
38 "local_domains",
39 "local_domains_include_host",
40 "local_domains_include_host_literals",
41 "log_all_parents",
42 "log_arguments",
43 "log_incoming_port",
44 "log_interface",
45 "log_level",
46 "log_received_sender",
47 "log_received_recipients",
48 "log_rewrites",
49 "log_sender_on_delivery",
50 "log_smtp_confirmation",
51 "log_smtp_connections",
52 "log_smtp_syntax_errors",
53 "log_subject",
54 "log_queue_run_level",
55 "rbl_domains",
56 "rbl_hosts",
57 "rbl_reject_recipients",
58 "receiver_verify",
59 "receiver_verify_addresses",
60 "receiver_verify_hosts",
61 "receiver_verify_senders",
62 "recipients_reject_except",
63 "recipients_reject_except_senders",
64 "relay_domains",
65 "relay_domains_include_local_mx",
66 "sender_address_relay",
67 "sender_address_relay_hosts",
68 "sender_reject_recipients",
69 "sender_verify",
70 "sender_verify_hosts_callback",
71 "sender_verify_callback_domains",
72 "sender_verify_callback_timeout",
73 "sender_verify_hosts",
74 "smtp_etrn_hosts",
75 "smtp_expn_hosts",
76 "smtp_verify",
77 "tls_host_accept_relay",
78 "tls_hosts",
79 "tls_log_cipher",
80 "tls_log_peerdn",
81 "tls_verify_ciphers"
82 );
83
84 # The second contains options that are completely abolished and have
85 # no equivalent.
86
87 @abolished_options = (
88 "always_bcc",
89 "debug_level",
90 "helo_strict_syntax",
91 "kill_ip_options",
92 "log_ip_options",
93 "log_refused_recipients",
94 "message_size_limit_count_recipients",
95 "rbl_log_headers",
96 "rbl_log_rcpt_count",
97 "receiver_try_verify",
98 "refuse_ip_options",
99 "relay_match_host_or_sender",
100 "sender_try_verify",
101 "sender_verify_batch",
102 "sender_verify_fixup",
103 "sender_verify_reject",
104 "sender_verify_max_retry_rate",
105 );
106
107 # This is a list of options that are not otherwise handled, but which
108 # contain domain or host lists that have to be processed so that any
109 # regular expressions are marked "not for expansion".
110
111 @list_options = (
112 "dns_again_means_nonexist",
113 "hold_domains",
114 "hosts_treat_as_local",
115 "percent_hack_domains",
116 "queue_smtp_domains",
117 "helo_accept_junk_hosts",
118 "host_lookup",
119 "ignore_fromline_hosts",
120 "rfc1413_hosts",
121 "sender_unqualified_hosts",
122 "smtp_reserve_hosts",
123 "tls_advertise_hosts",
124 "tls_verify_hosts",
125 );
126
127
128
129 ##################################################
130 #          Output problem rubric once            #
131 ##################################################
132
133 sub rubric {
134 return if $rubric_output;
135 $rubric_output = 1;
136 print STDERR "\n" .
137 "** The following comments describe problems that have been encountered\n" .
138 "   while converting an Exim 3 runtime file for Exim 4. More detail can\n" .
139 "   be found in the file doc/Exim4.upgrade.\n";
140 }
141
142
143 ##################################################
144 #             Analyse one line                   #
145 ##################################################
146
147 sub checkline{
148 my($line) = $_[0];
149
150 return "comment" if $line =~ /^\s*(#|$)/;
151 return "end"     if $line =~ /^\s*end\s*$/i;
152
153 # Macros are recognized only in the first section of the file.
154
155 return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/;
156
157 # In retry and rewrite sections, the type is always "other"
158
159 return "other" if $prefix eq "=retry" || $prefix eq "=rewrite";
160
161 # Pick out the name at the start and the rest of the line (into global
162 # variables) and return whether the start of a driver or not.
163
164 ($hide,$name,$rest) = $line =~ /^\s*(hide\s+|)([a-z0-9_]+)\s*(.*?)\s*$/;
165
166 # If $rest begins with a colon, this is a driver name
167
168 return "driver" if $rest =~ /^:/;
169
170 # If $rest begins with an = the value of the option is given explicitly;
171 # remove the = from the start. Turn "yes"/"no" into "true"/"false".
172
173 if ($rest =~ /^=/)
174   {
175   $rest =~ s/^=\s*//;
176   $rest = "true" if $rest eq "yes";
177   $rest = "false" if $rest eq "no";
178   }
179
180 # Otherwise we have a boolean option. Set up a "true"/"false" value.
181
182 else
183   {
184   if ($name =~ /^not?_/)     # Recognize "no_" or "not_"
185     {
186     $rest = "false";
187     $name =~ s/^not?_//;
188     }
189   else
190     {
191     $rest = "true";
192     }
193   }
194
195 return "option";
196 }
197
198
199
200 ##################################################
201 #       Negate a list of things                  #
202 ##################################################
203
204 # Can be tricky, because there may be comment lines in the list.
205 # Also, lists may have different delimiters.
206
207 sub negate {
208 my($list) = $_[0];
209 my($delim) = ":";
210 my($leadin) = "";
211
212 return $list if ! defined $list;
213
214 ($list) = $list =~ /^"?(.*?)"?\s*$/s;      # Remove surrounding quotes
215 $list =~ s/\\\s*\n\s*//g;                  # Remove continuation markers
216
217 if ($list =~ /^(\s*<(\S)\s*)(.*)/s)
218   {
219   $leadin = $1;
220   $delim = $2;
221   $list = $3;
222   }
223
224 $list =~ s/^\s+//;
225 $list =~ s/\Q$delim$delim/>%%%%</g;
226 @split = split /\s*\Q$delim\E\s*/s, $list;
227
228 foreach $item (@split)
229   {
230   $item =~ s/>%%%%</$delim$delim/g;
231
232   if ($item =~ /^\s*#/)
233     {
234     $item =~ s/((?:^\s*#[^\n]*\n)+\s*)/$1! /mg;
235     $item =~ s/!\s*!//sg;
236     }
237   else
238     {
239     if ($item =~ /^\s*!(.*)/)
240       { $item = $1; }
241     else
242       { $item = "! " . $item; }
243     }
244   }
245
246 $" = " $delim \\\n    ";
247 $leadin .= " " if $leadin !~ /(^|\s)$/;
248 return "$leadin@split";
249 }
250
251
252
253 ##################################################
254 #   Prevent regex expansion in a list of things  #
255 ##################################################
256
257 # Can be tricky, because there may be comment lines in the list.
258 # Also, lists may have different delimiters.
259
260 sub no_expand_regex {
261 my($list) = $_[0];
262 my($delim) = ":";
263 my($leadin) = "";
264
265 return $list if ! defined $list;
266
267 $delim = $_[1] if (defined $_[1]);
268
269 my($is_route_list) = $delim eq ";";
270
271 ($list) = $list =~ /^"?(.*?)"?\s*$/s;      # Remove surrounding quotes
272 $list =~ s/\\\s*\n\s*//g;                  # Remove continuation markers
273
274 if ($list =~ /^(\s*<(\S)\s*)(.*)/s)
275   {
276   $leadin = $1;
277   $delim = $2;
278   $list = $3;
279   }
280
281 $list =~ s/^\s+//;
282 $list =~ s/\Q$delim$delim/>%%%%</g;
283 @split = split /\s*\Q$delim\E\s*/s, $list;
284
285 my($changed) = 0;
286 foreach $item (@split)
287   {
288   $item =~ s/>%%%%</$delim$delim/g;
289   if ($item =~ /^\^/)
290     {
291     # Fudge for route_list items
292
293     if ($is_route_list)
294       {
295       $item = "\\N$item";      # Only one item ...
296       }
297     else
298       {
299       $item = "\\N$item\\N";
300       }
301     $changed = 1;
302     }
303   }
304 print STDOUT
305   "#!!# Regular expressions enclosed in \\N...\\N to avoid expansion\n"
306     if $changed;
307
308 $" = " $delim \\\n    ";
309 $leadin .= " " if $leadin !~ /(^|\s)$/;
310 return "$leadin@split";
311 }
312
313
314
315 ##################################################
316 #      Sort out lookups in an address list       #
317 ##################################################
318
319 # Can be tricky, because there may be comment lines in the list.
320 # Also, lists may have different delimiters.
321
322 sub sort_address_list {
323 my($list) = $_[0];
324 my($name) = $_[1];
325 my($delim) = ":";
326 my($leadin) = "";
327 my($quoted) = 0;
328
329 return $list if ! defined $list;
330
331 if ($list =~ /^"(.*?)"\s*$/s)            # Remove surrounding quotes
332   {
333   $list = $1;
334   $quoted = 1;
335   }
336
337 $list =~ s/\\\s*\n\s*//g;                  # Remove continuation markers
338
339 if ($list =~ /^(\s*<(\S)\s*)(.*)/s)
340   {
341   $leadin = $1;
342   $delim = $2;
343   $list = $3;
344   }
345
346 $list =~ s/^\s+//;
347 $list =~ s/\Q$delim$delim/>%%%%</g;
348 @split = split /\s*\Q$delim\E\s*/s, $list;
349
350 foreach $item (@split)
351   {
352   $item =~ s/>%%%%</$delim$delim/g;
353   if ($item =~ /^\s*(?:partial-)?(\w+;.*)$/)
354     {
355     my($lookup) = $1;
356     if ($lookup =~ /^lsearch|^dbm|^cdb|^nis[^p]/)
357       {
358       &rubric();
359       print STDERR "\n" .
360 "** The Exim 3 \"$name\" option specifies an address\n" .
361 "   list that includes the item\n\n" .
362 "     $item\n\n" .
363 "   In Exim 4 address lists, single-key lookups without a local part just\n" .
364 "   look up the complete address. They don't also try the domain, as\n" .
365 "   happened in Exim 3. The item has been rewritten as two items to make\n" .
366 "   it behave in the same way as Exim 3, but you should check to see if\n" .
367 "   this is actually what you want.\n";
368
369       $item = "*\@$item $delim $lookup";
370       }
371     }
372   }
373
374 $" = " $delim \\\n    ";
375 $leadin .= " " if $leadin !~ /(^|\s)$/;
376
377 return $quoted? "\"$leadin@split\"" : "$leadin@split";
378 }
379
380
381
382 ##################################################
383 #       Quote a string against expansion         #
384 ##################################################
385
386 # Used for setting up new "domains" options
387
388 sub expquote {
389 my($s) = $_[0];
390 $s =~ s/\$/\\\$/sg;
391 $s =~ s/\\(?!\s*\n)/\\\\/sg;
392 return $s;
393 }
394
395
396
397 ##################################################
398 #          Dequote an option string              #
399 ##################################################
400
401 # If the original list is not quoted, do nothing.
402 # If it is quoted, just get rid of the quotes.
403
404 sub unquote {
405 my($s) = $_[0];
406 $s =~ s/^"(.*)"$/$1/s;
407 return $s;
408 }
409
410
411 ##################################################
412 #      Quote/dequote an option string            #
413 ##################################################
414
415 # If the original list is not quoted, quote it against expansion.
416 # If it is quoted, just get rid of the quotes. Also, indent any
417 # continuations.
418
419 sub acl_quote {
420 my($s) = $_[0];
421 $s = ($s =~ /^"(.*)"$/s)? $1 : &expquote($s);
422 $s =~ s/\n/\n  /g;
423 $s =~ s/\n\s{11,}/\n           /g;
424 return $s;
425 }
426
427
428 ##################################################
429 #       Handle abolished driver options          #
430 ##################################################
431
432 sub abolished {
433 my($hash) = shift @_;
434 my($name) = shift @_;
435 for $abolished (@_)
436   {
437   if (defined $$hash{$abolished})
438     {
439     &rubric();
440     print STDERR "\n" .
441 "** $name used the \"$abolished\" option, which no\n".
442 "   longer exists. The option has been removed.\n";
443     print STDOUT "#!!# $abolished option removed\n";
444     delete $$hash{$abolished};
445     }
446   }
447 }
448
449
450
451 ##################################################
452 #        Handle renamed driver options           #
453 ##################################################
454
455 sub renamed {
456 my($hash,$old,$new) = @_;
457 if (defined $$hash{$old})
458   {
459   print STDOUT "#!!# $old renamed $new\n";
460   $$hash{$new} = $$hash{$old};
461   delete $$hash{$old};
462   }
463 }
464
465
466
467 ##################################################
468 #      Comment on user names in require_files    #
469 ##################################################
470
471 sub check_require {
472 my($string, $name) = @_;
473
474 $string =~ s/::/[[[]]]/g;
475 my(@list) = split /:/, $string;
476 my($item);
477
478 for $item (@list)
479   {
480   if ($item =~ /^\s*[\w,]+\s*$/)
481     {
482     &rubric();
483     $item =~ s/^\s*//;
484     $item =~ s/\s*$//;
485     print STDERR "\n" .
486 "** A setting of require_files in the $name contains\n" .
487 "   what appears to be a user name ('$item'). The ability to check files\n" .
488 "   as a specific user is done differently in Exim 4. In fact, because the\n" .
489 "   routers run as root, you may not need this at all.\n"
490     }
491   }
492 }
493
494
495 ##################################################
496 #        Handle current and home directory       #
497 ##################################################
498
499 sub handle_current_and_home_directory {
500 my($hash,$driver,$name) = @_;
501
502 for ("current_directory", "home_directory")
503   {
504   if (defined $$hash{$_} && $$hash{$_} eq "check_local_user")
505     {
506     my($article) = (substr($driver, 0, 1) eq "a")? "an" : "a";
507     &rubric();
508     print STDERR "\n" .
509 "** The Exim 3 configuration contains $article '$driver' director called\n" .
510 "   '$name', which set '$_' to the special value\n" .
511 "   'check_local_user'. This facility has been abolished in Exim 4 because\n" .
512 "   it is no longer necessary. The setting has therefore been omitted. See\n" .
513 "   note X.\n";
514     delete $$hash{$_};
515     }
516   else
517     {
518     &renamed($hash, $_, "transport_$_");
519     }
520   }
521 }
522
523
524
525 ##################################################
526 #    Handle batch/bsmtp for appendfile/pipe      #
527 ##################################################
528
529 sub handle_batch_and_bsmtp{
530 my($hash) = @_;
531
532 if (defined $$hash{"bsmtp"})
533   {
534   if ($$hash{"bsmtp"} ne "none")
535     {
536     $$hash{"use_bsmtp"} = "true";
537     $$hash{"message_prefix"} = "\"HELO \$primary_host_name\\n\""
538       if defined $$hash{"bsmtp_helo"} && $$hash{"bsmtp_helo"} eq "true";
539     }
540
541   if ($$hash{"bsmtp"} eq "one")
542     {
543     delete $$hash{"batch"};
544     }
545   else
546     {
547     $$hash{"batch"} = $$hash{"bsmtp"};
548     }
549
550   delete $$hash{"bsmtp"};
551   delete $$hash{"bsmtp_helo"};
552   }
553
554 if (defined $$hash{"batch"} && $$hash{"batch"} ne "none")
555   {
556   $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"};
557   $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain";
558   }
559 else
560   {
561   $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"};
562   }
563 delete $$hash{"batch"};
564 }
565
566
567
568 ##################################################
569 #              Output one option                 #
570 ##################################################
571
572 sub outopt {
573 my($hash, $key, $no_expand) = @_;
574 my($data) = $$hash{$key};
575
576 print STDOUT "hide " if defined $$hash{"$key-hide"};
577
578 # Output booleans in the form that doesn't use "="
579
580 if ($data eq "true")
581   {
582   print STDOUT "$key\n";
583   }
584 elsif ($data eq "false")
585   {
586   print STDOUT "no_$key\n";
587   }
588 else
589   {
590   if ($no_expand)
591     {
592     printf STDOUT ("$key = %s\n", &no_expand_regex($data));
593     }
594   else
595     {
596     print STDOUT "$key = $data\n";
597     }
598   }
599 }
600
601
602
603 ##################################################
604 #       Output the options for one driver        #
605 ##################################################
606
607 # Put the "driver" option first
608
609 sub outdriver {
610 my($hash) = $_[0];
611 print STDOUT "  driver = $$hash{'driver'}\n";
612 foreach $key (sort keys %$hash)
613   {
614   next if $key eq "driver" || $key =~ /-hide$/;
615   print STDOUT "  ";
616   &outopt($hash, $key, 0);
617   }
618 }
619
620
621
622 ##################################################
623 #      Output a rewrite or a retry line          #
624 ##################################################
625
626 # These lines start with patterns which are now always expanded. If the
627 # pattern is a regex, arrange for it not to expand.
628
629 sub print_no_expand {
630 my($s) = $_[0];
631 if ($s =~ /^\^/)
632   {
633   if (!$escape_output)
634     {
635     &rubric();
636     print STDERR "\n" .
637 "** You have a retry or rewrite pattern that is a regular expression. Because\n" .
638 "   these patterns are now always expanded, you need to be sure that the\n" .
639 "   special characters in the regex are not interpreted by the expander.\n" .
640 "   \\N has been inserted at the start of the regex to prevent the rest of\n" .
641 "   it from being expanded.\n";
642     $escape_output = 1;
643     }
644   print STDOUT "\\N";
645   }
646 print STDOUT "$s\n";
647 }
648
649
650
651 ##################################################
652 #          Test a boolean main option            #
653 ##################################################
654
655 # This just saves a lot of typing
656
657 sub bool {
658 return defined $main{$_[0]} && $main{$_[0]} eq "true";
659 }
660
661
662
663 ##################################################
664 #                  Main program                  #
665 ##################################################
666
667 print STDERR "Runtime configuration file converter for Exim release 4.\n";
668
669 $transport_start = $director_start = $router_start = $retry_start
670   = $rewrite_start = $auth_start = 999999;
671
672 $macro_output = "";
673 $rubric_output = 0;
674 $errmsg_output = 0;
675 $key_output = 0;
676 $unk_output = 0;
677 $escape_output = 0;
678 $add_no_more = 0;
679 $add_caseful_local_part = 0;
680 $done_dns_check_names = 0;
681
682 $queue_only_load_was_present = 0;
683 $deliver_queue_load_max_was_present = 0;
684
685 # Read the entire file into an array
686
687 chomp(@c = <STDIN>);
688 $clen = scalar @c;
689
690 # Remove the standard comment that appears at the end of the default
691
692 if ($clen > 0 && $c[$clen-1] =~ /^#\s*End of Exim configuration file\s*/i)
693   {
694   pop @c;
695   $clen--;
696   }
697
698 # The first pass over the input fishes out all the options settings in the
699 # main, transport, director, and router sections, and places their values in
700 # associative arrays. It also notes the starting position of all the sections.
701
702 $prefix = "";
703 %main = ();
704 $hash = \%main;
705
706 for ($i = 0; $i < $clen; $i++)
707   {
708   # Change references to +allow_unknown and +warn_unknown into +include_unknown
709
710   if ($c[$i] =~ /\+(?:allow|warn)_unknown/)
711     {
712     if (!$unk_output)
713       {
714       &rubric();
715       print STDERR "\n" .
716 "** You have used '+allow_unknown' or '+warn_unknown' in a configuration\n" .
717 "   option. This has been converted to '+include_unknown', but the action\n" .
718 "   is different in Exim 4, so you should review all the relevant options.\n";
719       $unk_output = 1;
720       }
721     $c[$i] =~ s/\+(?:allow|warn)_unknown/+include_unknown/g;
722     }
723
724   # Any reference to $errmsg_recipient is changed to $bounce_recipient
725
726   if ($c[$i] =~ /\$errmsg_recipient/)
727     {
728     if (!$errmsg_output)
729       {
730       &rubric();
731       print STDERR "\n" .
732 "** References to \$errmsg_recipient have been changed to \$bounce_recipient\n";
733       $errmsg_output = 1;
734       }
735     $c[$i] =~ s/\$errmsg_recipient/\$bounce_recipient/g;
736     }
737
738
739   # Analyse the type of line
740
741   $type = &checkline($c[$i]);
742   next if $type eq "comment";
743
744   # Output a warning if $key is used
745
746   if ($c[$i] =~ /\$key/ && !$key_output)
747     {
748     &rubric();
749     print STDERR "\n" .
750 "** You have used '\$key' in a configuration option. This variable does not\n" .
751 "   exist in Exim 4. Instead, the value you need for your lookup will be\n" .
752 "   in one of the other variables such as '\$domain' or '\$host'. You will\n" .
753 "   need to edit the new configuration to sort this out.\n";
754     $key_output = 1;
755     }
756
757   # Save macro definitions so we can output them first; must handle
758   # continuations.
759
760   if ($type eq "macro")
761     {
762     $macro_output .= "$c[$i++]\n" while $c[$i] =~ /\\\s*$|^\s*#/;
763     $macro_output .= "$c[$i]\n";
764     }
765
766   # Handle end of section
767
768   elsif ($type eq "end")
769     {
770     if ($prefix eq "=rewrite")
771       {
772       $prefix = "a.";
773       $auth_start = $i + 1;
774       last;
775       }
776     elsif ($prefix eq "=retry")
777       {
778       $prefix = "=rewrite";
779       $rewrite_start = $i + 1;
780       }
781     elsif ($prefix eq "r.")
782       {
783       $prefix = "=retry";
784       $retry_start = $i + 1;
785       }
786     elsif ($prefix eq "d.")
787       {
788       $prefix = "r.";
789       $router_start = $i + 1;
790       }
791     elsif ($prefix eq "t.")
792       {
793       $prefix = "d.";
794       $director_start = $i + 1;
795       }
796     elsif ($prefix eq "")
797       {
798       $prefix = "t.";
799       $transport_start = $i + 1;
800       }
801     }
802
803   # Handle start of a new director, router or transport driver
804
805   elsif ($type eq "driver" && $prefix !~ /^=/)
806     {
807     $hash = {};
808     if (defined $driverlist{"$prefix$name"})
809       {
810       die "*** There are two drivers with the name \"$name\"\n";
811       }
812     $driverlist{"$prefix$name"} = $hash;
813     $first_director = $name if !defined $first_director && $prefix eq "d.";
814     }
815
816   # Handle definition of an option; we must pull in any continuation
817   # strings, and save the value in the current hash. Note if the option
818   # is hidden.
819
820   elsif ($type eq "option")
821     {
822     my($nextline) = "";
823
824     while ($i < $clen - 1 && ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/))
825       {
826       $nextline = $c[++$i];
827       $rest .= "\n$nextline";
828       }
829
830     $$hash{$name} = $rest;
831     $$hash{"$name-hide"} = 1 if $hide ne "";
832     }
833   }
834
835
836 # Generate the new configuration. Start with a warning rubric.
837
838 print STDOUT "#!!# This file is output from the convert4r4 script, which tries\n";
839 print STDOUT "#!!# to convert Exim 3 configurations into Exim 4 configurations.\n";
840 print STDOUT "#!!# However, it is not perfect, especially with non-simple\n";
841 print STDOUT "#!!# configurations. You must check it before running it.\n";
842 print STDOUT "\n\n";
843
844 # Output the macro definitions
845
846 if ($macro_output ne "")
847   {
848   print STDOUT "#!!# All macro definitions have been gathered here to ensure\n";
849   print STDOUT "#!!# they precede any references to them.\n\n";
850   print STDOUT "$macro_output\n";
851   }
852
853 # Output some default pointers to ACLs for RCPT and DATA time. If no Exim 3
854 # options that apply are set, non-restricting ACLs are generated.
855
856 print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n";
857 print STDOUT "#!!# are used for incoming SMTP messages - after the RCPT and DATA\n";
858 print STDOUT "#!!# commands, respectively.\n\n";
859
860 print STDOUT "acl_smtp_rcpt = check_recipient\n";
861 print STDOUT "acl_smtp_data = check_message\n\n";
862
863 if (defined $main{"auth_over_tls_hosts"})
864   {
865   print STDOUT "#!!# This option specifies the Access Control List (ACL) that\n";
866   print STDOUT "#!!# is used after an AUTH command.\n\n";
867   print STDOUT "acl_smtp_auth = check_auth\n\n";
868   }
869
870 if (&bool("smtp_verify") ||
871     defined $main{"smtp_etrn_hosts"} ||
872     defined $main{"smtp_expn_hosts"})
873   {
874   print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n";
875   print STDOUT "#!!# are used to control the ETRN, EXPN, and VRFY commands.\n";
876   print STDOUT "#!!# Where no ACL is defined, the command is locked out.\n\n";
877
878   print STDOUT "acl_smtp_etrn = check_etrn\n" if defined $main{"smtp_etrn_hosts"};
879   print STDOUT "acl_smtp_expn = check_expn\n" if defined $main{"smtp_expn_hosts"};
880   print STDOUT "acl_smtp_vrfy = check_vrfy\n" if &bool("smtp_verify");
881   print STDOUT "\n";
882   }
883
884 # If local_domains was set, get its value; otherwise set to "@". Add into it
885 # appropriate magic for local_domains_include_host[_literals].
886
887 $local_domains = (defined $main{"local_domains"})? $main{"local_domains"} : "@";
888
889 $ldsep = ":";
890 if ($local_domains =~ /^\s*<(.)\s*(.*)/s)
891   {
892   $ldsep = $1;
893   $local_domains = $2;
894   }
895
896 $local_domains = "\@[] $ldsep " . $local_domains
897   if defined $main{"local_domains_include_host_literals"} &&
898      $main{"local_domains_include_host_literals"} eq "true";
899
900 $local_domains = "\@ $ldsep " . $local_domains
901   if defined $main{"local_domains_include_host"} &&
902      $main{"local_domains_include_host"} eq "true";
903
904 $local_domains = "<$ldsep " . $local_domains if $ldsep ne ":";
905
906 # Output a domain list setting for these domains, provided something is defined
907
908 if ($local_domains !~ /^\s*$/)
909   {
910   print STDOUT "#!!# This setting defines a named domain list called\n";
911   print STDOUT "#!!# local_domains, created from the old options that\n";
912   print STDOUT "#!!# referred to local domains. It will be referenced\n";
913   print STDOUT "#!!# later on by the syntax \"+local_domains\".\n";
914   print STDOUT "#!!# Other domain and host lists may follow.\n\n";
915
916   printf STDOUT ("domainlist local_domains = %s\n\n",
917     &no_expand_regex($local_domains));
918   }
919
920 $relay_domains = (defined $main{"relay_domains"})? $main{"relay_domains"} : "";
921
922 $ldsep = ":";
923 if ($relay_domains =~ /^\s*<(.)\s*(.*)/s)
924   {
925   $ldsep = $1;
926   }
927
928 if (defined $main{"relay_domains_include_local_mx"})
929   {
930   $relay_domains .= ($relay_domains =~ /^\s*$/)? "\@mx_any" :
931     " $ldsep \@mx_any";
932   }
933
934 printf STDOUT ("domainlist relay_domains = %s\n",
935   &no_expand_regex($relay_domains))
936     if $relay_domains !~ /^\s*$/;
937
938
939 # If ignore_errmsg_errors is set, we are going to force 0s as the value
940 # for ignore_errmsg_errors_after, so arrange to skip any other value.
941
942 push @skipped_options, "ignore_errmsg_errors_after"
943    if &bool("ignore_errmsg_errors");
944
945
946 # If rbl_domains is set, split it up and generate six lists:
947 #   rbl_warn_domains, rbl_warn_domains_skiprelay
948 #   rbl_reject_domains, rbl_reject_domains_skiprelay
949 #   rbl_accept_domains, rbl_accept_domains_skiprelay
950
951 if (defined $main{"rbl_domains"})
952   {
953   my($s) = &unquote($main{"rbl_domains"});
954   $s =~ s/\s*\\\s*\n\s*/ /g;
955   my(@list) = split /\s*:\s*/, $s;
956
957   foreach $d (@list)
958     {
959     my(@sublist) = split /\//, $d;
960     my($name) = shift @sublist;
961     my($warn) = 0;
962     if (defined $main{"rbl_reject_recipients"})
963       {
964       $warn = $main{"rbl_reject_recipients"} ne "true";
965       }
966
967     foreach $o (@sublist)
968       {
969       $warn = 1 if $o eq "warn";
970       $warn = 0 if $o eq "reject";
971       $warn = 2 if $o eq "accept";
972       $skiprelay = 1 if $o eq "skiprelay";
973       }
974
975     if ($skiprelay)
976       {
977       if ($warn == 0)
978         {
979         $rbl_reject_skiprelay .= ((defined $rbl_reject_skiprelay)? ":":"").$name;
980         }
981       elsif ($warn == 1)
982         {
983         $rbl_warn_skiprelay .= ((defined $rbl_warn_skiprelay)? ":":"").$name;
984         }
985       elsif ($warn == 2)
986         {
987         $rbl_accept_skiprelay .= ((defined $rbl_accept_skiprelay)? ":":"").$name;
988         }
989       }
990     else
991       {
992       if ($warn == 0)
993         {
994         $rbl_reject_domains .= ((defined $rbl_reject_domains)? ":":"").$name;
995         }
996       elsif ($warn == 1)
997         {
998         $rbl_warn_domains .= ((defined $rbl_warn_domains)? ":":"").$name;
999         }
1000       elsif ($warn == 2)
1001         {
1002         $rbl_accept_domains .= ((defined $rbl_accept_domains)? ":":"").$name;
1003         }
1004       }
1005     }
1006   }
1007
1008
1009 # Output host list settings
1010
1011 printf STDOUT ("hostlist auth_hosts = %s\n",
1012   &no_expand_regex($main{"auth_hosts"}))
1013     if defined $main{"auth_hosts"};
1014 printf STDOUT ("hostlist rbl_hosts = %s\n",
1015   &no_expand_regex($main{"rbl_hosts"}))
1016     if defined $main{"rbl_hosts"};
1017 printf STDOUT ("hostlist relay_hosts = %s\n",
1018   &no_expand_regex($main{"host_accept_relay"}))
1019     if defined $main{"host_accept_relay"};
1020 printf STDOUT ("hostlist auth_relay_hosts = %s\n",
1021   &no_expand_regex($main{"host_auth_accept_relay"}))
1022     if defined $main{"host_auth_accept_relay"};
1023
1024 printf STDOUT ("hostlist auth_over_tls_hosts = %s\n",
1025   &no_expand_regex($main{"auth_over_tls_hosts"}))
1026     if defined $main{"auth_over_tls_hosts"};
1027 printf STDOUT ("hostlist tls_hosts = %s\n",
1028   &no_expand_regex($main{"tls_hosts"}))
1029     if defined $main{"tls_hosts"};
1030 printf STDOUT ("hostlist tls_relay_hosts = %s\n",
1031   &no_expand_regex($main{"tls_host_accept_relay"}))
1032     if defined $main{"tls_host_accept_relay"};
1033
1034 print STDOUT "\n";
1035
1036
1037 # Convert various logging options
1038
1039 $log_selector = "";
1040 $sep = " \\\n             ";
1041
1042 if (defined $main{"log_level"})
1043   {
1044   my($level) = $main{"log_level"};
1045   $log_selector .= "$sep -retry_defer$sep -skip_delivery" if $level < 5;
1046   $log_selector .= "$sep -lost_incoming_connection$sep -smtp_syntax_error" .
1047                    "$sep -delay_delivery" if $level < 4;
1048   $log_selector .= "$sep -size_reject" if $level < 2;
1049   }
1050
1051 $log_selector .= "$sep -queue_run"
1052   if defined $main{"log_queue_run_level"} &&
1053      defined $main{"log_level"} &&
1054      $main{"log_queue_run_level"} > $main{"log_level"};
1055
1056 $log_selector .= "$sep +address_rewrite"       if &bool("log_rewrites");
1057 $log_selector .= "$sep +all_parents"           if &bool("log_all_parents");
1058 $log_selector .= "$sep +arguments"             if &bool("log_arguments");
1059 $log_selector .= "$sep +incoming_port"         if &bool("log_incoming_port");
1060 $log_selector .= "$sep +incoming_interface"    if &bool("log_interface");
1061 $log_selector .= "$sep +received_sender"       if &bool("log_received_sender");
1062 $log_selector .= "$sep +received_recipients"   if &bool("log_received_recipients");
1063 $log_selector .= "$sep +sender_on_delivery"    if &bool("log_sender_on_delivery");
1064 $log_selector .= "$sep +smtp_confirmation"     if &bool("log_smtp_confirmation");
1065 $log_selector .= "$sep +smtp_connection"       if &bool("log_smtp_connections");
1066 $log_selector .= "$sep +smtp_syntax_error"     if &bool("log_smtp_syntax_errors");
1067 $log_selector .= "$sep +subject"               if &bool("log_subject");
1068 $log_selector .= "$sep +tls_cipher"            if &bool("tls_log_cipher");
1069 $log_selector .= "$sep +tls_peerdn"            if &bool("tls_log_peerdn");
1070
1071
1072 if ($log_selector ne "")
1073   {
1074   print STDOUT "#!!# All previous logging options are combined into a single\n"
1075              . "#!!# option in Exim 4. This setting is an approximation to\n"
1076              . "#!!# the previous state - some logging has changed.\n\n";
1077   print STDOUT "log_selector = $log_selector\n\n";
1078   }
1079
1080 # If deliver_load_max is set, replace it with queue_only_load (taking the
1081 # lower value if both set) and also set deliver_queue_load_max if it is
1082 # not already set. When scanning for output, deliver_load_max is skipped.
1083
1084 if (defined $main{"deliver_load_max"})
1085   {
1086   &rubric();
1087   print STDERR "\n" .
1088 "** deliver_load_max is abolished in Exim 4.\n";
1089
1090   if (defined $main{"queue_only_load"})
1091     {
1092     $queue_only_load_was_present = 1;
1093     if ($main{"queue_only_load"} < $main{"deliver_load_max"})
1094       {
1095       print STDERR
1096 "   As queue_only_load was set lower, deliver_load_max is just removed.\n";
1097       }
1098     else
1099       {
1100       print STDERR
1101 "   As queue_only_load was set higher, it's value has been replaced by\n" .
1102 "   the value of deliver_load_max.\n";
1103       $main{"queue_only_load"} = $main{"deliver_load_max"};
1104       }
1105     }
1106   else
1107     {
1108     print STDERR
1109 "   queue_only_load has been set to the load value.\n";
1110     $main{"queue_only_load"} = $main{"deliver_load_max"};
1111     }
1112
1113   if (!defined $main{"deliver_queue_load_max"})
1114     {
1115     print STDERR
1116 "   deliver_queue_load_max has been set to the value of queue_only_load.\n";
1117     $main{"deliver_queue_load_max"} = $main{"queue_only_load"};
1118     }
1119   else
1120     {
1121     $deliver_queue_load_max_was_present = 1;
1122     }
1123   }
1124
1125
1126 # Now we scan through the various parts of the file again, making changes
1127 # as necessary.
1128
1129 # -------- The main configuration --------
1130
1131 $prefix = "";
1132 MainLine: for ($i = 0; $i < $clen; $i++)
1133   {
1134   my($nextline) = "";
1135   $type = &checkline($c[$i]);
1136   last if $type eq "end";
1137
1138   if ($type eq "macro")
1139     {
1140     $i++ while $c[$i] =~ /\\\s*$|^\s*#/;
1141     next;
1142     }
1143
1144   if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; }
1145
1146   # Collect any continuation lines for an option setting
1147
1148   while ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/)
1149     {
1150     $nextline = $c[++$i];
1151     $rest .= "\n$nextline";
1152     }
1153
1154   $rest =~ s/^=\s*//;
1155
1156   # Deal with main options that are skipped (they are used in other
1157   # options in other places).
1158
1159   for $skipped (@skipped_options)
1160     {
1161     next MainLine if $name eq $skipped;
1162     }
1163
1164   # Deal with main options that are totally abolished
1165
1166   for $abolished (@abolished_options)
1167     {
1168     if ($name eq $abolished)
1169       {
1170       &rubric();
1171       print STDERR "\n" .
1172 "** The $name option no longer exists, and has no equivalent\n" .
1173 "   in Exim 4.\n";
1174       next MainLine;
1175       }
1176     }
1177
1178   # There is a special case for rbl_warn_header
1179
1180   if ($name eq "rbl_warn_header")
1181     {
1182     &rubric();
1183     print STDERR "\n" .
1184 "** The $name option no longer exists. In Exim 4 you can achieve the\n" .
1185 "   effect by adding a suitable \"message\" statement in the ACL.\n";
1186     }
1187
1188   # There is a special case for sender_reject and host_reject
1189
1190   elsif ($name eq "sender_reject" || $name eq "host_reject")
1191     {
1192     &rubric();
1193     print STDERR "\n" .
1194 "** The $name option no longer exists. Its data has been used in\n" .
1195 "   an Access Control List as if it were in ${name}_recipients.\n";
1196     }
1197
1198   # And a special message for prohibition_message
1199
1200   elsif ($name eq "prohibition_message")
1201     {
1202     &rubric();
1203     print STDERR "\n" .
1204 "** The prohibition_message option no longer exists. The facility is\n" .
1205 "   provided in a different way in Exim 4, via the \"message\" keyword\n" .
1206 "   in Access Control Lists. It isn't possible to do an automatic conversion,\n" .
1207 "   so the value of prohibition_message has been ignored. You will have to\n" .
1208 "   modify the ACLs if you want to reinstate the feature.\n";
1209     }
1210
1211   # auth_always_advertise gets converted to auth_advertise_hosts
1212
1213   elsif ($name eq "auth_always_advertise")
1214     {
1215     print STDOUT "#!!# auth_always_advertise converted to auth_advertise_hosts\n";
1216     if (&bool("auth_always_advertise"))
1217       {
1218       print STDOUT "auth_advertise_hosts = *\n";
1219       }
1220     else
1221       {
1222       $sep = "";
1223       print STDOUT "auth_advertise_hosts =";
1224       if (defined $main{"auth_hosts"})
1225         {
1226         print STDOUT "$sep +auth_hosts";
1227         $sep = " :";
1228         }
1229       if (defined $main{"host_accept_relay"})
1230         {
1231         print STDOUT "$sep !+relay_hosts";
1232         $sep = " :";
1233         }
1234       if (defined $main{"host_auth_accept_relay"})
1235         {
1236         print STDOUT "$sep +auth_relay_hosts";
1237         }
1238       print STDOUT "\n";
1239       }
1240     }
1241
1242   # Deal with main options that have to be rewritten
1243
1244   elsif ($name eq "accept_timeout")
1245     {
1246     print STDOUT "#!!# accept_timeout renamed receive_timeout\n";
1247     print STDOUT "receive_timeout = $rest\n";
1248     }
1249
1250   elsif ($name eq "collapse_source_routes")
1251     {
1252     print STDOUT "#!!# collapse_source_routes removed\n";
1253     print STDOUT "#!!# It has been a no-op since 3.10.\n";
1254     }
1255
1256   elsif ($name eq "daemon_smtp_service")
1257     {
1258     print STDOUT "#!!# daemon_smtp_service renamed daemon_smtp_port\n";
1259     print STDOUT "daemon_smtp_port = $rest\n";
1260     }
1261
1262   elsif ($name eq "dns_check_names" || $name eq "dns_check_names_pattern")
1263     {
1264     if (!$done_dns_check_names)
1265       {
1266       if (&bool("dns_check_names"))
1267         {
1268         if (defined $main{"dns_check_names_pattern"})
1269           {
1270           &outopt(\%main, "dns_check_names_pattern", 0);
1271           }
1272         }
1273
1274       else
1275         {
1276         print STDOUT "#!!# dns_check_names has been abolished\n";
1277         print STDOUT "#!!# setting dns_check_pattern empty to turn off check\n";
1278         print STDOUT "dns_check_names_pattern =\n";
1279         }
1280
1281       $done_dns_check_names = 1;
1282       }
1283     }
1284
1285   elsif ($name eq "deliver_load_max")
1286     {
1287     print STDOUT "deliver_queue_load_max = $main{'deliver_queue_load_max'}\n"
1288       if !$deliver_queue_load_max_was_present;
1289     print STDOUT "queue_only_load = $main{'queue_only_load'}\n"
1290       if !$queue_only_load_was_present;
1291     }
1292
1293   elsif ($name eq "errmsg_file")
1294     {
1295     print STDOUT "#!!# errmsg_file renamed bounce_message_file\n";
1296     print STDOUT "bounce_message_file = $rest\n";
1297     }
1298
1299   elsif ($name eq "errmsg_text")
1300     {
1301     print STDOUT "#!!# errmsg_text renamed bounce_message_text\n";
1302     print STDOUT "bounce_message_text = $rest\n";
1303     }
1304
1305   elsif ($name eq "forbid_domain_literals")
1306     {
1307     print STDOUT "#!!# forbid_domain_literals replaced by allow_domain_literals\n";
1308     print STDOUT "allow_domain_literals = ",
1309           &bool("forbid_domain_literals")? "false" : "true", "\n";
1310     }
1311
1312   elsif ($name eq "freeze_tell_mailmaster")
1313     {
1314     print STDOUT "#!!# freeze_tell_mailmaster replaced by freeze_tell\n";
1315     if (&bool("freeze_tell_mailmaster"))
1316       {
1317       print STDOUT "freeze_tell = ",
1318         ((defined $main{"errors_address"})?
1319           $main{"errors_address"} : "postmaster"), "\n";
1320       }
1321     else
1322       {
1323       print STDOUT "#!!# freeze_tell is unset by default\n";
1324       }
1325     }
1326
1327   elsif ($name eq "helo_verify")
1328     {
1329     print STDOUT "#!!# helo_verify renamed helo_verify_hosts\n";
1330     printf STDOUT ("helo_verify_hosts = %s\n", &no_expand_regex($rest));
1331     }
1332
1333   elsif ($name eq "ignore_errmsg_errors")
1334     {
1335     print STDOUT "ignore_bounce_errors_after = 0s\n";
1336     }
1337
1338   elsif ($name eq "ignore_errmsg_errors_after")
1339     {
1340     print STDOUT "#!!# ignore_errmsg_errors_after renamed ignore_bounce_errors_after\n";
1341     print STDOUT "ignore_bounce_errors_after = $rest\n";
1342     }
1343
1344   elsif ($name eq "ipv4_address_lookup" || $name eq "dns_ipv4_lookup")
1345     {
1346     print STDOUT "#!!# $name changed to dns_ipv4_lookup\n"
1347       if $name eq "ipv4_address_lookup";
1348     print STDOUT "#!!# dns_ipv4_lookup is now a domain list\n";
1349     if (&bool($name))
1350       {
1351       print STDOUT "dns_ipv4_lookup = *\n";
1352       }
1353     else
1354       {
1355       print STDOUT "#!!# default for dns_ipv4_lookup is unset\n";
1356       }
1357     }
1358
1359   elsif ($name eq "locally_caseless")
1360     {
1361     print STDOUT "#!!# locally_caseless removed\n";
1362     print STDOUT "#!!# caseful_local_part will be added to ex-directors\n";
1363     $add_caseful_local_part = 1;
1364     }
1365
1366   elsif ($name eq "message_filter_directory2_transport")
1367     {
1368     print STDOUT "#!!# message_filter_directory2_transport removed\n";
1369     }
1370
1371   elsif ($name =~ /^message_filter(.*)/)
1372     {
1373     print STDOUT "#!!# $name renamed system_filter$1\n";
1374     print STDOUT "system_filter$1 = $rest\n";
1375     }
1376
1377   elsif ($name eq "queue_remote_domains")
1378     {
1379     print STDOUT "#!!# queue_remote_domains renamed queue_domains\n";
1380     printf STDOUT ("queue_domains = %s\n", &no_expand_regex($rest));
1381     }
1382
1383   elsif ($name eq "receiver_unqualified_hosts")
1384     {
1385     print STDOUT "#!!# receiver_unqualified_hosts renamed recipient_unqualified_hosts\n";
1386     printf STDOUT ("recipient_unqualified_hosts = %s\n",
1387       &no_expand_regex($rest));
1388     }
1389
1390   elsif ($name eq "remote_sort")
1391     {
1392     print STDOUT "#!!# remote_sort renamed remote_sort_domains\n";
1393     printf STDOUT ("remote_sort_domains = %s\n", &no_expand_regex($rest));
1394     }
1395
1396   elsif ($name eq "security")
1397     {
1398     if ($rest eq "unprivileged")
1399       {
1400       print STDOUT "#!!# security=unprivileged changed to deliver_drop_privilege\n";
1401       print STDOUT "deliver_drop_privilege\n";
1402       }
1403     else
1404       {
1405       &rubric();
1406       print STDERR "\n" .
1407 "** The 'security' option no longer exists.\n";
1408       }
1409     }
1410
1411   elsif ($name eq "timestamps_utc")
1412     {
1413     print STDOUT "#!!# timestamps_utc changed to use timezone\n";
1414     print STDOUT "timezone = utc\n";
1415     }
1416
1417   elsif ($name eq "untrusted_set_sender")
1418     {
1419     print STDOUT "#!!# untrusted_set_sender is now a list of what can be set\n";
1420     print STDOUT "#!!# The default is an empty list.\n";
1421     if (&bool("untrusted_set_sender"))
1422       {
1423       print STDOUT "untrusted_set_sender = *\n";
1424       }
1425     }
1426
1427   elsif ($name eq "warnmsg_file")
1428     {
1429     print STDOUT "#!!# warnmsg_file renamed warn_message_file\n";
1430     print STDOUT "warn_message_file = $rest\n";
1431     }
1432
1433   # Remaining options just get copied unless they are one of those that's
1434   # a list where any regular expressions have to be escaped.
1435
1436   else
1437     {
1438     my($no_expand) = 0;
1439     foreach $o (@list_options)
1440       {
1441       if ($name eq $o)
1442         {
1443         $no_expand = 1;
1444         last;
1445         }
1446       }
1447     &outopt(\%main, $name, $no_expand);
1448     }
1449   }
1450
1451
1452 # -------- The ACL configuration --------
1453
1454 print STDOUT "\n";
1455 print STDOUT "#!!#######################################################!!#\n";
1456 print STDOUT "#!!# This new section of the configuration contains ACLs #!!#\n";
1457 print STDOUT "#!!# (Access Control Lists) derived from the Exim 3      #!!#\n";
1458 print STDOUT "#!!# policy control options.                             #!!#\n";
1459 print STDOUT "#!!#######################################################!!#\n";
1460
1461 print STDOUT "\n";
1462 print STDOUT "#!!# These ACLs are crudely constructed from Exim 3 options.\n";
1463 print STDOUT "#!!# They are almost certainly not optimal. You should study\n";
1464 print STDOUT "#!!# them and rewrite as necessary.\n";
1465
1466 print STDOUT "\nbegin acl\n\n";
1467
1468
1469 # Output an ACL for use after the RCPT command. This combines all the previous
1470 # policy checking options.
1471
1472 print STDOUT "#!!# ACL that is used after the RCPT command\n";
1473 print STDOUT "check_recipient:\n";
1474
1475 print STDOUT "  # Exim 3 had no checking on -bs messages, so for compatibility\n";
1476 print STDOUT "  # we accept if the source is local SMTP (i.e. not over TCP/IP).\n";
1477 print STDOUT "  # We do this by testing for an empty sending host field.\n";
1478 print STDOUT "  accept  hosts = :\n";
1479
1480 if (defined $main{"tls_verify_ciphers"})
1481   {
1482   print STDOUT "  deny    ";
1483   print STDOUT "hosts = $main{'tls_verify_hosts'}\n         "
1484     if defined $main{"tls_verify_hosts"};
1485   print STDOUT " encrypted = *\n         ";
1486   print STDOUT "!encrypted = $main{'tls_verify_ciphers'}\n";
1487   }
1488
1489 print STDOUT "  deny    hosts = +auth_hosts\n" .
1490              "          message = authentication required\n" .
1491              "         !authenticated = *\n"
1492   if defined $main{"auth_hosts"};
1493
1494 print STDOUT "  deny    hosts = +tls_hosts\n" .
1495              "          message = encryption required\n" .
1496              "         !encrypted = *\n"
1497   if defined $main{"tls_hosts"};
1498
1499 printf STDOUT ("  accept  recipients = %s\n",
1500   &acl_quote(&sort_address_list($main{"recipients_reject_except"},
1501     "recipients_reject_except")))
1502       if defined $main{"recipients_reject_except"};
1503
1504 printf STDOUT ("  accept  senders = %s\n",
1505   &acl_quote(&sort_address_list($main{"recipients_reject_except_senders"},
1506     "recipients_reject_except_senders")))
1507       if defined $main{"recipients_reject_except_senders"};
1508
1509 printf STDOUT ("  deny    hosts = %s\n", &acl_quote($main{"host_reject"}))
1510   if defined $main{"host_reject"};
1511
1512 printf STDOUT ("  deny    hosts = %s\n",
1513   &acl_quote($main{"host_reject_recipients"}))
1514     if defined $main{"host_reject_recipients"};
1515
1516 if (defined $main{"rbl_domains"})
1517   {
1518   my($msg) = "message = host is listed in \$dnslist_domain\n          ";
1519   my($hlist) = (defined $main{"rbl_hosts"})?
1520     "hosts = +rbl_hosts\n          " : "";
1521
1522   print STDOUT "  accept  ${hlist}dnslists = $rbl_accept_domains\n"
1523     if defined $rbl_accept_domains;
1524   print STDOUT "  deny    ${hlist}${msg}dnslists = $rbl_reject_domains\n"
1525     if defined $rbl_reject_domains;
1526   print STDOUT "  warn    ${hlist}" .
1527     "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" .
1528     "          dnslists = $rbl_warn_domains\n"
1529       if defined $rbl_warn_domains;
1530
1531   if (defined $main{"host_accept_relay"})
1532     {
1533     $hlist .= "hosts = !+relay_hosts\n          ";
1534     print STDOUT "  accept  ${hlist}dnslists = $rbl_accept_skiprelay\n"
1535       if defined $rbl_accept_skiprelay;
1536     print STDOUT "  deny    ${hlist}${msg}dnslists = $rbl_reject_skiprelay\n"
1537       if defined $rbl_reject_skiprelay;
1538     print STDOUT "  warn    ${hlist}" .
1539       "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" .
1540       "          dnslists = $rbl_warn_skiprelay\n"
1541         if defined $rbl_warn_skiprelay;
1542     }
1543   }
1544
1545 printf STDOUT ("  deny    senders = %s\n",
1546   &acl_quote(&sort_address_list($main{"sender_reject"}, "sender_reject")))
1547     if defined $main{"sender_reject"};
1548
1549 printf STDOUT ("  deny    senders = %s\n",
1550   &acl_quote(&sort_address_list($main{"sender_reject_recipients"},
1551     "sender_reject_recipients")))
1552       if defined $main{"sender_reject_recipients"};
1553
1554 if (&bool("sender_verify"))
1555   {
1556   if (defined $main{"sender_verify_hosts_callback"} &&
1557       defined $main{"sender_verify_callback_domains"})
1558     {
1559     printf STDOUT ("  deny    hosts = %s\n",
1560       &acl_quote($main{"sender_verify_hosts_callback"}));
1561     printf STDOUT ("          sender_domains = %s\n",
1562       &acl_quote($main{"sender_verify_callback_domains"}));
1563     print  STDOUT  "         !verify = sender/callout";
1564     print  STDOUT  "=$main{\"sender_verify_callback_timeout\"}"
1565       if defined $main{"sender_verify_callback_timeout"};
1566     print  STDOUT  "\n";
1567     }
1568
1569   if (defined $main{"sender_verify_hosts"})
1570     {
1571     printf STDOUT ("  deny    hosts = %s\n",
1572       &acl_quote($main{"sender_verify_hosts"}));
1573     print  STDOUT  "         !verify = sender\n";
1574     }
1575   else
1576     {
1577     print STDOUT "  require verify = sender\n";
1578     }
1579   }
1580
1581 if (&bool("receiver_verify"))
1582   {
1583   print  STDOUT  "  deny    message = unrouteable address\n";
1584   printf STDOUT ("          recipients = %s\n",
1585     &acl_quote(&sort_address_list($main{"receiver_verify_addresses"},
1586       "receiver_verify_addresses")))
1587         if defined $main{"receiver_verify_addresses"};
1588   printf STDOUT ("          hosts = %s\n",
1589     &acl_quote($main{"receiver_verify_hosts"}))
1590       if defined $main{"receiver_verify_hosts"};
1591   printf STDOUT ("          senders = %s\n",
1592     &acl_quote(&sort_address_list($main{"receiver_verify_senders"},
1593       "receiver_verify_senders")))
1594         if defined $main{"receiver_verify_senders"};
1595   print  STDOUT  "         !verify = recipient\n";
1596   }
1597
1598 print STDOUT "  accept  domains = +local_domains\n"
1599   if $local_domains !~ /^\s*$/;
1600
1601 print STDOUT "  accept  domains = +relay_domains\n"
1602   if $relay_domains !~ /^\s*$/;
1603
1604 if (defined $main{"host_accept_relay"})
1605   {
1606   if (defined $main{"sender_address_relay"})
1607     {
1608     if (defined $main{"sender_address_relay_hosts"})
1609       {
1610       printf STDOUT ("  accept  hosts = %s\n",
1611         &acl_quote($main{"sender_address_relay_hosts"}));
1612       print  STDOUT  "          endpass\n";
1613       print  STDOUT  "          message = invalid sender\n";
1614       printf STDOUT ("          senders = %s\n",
1615         &acl_quote(&sort_address_list($main{"sender_address_relay"},
1616           "sender_address_relay")));
1617       print  STDOUT  "  accept  hosts = +relay_hosts\n";
1618       }
1619     else
1620       {
1621       print  STDOUT  "  accept  hosts = +relay_hosts\n";
1622       print  STDOUT  "          endpass\n";
1623       print  STDOUT  "          message = invalid sender\n";
1624       printf STDOUT ("          senders = %s\n",
1625         &acl_quote(&sort_address_list($main{"sender_address_relay"},
1626           "sender_address_relay")));
1627       }
1628     }
1629   else
1630     {
1631     print STDOUT "  accept  hosts = +relay_hosts\n";
1632     }
1633   }
1634
1635 print STDOUT "  accept  hosts = +auth_relay_hosts\n" .
1636              "          endpass\n" .
1637              "          message = authentication required\n" .
1638              "          authenticated = *\n"
1639   if defined $main{"host_auth_accept_relay"};
1640
1641 print STDOUT "  accept  hosts = +tls_relay_hosts\n" .
1642              "          endpass\n" .
1643              "          message = encryption required\n" .
1644              "          encrypted = *\n"
1645   if defined $main{"tls_host_accept_relay"};
1646
1647 print STDOUT "  deny    message = relay not permitted\n\n";
1648
1649
1650 # Output an ACL for use after the DATA command. This is concerned with
1651 # header checking.
1652
1653 print STDOUT "#!!# ACL that is used after the DATA command\n";
1654 print STDOUT "check_message:\n";
1655
1656 # Default for headers_checks_fail is true
1657
1658 if (!defined $main{"headers_checks_fail"} ||
1659     $main{"headers_checks_fail"} eq "true")
1660   {
1661   print STDOUT "  require verify = header_syntax\n"
1662     if &bool("headers_check_syntax");
1663   print STDOUT "  require verify = header_sender\n"
1664     if &bool("headers_sender_verify");
1665   print STDOUT "  accept  senders = !:\n  require verify = header_sender\n"
1666     if &bool("headers_sender_verify_errmsg");
1667   }
1668 else
1669   {
1670   print STDOUT "  warn    !verify = header_syntax\n"
1671     if &bool("headers_check_syntax");
1672   print STDOUT "  warn    !verify = header_sender\n"
1673     if &bool("headers_sender_verify");
1674   print STDOUT "  accept  senders = !:\n  warn    !verify = header_sender\n"
1675     if &bool("headers_sender_verify_errmsg");
1676   }
1677
1678 print STDOUT "  accept\n\n";
1679
1680
1681 # Output an ACL for AUTH if required
1682
1683 if (defined $main{"auth_over_tls_hosts"})
1684   {
1685   print STDOUT "#!!# ACL that is used after the AUTH command\n" .
1686                "check_auth:\n" .
1687                "  accept  hosts = +auth_over_tls_hosts\n" .
1688                "          endpass\n" .
1689                "          message = STARTTLS required before AUTH\n" .
1690                "          encrypted = *\n" .
1691                "  accept\n";
1692   }
1693
1694
1695 # Output ACLs for ETRN, EXPN, and VRFY if required
1696
1697 if (defined $main{"smtp_etrn_hosts"})
1698   {
1699   print STDOUT "#!!# ACL that is used after the ETRN command\n" .
1700                "check_etrn:\n";
1701   print STDOUT "  deny    hosts = +auth_hosts\n" .
1702                "          message = authentication required\n" .
1703                "         !authenticated = *\n"
1704     if defined $main{"auth_hosts"};
1705   print STDOUT "  accept  hosts = $main{\"smtp_etrn_hosts\"}\n\n";
1706   }
1707
1708 if (defined $main{"smtp_expn_hosts"})
1709   {
1710   print STDOUT "#!!# ACL that is used after the EXPN command\n" .
1711                "check_expn:\n";
1712   print STDOUT "  deny    hosts = +auth_hosts\n" .
1713                "          message = authentication required\n" .
1714                "         !authenticated = *\n"
1715     if defined $main{"auth_hosts"};
1716   print STDOUT "  accept  hosts = $main{\"smtp_expn_hosts\"}\n\n";
1717   }
1718
1719 if (&bool("smtp_verify"))
1720   {
1721   print STDOUT "#!!# ACL that is used after the VRFY command\n" .
1722                "check_vrfy:\n";
1723   print STDOUT "  deny    hosts = +auth_hosts\n" .
1724                "          message = authentication required\n" .
1725                "         !authenticated = *\n"
1726     if defined $main{"auth_hosts"};
1727   print STDOUT "  accept\n\n";
1728   }
1729
1730 # -------- The authenticators --------
1731
1732 $started = 0;
1733 for ($i = $auth_start; $i < $clen; $i++)
1734   {
1735   if (!$started)
1736     {
1737     if ($c[$i] !~ /^\s*(#|$)/)
1738       {
1739       print STDOUT "\nbegin authenticators\n\n";
1740       $started = 1;
1741       }
1742     }
1743   print STDOUT "$c[$i]\n";
1744   }
1745
1746
1747 # -------- Rewrite section --------
1748
1749 $started = 0;
1750 for ($i = $rewrite_start; $i < $clen && $i < $auth_start - 1; $i++)
1751   {
1752   if (!$started)
1753     {
1754     if ($c[$i] !~ /^\s*(#|$)/)
1755       {
1756       print STDOUT "\nbegin rewrite\n\n";
1757       $started = 1;
1758       }
1759     }
1760   &print_no_expand($c[$i]);
1761   }
1762
1763
1764 # -------- The routers configuration --------
1765
1766 # The new routers configuration is created out of the old directors and routers
1767 # configuration. We put the old routers first, adding a "domains" option to
1768 # any that don't have one, to make them select the domains that do not match
1769 # the original local_domains. The routers get modified as necessary, and the
1770 # final one has "no_more" set, unless it has conditions. In that case we have
1771 # to add an extra router to be sure of failing all non-local addresses that
1772 # fall through. We do this also if there are no routers at all. The old
1773 # directors follow, modified as required.
1774
1775 $prefix = "r.";
1776 undef @comments;
1777
1778 print STDOUT "\n";
1779 print STDOUT "#!!#######################################################!!#\n";
1780 print STDOUT "#!!# Here follow routers created from the old routers,   #!!#\n";
1781 print STDOUT "#!!# for handling non-local domains.                     #!!#\n";
1782 print STDOUT "#!!#######################################################!!#\n";
1783
1784 print STDOUT "\nbegin routers\n\n";
1785
1786 for ($i = $router_start; $i < $clen; $i++)
1787   {
1788   $type = &checkline($c[$i]);
1789   last if $type eq "end";
1790
1791   if ($type eq "comment") { push(@comments, "$c[$i]\n"); next; }
1792
1793   # When we hit the start of a driver, modify its options as necessary,
1794   # and then output it from the stored option settings, having first output
1795   # and previous comments.
1796
1797   if ($type eq "driver")
1798     {
1799     print STDOUT shift @comments while scalar(@comments) > 0;
1800
1801     $hash = $driverlist{"$prefix$name"};
1802     $driver = $$hash{"driver"};
1803     print STDOUT "$name:\n";
1804
1805     $add_no_more =
1806       ! defined $$hash{"domains"} &&
1807       ! defined $$hash{"local_parts"} &&
1808       ! defined $$hash{"senders"} &&
1809       ! defined $$hash{"condition"} &&
1810       ! defined $$hash{"require_files"} &&
1811       (!defined $$hash{"verify_only"} || $$hash{"verify_only"} eq "false") &&
1812       (!defined $$hash{"verify"} || $$hash{"verify"} eq "true");
1813
1814     # Create a "domains" setting if there isn't one, unless local domains
1815     # was explicitly empty.
1816
1817     $$hash{"domains"} = "! +local_domains"
1818       if !defined $$hash{"domains"} && $local_domains !~ /^\s*$/;
1819
1820     # If the router had a local_parts setting, add caseful_local_part
1821
1822     $$hash{"caseful_local_part"} = "true" if defined $$hash{"local_parts"};
1823
1824     # If the router has "self=local" set, change it to "self=pass", and
1825     # set pass_router to the router that was the first director. Change the
1826     # obsolete self settings of "fail_hard" and "fail_soft" to "fail" and
1827     # "pass".
1828
1829     if (defined $$hash{"self"})
1830       {
1831       if ($$hash{"self"} eq "local")
1832         {
1833         $$hash{"self"} = "pass";
1834         $$hash{"pass_router"} = $first_director;
1835         }
1836       elsif ($$hash{"self"} eq "fail_hard")
1837         {
1838         $$hash{"self"} = "fail";
1839         }
1840       elsif ($$hash{"self"} eq "fail_soft")
1841         {
1842         $$hash{"self"} = "pass";
1843         }
1844       }
1845
1846     # If the router had a require_files setting, check it for user names
1847     # and colons that are part of expansion items
1848
1849     if (defined $$hash{"require_files"})
1850       {
1851       &check_require($$hash{"require_files"}, "'$name' router");
1852       if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 ||
1853           ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0)
1854         {
1855         &rubric();
1856         print STDERR "\n" .
1857 "*** A setting of require_files in the $name router contains\n" .
1858 "    a colon in what appears to be an expansion item. In Exim 3, the\n" .
1859 "    whole string was expanded before splitting the list, but in Exim 4\n" .
1860 "    each item is expanded separately, so colons that are not list\n" .
1861 "    item separators have to be doubled. One or more such colons in this\n" .
1862 "    list have been doubled as a precaution. Please check the result.\n";
1863         }
1864       }
1865
1866     # If the router had a "senders" setting, munge the address list
1867
1868     $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders")
1869       if defined $$hash{"senders"};
1870
1871     # ---- Changes to domainlist router ----
1872
1873     if ($driver eq "domainlist")
1874       {
1875       &abolished($hash, "A domainlist router",
1876         "modemask", "owners", "owngroups",
1877         "qualify_single", "search_parents");
1878
1879       # The name has changed
1880
1881       $$hash{"driver"} = "manualroute";
1882
1883       # Turn "route_file", "route_query" and "route_queries" into lookups for
1884       # route_data.
1885
1886       if (defined $$hash{"route_file"})
1887         {
1888         $$hash{"route_data"} = "\${lookup\{\$domain\}$$hash{'search_type'}" .
1889                          "\{$$hash{'route_file'}\}\}";
1890         }
1891       elsif (defined $$hash{"route_query"})
1892         {
1893         $$hash{"route_data"} = "\${lookup $$hash{'search_type'}" .
1894                                "\{" . &unquote($$hash{'route_query'}) . "\}\}";
1895         }
1896       elsif (defined $$hash{"route_queries"})
1897         {
1898         $endkets = 0;
1899         $$hash{"route_data"} = "";
1900         $route_queries = $$hash{'route_queries'};
1901         $route_queries =~ s/^"(.*)"$/$1/s;
1902         $route_queries =~ s/::/++colons++/g;
1903         @qq = split(/:/, $route_queries);
1904
1905         foreach $q (@qq)
1906           {
1907           $q =~ s/\+\+colons\+\+/:/g;
1908           $q =~ s/^\s+//;
1909           $q =~ s/\s+$//;
1910           if ($endkets > 0)
1911             {
1912             $$hash{"route_data"} .= "\\\n    {";
1913             $endkets++;
1914             }
1915           $$hash{"route_data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}";
1916           $endkets++;
1917           }
1918
1919         $$hash{"route_data"} .= "}" x $endkets;
1920         }
1921
1922       delete $$hash{"route_file"};
1923       delete $$hash{"route_query"};
1924       delete $$hash{"route_queries"};
1925       delete $$hash{"search_type"};
1926
1927       # But we can't allow both route_data and route_list
1928
1929       if (defined $$hash{"route_data"} && defined $$hash{"route_list"})
1930         {
1931         &rubric();
1932         print STDERR "\n" .
1933 "** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" .
1934 "   option as well as a setting of 'route_file', 'route_query', or\n" .
1935 "   'route_queries'. The latter has been turned into a 'route_data' setting,\n".
1936 "   but in Exim 4 you can't have both 'route_data' and 'route_list'. You'll\n" .
1937 "   have to rewrite this router; in the meantime, 'route_list' has been\n" .
1938 "   omitted.\n";
1939         print STDOUT "#!!# route_list option removed\n";
1940         delete $$hash{"route_list"};
1941         }
1942
1943       # Change bydns_a into bydns in a route_list; also bydns_mx, but that
1944       # works differently.
1945
1946       if (defined $$hash{"route_list"})
1947         {
1948         $$hash{"route_list"} =~ s/bydns_a/bydns/g;
1949         if ($$hash{"route_list"} =~ /bydns_mx/)
1950           {
1951           $$hash{"route_list"} =~ s/bydns_mx/bydns/g;
1952           &rubric();
1953           print STDERR "\n" .
1954 "*** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" .
1955 "    option which used 'bydns_mx'. This feature no longer exists in Exim 4.\n" .
1956 "    It has been changed to 'bydns', but it won't have the same effect,\n" .
1957 "    because it will look for A rather than MX records. Use the 'dnslookup'\n" .
1958 "    router to do MX lookups - if you want to override the hosts found from\n" .
1959 "    MX records, you should route to a special 'smtp' transport which has\n" .
1960 "    both 'hosts' and 'hosts_override' set.\n";
1961           }
1962         }
1963
1964       # Arrange to not expand regex
1965
1966       $$hash{"route_list"} = &no_expand_regex($$hash{"route_list"}, ";")
1967         if (defined $$hash{"route_list"})
1968       }
1969
1970
1971     # ---- Changes to iplookup router ----
1972
1973     elsif ($driver eq "iplookup")
1974       {
1975       &renamed($hash, "service", "port");
1976       }
1977
1978
1979     # ---- Changes to lookuphost router ----
1980
1981     elsif ($driver eq "lookuphost")
1982       {
1983       $$hash{"driver"} = "dnslookup";
1984
1985       if (defined $$hash{"gethostbyname"})
1986         {
1987         &rubric();
1988         print STDERR "\n" .
1989 "** An Exim 3 'lookuphost' router called '$name' used the 'gethostbyname'\n" .
1990 "   option, which no longer exists. You will have to rewrite it.\n";
1991         print STDOUT "#!!# gethostbyname option removed\n";
1992         delete $$hash{"gethostbyname"};
1993         }
1994
1995       $$hash{"mx_domains"} = &no_expand_regex($$hash{"mx_domains"})
1996         if defined $$hash{"mx_domains"};
1997       }
1998
1999
2000     # ---- Changes to the queryprogram router ----
2001
2002     elsif ($driver eq "queryprogram")
2003       {
2004       &rubric();
2005       print STDERR "\n" .
2006 "** The configuration contains a 'queryprogram' router. Please note that\n" .
2007 "   the specification for the text that is returned by the program run\n" .
2008 "   by this router has changed in Exim 4. You will need to modify your\n" .
2009 "   program.\n";
2010
2011       if (!defined $$hash{'command_user'})
2012         {
2013         &rubric();
2014         print STDERR "\n" .
2015 "** The 'queryprogram' router called '$name' does not have a setting for\n" .
2016 "   the 'command_user' option. This is mandatory in Exim 4. A setting of\n" .
2017 "   'nobody' has been created.\n";
2018         $$hash{"command_user"} = "nobody";
2019         }
2020       }
2021
2022
2023     # -------------------------------------
2024
2025     # Output the router's option settings
2026
2027     &outdriver($hash);
2028     next;
2029     }
2030
2031   # Skip past any continuation lines for an option setting
2032   while ($c[$i] =~ /\\\s*$/s && $i < $clen - 1)
2033     {
2034     $i++;
2035     $i++ while ($c[$i] =~ /^\s*#/);
2036     }
2037   }
2038
2039 # Add "no_more" to the final driver from the old routers, provided it had no
2040 # conditions. Otherwise, or if there were no routers, make up one to fail all
2041 # non-local domains.
2042
2043 if ($add_no_more)
2044   {
2045   print STDOUT "  no_more\n";
2046   print STDOUT shift @comments while scalar(@comments) > 0;
2047   }
2048 else
2049   {
2050   print STDOUT shift @comments while scalar(@comments) > 0;
2051   print STDOUT "\n#!!# This new router is put here to fail all domains that\n";
2052   print STDOUT "#!!# were not in local_domains in the Exim 3 configuration.\n\n";
2053   print STDOUT "fail_remote_domains:\n";
2054   print STDOUT "  driver = redirect\n";
2055   print STDOUT "  domains = ! +local_domains\n";
2056   print STDOUT "  allow_fail\n";
2057   print STDOUT "  data = :fail: unrouteable mail domain \"\$domain\"\n\n";
2058   }
2059
2060 # Now copy the directors, making appropriate changes
2061
2062 print STDOUT "\n";
2063 print STDOUT "#!!#######################################################!!#\n";
2064 print STDOUT "#!!# Here follow routers created from the old directors, #!!#\n";
2065 print STDOUT "#!!# for handling local domains.                         #!!#\n";
2066 print STDOUT "#!!#######################################################!!#\n";
2067
2068 $prefix = "d.";
2069 for ($i = $director_start; $i < $clen; $i++)
2070   {
2071   $type = &checkline($c[$i]);
2072   last if $type eq "end";
2073
2074   if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; }
2075
2076   undef $second_router;
2077
2078   if ($type eq "driver")
2079     {
2080     $hash = $driverlist{"$prefix$name"};
2081     $driver = $$hash{"driver"};
2082     print STDOUT "$name:\n";
2083
2084     $$hash{"caseful_local_part"} = "true" if $add_caseful_local_part;
2085
2086     if (defined $$hash{"local_parts"} &&
2087         (defined $$hash{"prefix"} || defined $hash{"suffix"}))
2088       {
2089       &rubric();
2090       print STDERR "\n" .
2091 "** The Exim 3 configuration contains a director called '$name' which has\n" .
2092 "   'local_parts' set, together with either or both of 'prefix' and 'suffix'\n".
2093 "   This combination has a different effect in Exim 4, where the affix\n" .
2094 "   is removed *before* 'local_parts' is tested. You will probably need\n" .
2095 "   to make changes to this driver.\n";
2096       }
2097
2098     &renamed($hash, "prefix", "local_part_prefix");
2099     &renamed($hash, "prefix_optional", "local_part_prefix_optional");
2100     &renamed($hash, "suffix", "local_part_suffix");
2101     &renamed($hash, "suffix_optional", "local_part_suffix_optional");
2102     &renamed($hash, "new_director", "redirect_router");
2103
2104     &handle_current_and_home_directory($hash, $driver, $name);
2105
2106     # If the director had a require_files setting, check it for user names
2107     # and colons that are part of expansion items
2108
2109     if (defined $$hash{"require_files"})
2110       {
2111       &check_require($$hash{"require_files"}, "'$name' director");
2112       if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 ||
2113           ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0)
2114         {
2115         &rubric();
2116         print STDERR "\n" .
2117 "*** A setting of require_files in the $name director contains\n" .
2118 "    a colon in what appears to be an expansion item. In Exim 3, the\n" .
2119 "    whole string was expanded before splitting the list, but in Exim 4\n" .
2120 "    each item is expanded separately, so colons that are not list\n" .
2121 "    item separators have to be doubled. One or more such colons in this\n" .
2122 "    list have been doubled as a precaution. Please check the result.\n";
2123         }
2124       }
2125
2126     # If the director had a "senders" setting, munge the address list
2127
2128     $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders")
2129       if defined $$hash{"senders"};
2130
2131     # ---- Changes to aliasfile director ----
2132
2133     if ($driver eq "aliasfile")
2134       {
2135       &abolished($hash, "An aliasfile director",
2136         "directory2_transport", "freeze_missing_include",
2137         "modemask", "owners", "owngroups");
2138
2139       $$hash{"driver"} = "redirect";
2140
2141       $key = "\$local_part";
2142       $key = "\$local_part\@\$domain"
2143         if defined $$hash{"include_domain"} &&
2144           $$hash{"include_domain"} eq "true";
2145       delete $$hash{"include_domain"};
2146
2147       if (defined $$hash{"forbid_special"} && $$hash{"forbid_special"} eq "true")
2148         {
2149         $$hash{"forbid_blackhole"} = "true";
2150         }
2151       else
2152         {
2153         $$hash{"allow_defer"} = "true";
2154         $$hash{"allow_fail"} = "true";
2155         }
2156       delete $$hash{"forbid_special"};
2157
2158       # Deal with "file", "query", or "queries"
2159
2160       if (defined $$hash{"file"})
2161         {
2162         $$hash{"data"} =
2163           "\$\{lookup\{$key\}$$hash{'search_type'}\{$$hash{'file'}\}\}";
2164         if (defined $$hash{"optional"} && $$hash{"optional"} eq "true")
2165           {
2166           $$hash{"data"} =
2167             "\$\{if exists\{$$hash{'file'}\}\{$$hash{'data'}\}\}";
2168           }
2169         delete $$hash{"optional"};
2170         }
2171       elsif (defined $$hash{"query"})
2172         {
2173         &abolished($hash, "An aliasfile director", "optional");
2174         $$hash{"data"} = "\${lookup $$hash{'search_type'} " .
2175                          "\{" . &unquote($$hash{'query'}) . "\}\}";
2176         }
2177       else   # Must be queries
2178         {
2179         &abolished($hash, "An aliasfile director", "optional");
2180         $endkets = 0;
2181         $$hash{"data"} = "";
2182         $queries = $$hash{'queries'};
2183         $queries =~ s/^"(.*)"$/$1/s;
2184         $queries =~ s/::/++colons++/g;
2185         @qq = split(/:/, $queries);
2186
2187         foreach $q (@qq)
2188           {
2189           $q =~ s/\+\+colons\+\+/:/g;
2190           $q =~ s/^\s+//;
2191           $q =~ s/\s+$//;
2192           if ($endkets > 0)
2193             {
2194             $$hash{"data"} .= "\\\n    {";
2195             $endkets++;
2196             }
2197           $$hash{"data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}";
2198           $endkets++;
2199           }
2200
2201         $$hash{"data"} .= "}" x $endkets;
2202         }
2203
2204       $$hash{"data"} = "\${expand:$$hash{'data'}\}"
2205         if (defined $$hash{"expand"} && $$hash{"expand"} eq "true");
2206
2207       delete $$hash{"expand"};
2208       delete $$hash{"file"};
2209       delete $$hash{"query"};
2210       delete $$hash{"queries"};
2211       delete $$hash{"search_type"};
2212
2213       # Turn aliasfile + transport into accept + condition
2214
2215       if (defined $$hash{'transport'})
2216         {
2217         &rubric();
2218         if (!defined $$hash{'condition'})
2219           {
2220           print STDERR "\n" .
2221 "** The Exim 3 configuration contains an aliasfile director called '$name',\n".
2222 "   which has 'transport' set. This has been turned into an 'accept' router\n".
2223 "   with a 'condition' setting, but should be carefully checked.\n";
2224           $$hash{'driver'} = "accept";
2225           $$hash{'condition'} =
2226             "\$\{if eq \{\}\{$$hash{'data'}\}\{no\}\{yes\}\}";
2227           delete $$hash{'data'};
2228           delete $$hash{'allow_defer'};
2229           delete $$hash{'allow_fail'};
2230           }
2231         else
2232           {
2233           print STDERR "\n" .
2234 "** The Exim 3 configuration contains an aliasfile director called '$name',\n".
2235 "   which has 'transport' set. This cannot be turned into an 'accept' router\n".
2236 "   with a 'condition' setting, because there is already a 'condition'\n" .
2237 "   setting. It has been left as 'redirect' with a transport, which is\n" .
2238 "   invalid - you must sort this one out.\n";
2239           }
2240         }
2241       }
2242
2243
2244     # ---- Changes to forwardfile director ----
2245
2246     elsif ($driver eq "forwardfile")
2247       {
2248       &abolished($hash, "A forwardfile director",
2249         "check_group", "directory2_transport",
2250         "freeze_missing_include", "match_directory",
2251         "seteuid");
2252
2253       &renamed($hash, "filter", "allow_filter");
2254
2255       $$hash{"driver"} = "redirect";
2256       $$hash{"check_local_user"} = "true"
2257         if !defined $$hash{"check_local_user"};
2258
2259       if (defined $$hash{"forbid_pipe"} && $$hash{"forbid_pipe"} eq "true")
2260         {
2261         print STDOUT "#!!# forbid_filter_run added because forbid_pipe is set\n";
2262         $$hash{"forbid_filter_run"} = "true";
2263         }
2264
2265       if (defined $$hash{'allow_system_actions'} &&
2266           $$hash{'allow_system_actions'} eq 'true')
2267         {
2268         $$hash{'allow_freeze'} = "true";
2269         }
2270       delete $$hash{'allow_system_actions'};
2271
2272       # If file_directory is defined, use it to qualify relative paths; if not,
2273       # and check_local_user is defined, use $home. Remove file_directory from
2274       # the output.
2275
2276       $dir = "";
2277       if (defined $$hash{"file_directory"})
2278         {
2279         $dir = $$hash{"file_directory"} . "/";
2280         delete $$hash{"file_directory"};
2281         }
2282       elsif ($$hash{"check_local_user"} eq "true")
2283         {
2284         $dir = "\$home/";
2285         }
2286
2287       # If it begins with an upper case letter, guess that this is really
2288       # a macro.
2289
2290       if (defined $$hash{"file"} && $$hash{"file"} !~ /^[\/A-Z]/)
2291         {
2292         $$hash{"file"} = $dir . $$hash{"file"};
2293         }
2294       }
2295
2296
2297     # ---- Changes to localuser director ----
2298
2299     elsif ($driver eq "localuser")
2300       {
2301       &abolished($hash, "A localuser director", "match_directory");
2302       $$hash{"driver"} = "accept";
2303       $$hash{"check_local_user"} = "true";
2304       }
2305
2306
2307     # ---- Changes to smartuser director ----
2308
2309     elsif ($driver eq "smartuser")
2310       {
2311       &abolished($hash, "A smartuser director", "panic_expansion_fail");
2312
2313       $transport = $$hash{"transport"};
2314       $new_address = $$hash{"new_address"};
2315
2316       if (defined $transport && defined $new_address)
2317         {
2318         &rubric();
2319         print STDERR "\n" .
2320 "** The Exim 3 configuration contains a smartuser director called '$name',\n".
2321 "   which has both 'transport' and 'new_address' set. This has been turned\n".
2322 "   into two routers for Exim 4. However, if the new address contains a\n" .
2323 "   reference to \$local_part, this won't work correctly. In any case, you\n".
2324 "   may be able to make it tidier by rewriting.\n";
2325         $$hash{"driver"} = "redirect";
2326         $$hash{"data"} = $new_address;
2327         $$hash{"redirect_router"} = "${name}_part2";
2328
2329         $second_router = "\n".
2330           "#!!# This router is invented to go with the previous one because\n".
2331           "#!!# in Exim 4 you can't have a change of address and a transport\n".
2332           "#!!# setting in the same router as you could in Exim 3.\n\n" .
2333           "${name}_part2:\n".
2334           "  driver = accept\n".
2335           "  condition = \$\{if eq\{\$local_part@\$domain\}" .
2336           "\{$new_address\}\{yes\}\{no\}\}\n".
2337           "  transport = $$hash{'transport'}\n";
2338
2339         delete $$hash{"new_address"};
2340         delete $$hash{"transport"};
2341         }
2342       elsif (defined $new_address)
2343         {
2344         $$hash{"driver"} = "redirect";
2345         $$hash{"data"} = $new_address;
2346         $$hash{"allow_defer"} = "true";
2347         $$hash{"allow_fail"} = "true";
2348         delete $$hash{"new_address"};
2349         }
2350       else     # Includes the case of neither set (verify_only)
2351         {
2352         $$hash{"driver"} = "accept";
2353         if (defined $$hash{"rewrite"})
2354           {
2355           &rubric();
2356           print STDERR "\n" .
2357 "** The Exim 3 configuration contains a setting of the 'rewrite' option on\n".
2358 "   a smartuser director called '$name', but this director does not have\n".
2359 "   a setting of 'new_address', so 'rewrite' has no effect. The director\n".
2360 "   has been turned into an 'accept' router, and 'rewrite' has been discarded.";
2361           delete $$hash{"rewrite"};
2362           }
2363         }
2364       }
2365
2366
2367     # -------------------------------------
2368
2369     # For ex-directors that don't have check_local_user set, add
2370     # retry_use_local_part to imitate what Exim 3 would have done.
2371
2372     $$hash{"retry_use_local_part"} = "true"
2373       if (!defined $$hash{"check_local_user"} ||
2374           $$hash{"check_local_user"} eq "false") ;
2375
2376     # Output the router's option settings
2377
2378     &outdriver($hash);
2379
2380     # Output an auxiliary router if one is needed
2381
2382     print STDOUT $second_router if defined $second_router;
2383
2384     next;
2385     }
2386
2387   # Skip past any continuation lines for an option setting
2388   while ($c[$i] =~ /\\\s*$/s)
2389     {
2390     $i++;
2391     $i++ while ($c[$i] =~ /^\s*#/);
2392     }
2393   }
2394
2395
2396
2397 # -------- The transports configuration --------
2398
2399 $started = 0;
2400 $prefix = "t.";
2401 for ($i = $transport_start; $i < $clen; $i++)
2402   {
2403   $type = &checkline($c[$i]);
2404   last if $type eq "end";
2405
2406   if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; }
2407
2408   if (!$started)
2409     {
2410     print STDOUT "begin transports\n\n";
2411     $started = 1;
2412     }
2413
2414   if ($type eq "driver")
2415     {
2416     $hash = $driverlist{"$prefix$name"};
2417     $driver = $$hash{"driver"};
2418     print STDOUT "$name:\n";
2419
2420     # ---- Changes to the appendfile transport ----
2421
2422     if ($driver eq "appendfile")
2423       {
2424       &renamed($hash, "prefix", "message_prefix");
2425       &renamed($hash, "suffix", "message_suffix");
2426       &abolished($hash, "An appendfile transport",
2427         "require_lockfile");
2428       &handle_batch_and_bsmtp($hash);
2429       if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false")
2430         {
2431         print STDOUT "#!!# no_from_hack replaced by check_string\n";
2432         $$hash{"check_string"} = "";
2433         }
2434       delete $$hash{"from_hack"};
2435       }
2436
2437     # ---- Changes to the lmtp transport ----
2438
2439     elsif ($driver eq "lmtp")
2440       {
2441       if (defined $$hash{"batch"} && $$hash{"batch"} ne "none")
2442         {
2443         $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"};
2444         $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain";
2445         }
2446       else
2447         {
2448         $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"};
2449         }
2450       delete $$hash{"batch"};
2451       }
2452
2453     # ---- Changes to the pipe transport ----
2454
2455     elsif ($driver eq "pipe")
2456       {
2457       &renamed($hash, "prefix", "message_prefix");
2458       &renamed($hash, "suffix", "message_suffix");
2459       &handle_batch_and_bsmtp($hash);
2460       if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false")
2461         {
2462         print STDOUT "#!!# no_from_hack replaced by check_string\n";
2463         $$hash{"check_string"} = "";
2464         }
2465       delete $$hash{"from_hack"};
2466       }
2467
2468     # ---- Changes to the smtp transport ----
2469
2470     elsif ($driver eq "smtp")
2471       {
2472       &abolished($hash, "An smtp transport", "mx_domains");
2473       &renamed($hash, "service", "port");
2474       &renamed($hash, "tls_verify_ciphers", "tls_require_ciphers");
2475       &renamed($hash, "authenticate_hosts", "hosts_try_auth");
2476
2477       if (defined $$hash{"batch_max"})
2478         {
2479         print STDOUT "#!!# batch_max renamed connection_max_messages\n";
2480         $$hash{"connection_max_messages"} = $$hash{"batch_max"};
2481         delete $$hash{"batch_max"};
2482         }
2483
2484       foreach $o ("hosts_try_auth", "hosts_avoid_tls", "hosts_require_tls",
2485                   "mx_domains", "serialize_hosts")
2486         {
2487         $$hash{$o} = &no_expand_regex($$hash{$o}) if defined $$hash{$o};
2488         }
2489       }
2490
2491     &outdriver($driverlist{"$prefix$name"});
2492     next;
2493     }
2494
2495   # Skip past any continuation lines for an option setting
2496   while ($c[$i] =~ /\\\s*$/s)
2497     {
2498     $i++;
2499     $i++ while ($c[$i] =~ /^\s*#/);
2500     }
2501   }
2502
2503
2504 # -------- The retry configuration --------
2505
2506 $started = 0;
2507 for ($i = $retry_start; $i < $clen && $i < $rewrite_start - 1; $i++)
2508   {
2509   if (!$started)
2510     {
2511     if ($c[$i] !~ /^\s*(#|$)/)
2512       {
2513       print STDOUT "\nbegin retry\n\n";
2514       $started = 1;
2515       }
2516     }
2517   &print_no_expand($c[$i]);
2518   }
2519
2520 print STDOUT "\n# End of Exim 4 configuration\n";
2521
2522 print STDERR "\n*******************************************************\n";
2523 print STDERR   "***** Please review the generated file carefully. *****\n";
2524 print STDERR   "*******************************************************\n\n";
2525
2526 # End of convert4r4
2527